|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | + |
| 3 | +# Copyright © 2012-2016 Roberto Alsina and others. |
| 4 | + |
| 5 | +# Permission is hereby granted, free of charge, to any |
| 6 | +# person obtaining a copy of this software and associated |
| 7 | +# documentation files (the "Software"), to deal in the |
| 8 | +# Software without restriction, including without limitation |
| 9 | +# the rights to use, copy, modify, merge, publish, |
| 10 | +# distribute, sublicense, and/or sell copies of the |
| 11 | +# Software, and to permit persons to whom the Software is |
| 12 | +# furnished to do so, subject to the following conditions: |
| 13 | +# |
| 14 | +# The above copyright notice and this permission notice |
| 15 | +# shall be included in all copies or substantial portions of |
| 16 | +# the Software. |
| 17 | +# |
| 18 | +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
| 19 | +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
| 20 | +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
| 21 | +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS |
| 22 | +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR |
| 23 | +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
| 24 | +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| 25 | +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 26 | + |
| 27 | +"""Render the taxonomy overviews, classification pages and feeds.""" |
| 28 | + |
| 29 | +from __future__ import unicode_literals |
| 30 | +import blinker |
| 31 | +import io |
| 32 | +import string |
| 33 | + |
| 34 | +from nikola.plugin_categories import SignalHandler |
| 35 | +from nikola import utils |
| 36 | +from nikola.rc4 import rc4 |
| 37 | + |
| 38 | + |
| 39 | +class PostEncryption(SignalHandler): |
| 40 | + """Render the tag/category pages and feeds.""" |
| 41 | + |
| 42 | + name = "post_encryption" |
| 43 | + |
| 44 | + @staticmethod |
| 45 | + def wrap_encrypt(path, password): |
| 46 | + """Wrap a post with encryption.""" |
| 47 | + with io.open(path, 'r+', encoding='utf8') as inf: |
| 48 | + data = inf.read() + "<!--tail-->" |
| 49 | + data = CRYPT.substitute(data=rc4(password, data)) |
| 50 | + with io.open(path, 'w+', encoding='utf8') as outf: |
| 51 | + outf.write(data) |
| 52 | + |
| 53 | + def _handle_post_compiled(self, source, dest, post): |
| 54 | + """Encrypt post if password is set.""" |
| 55 | + if post.meta('password'): |
| 56 | + # TODO: get rid of this feature one day (v8?; warning added in v7.3.0.) |
| 57 | + utils.LOGGER.warn("The post {0} is using the `password` attribute, which may stop working in the future.") |
| 58 | + utils.LOGGER.warn("Please consider switching to a more secure method of encryption.") |
| 59 | + utils.LOGGER.warn("More details: https://github.com/getnikola/nikola/issues/1547") |
| 60 | + self.wrap_encrypt(dest, post.meta('password')) |
| 61 | + |
| 62 | + def set_site(self, site): |
| 63 | + """Set site, which is a Nikola instance.""" |
| 64 | + super(PostEncryption, self).set_site(site) |
| 65 | + # Add hook for after post compilation |
| 66 | + blinker.signal("compiled").connect(self._handle_post_compiled) |
| 67 | + |
| 68 | + |
| 69 | +CRYPT = string.Template("""\ |
| 70 | +<script> |
| 71 | +function rc4(key, str) { |
| 72 | + var s = [], j = 0, x, res = ''; |
| 73 | + for (var i = 0; i < 256; i++) { |
| 74 | + s[i] = i; |
| 75 | + } |
| 76 | + for (i = 0; i < 256; i++) { |
| 77 | + j = (j + s[i] + key.charCodeAt(i % key.length)) % 256; |
| 78 | + x = s[i]; |
| 79 | + s[i] = s[j]; |
| 80 | + s[j] = x; |
| 81 | + } |
| 82 | + i = 0; |
| 83 | + j = 0; |
| 84 | + for (var y = 0; y < str.length; y++) { |
| 85 | + i = (i + 1) % 256; |
| 86 | + j = (j + s[i]) % 256; |
| 87 | + x = s[i]; |
| 88 | + s[i] = s[j]; |
| 89 | + s[j] = x; |
| 90 | + res += String.fromCharCode(str.charCodeAt(y) ^ s[(s[i] + s[j]) % 256]); |
| 91 | + } |
| 92 | + return res; |
| 93 | +} |
| 94 | +function decrypt() { |
| 95 | + key = $$("#key").val(); |
| 96 | + crypt_div = $$("#encr") |
| 97 | + crypted = crypt_div.html(); |
| 98 | + decrypted = rc4(key, window.atob(crypted)); |
| 99 | + if (decrypted.substr(decrypted.length - 11) == "<!--tail-->"){ |
| 100 | + crypt_div.html(decrypted); |
| 101 | + $$("#pwform").hide(); |
| 102 | + crypt_div.show(); |
| 103 | + } else { alert("Wrong password"); }; |
| 104 | +} |
| 105 | +</script> |
| 106 | +
|
| 107 | +<div id="encr" style="display: none;">${data}</div> |
| 108 | +<div id="pwform"> |
| 109 | +<form onsubmit="javascript:decrypt(); return false;" class="form-inline"> |
| 110 | +<fieldset> |
| 111 | +<legend>This post is password-protected.</legend> |
| 112 | +<input type="password" id="key" placeholder="Type password here"> |
| 113 | +<button type="submit" class="btn">Show Content</button> |
| 114 | +</fieldset> |
| 115 | +</form> |
| 116 | +</div>""") |
0 commit comments