pelican是一个静态博客系统,很早之前就想要实现一个加密pelican文章的功能,但一直没什么时间,这次总算静下心花两天时间搞定了
为什么不用现有的插件encript-content
因为自己实现更有成就感啊!!!
前言
因为我不仅有静态博客honmaple.me
,还有一个动态博客honmaple.com
,所以此次加密功能我会在动态博客那边添加一个验证密码的接口,来对密码进行验证以及对加密文章进行解密,虽然验证也可以使用crypto-js.js进行双向解密,但还是觉得自定义的接口更安全一些。
自定义pelican插件
加密算法
加密算法我使用cryptography,使用起来很简单
>>> from cryptography.fernet import Fernet >>> # Put this somewhere safe! >>> key = Fernet.generate_key() >>> f = Fernet(key) >>> token = f.encrypt(b"A really secret message. Not for prying eyes.") >>> token '...' >>> f.decrypt(token) 'A really secret message. Not for prying eyes.'
但如果要使用自定义密码,需要更多设置 ,参考这里
from base64 import urlsafe_b64encode from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC salt = b'不要让人知道' key = PBKDF2HMAC( algorithm=hashes.SHA256(), length=32, salt=salt, iterations=100000, backend=default_backend()) key = urlsafe_b64encode(key.derive(password.encode("utf-8"))) # 使用 >>> f = Fernet(key) >>> encript_content = f.encrypt(b"A really secret message. Not for prying eyes.")
注册插件
参考于encript-content
def encrypt_article(article): ''' custom help text with password ''' # 对整篇文章和简介进行加密 ec_summary = f.encrypt(article.summary) ec_content = f.encrypt(article.content) # 设置显示模板 article._summary = TEMPLATE.format(help_text, ec_summary) article._content = TEMPLATE.format(help_text, ec_content) def pelican_generators_finalized(content_generators): for generator in content_generators: if isinstance(generator, generators.ArticlesGenerator): for article in generator.articles + generator.translations: if hasattr(article, 'password'): encrypt_article(article) for draft in generator.drafts + generator.drafts_translations: if hasattr(draft, 'password'): encrypt_article(article) if isinstance(generator, generators.PagesGenerator): for page in generator.pages: if 'password' in page.metadata: encrypt_article(article) def register(): signals.all_generators_finalized.connect(pelican_generators_finalized)
更新于2018.5.1
注意: 如果生成了 rss, 加密的内容会无加密的出现在 rss 内容中,查看 pelican 源码后发现需要自定义 writer
from pelican.writers import Writer class EncrptWriter(Writer): def _add_item_to_the_feed(self, feed, item): if hasattr(item, "password"): return return super(EncrptWriter, self)._add_item_to_the_feed(feed, item) def register(): signals.get_writer.connect(lambda pelican: EncrptWriter)
自定义主题
显示模板
显示模板很简单,一个表单,一个点击按钮,一个默认隐藏的加密内容
TEMPLATE = ''' <div class="entry-encrypt"> <div class="form-group has-feedback"> <input type="password" class="form-control input-sm" placeholder="请输入文章密码"> <i class="fa fa-key form-control-feedback entry-decrypt"></i> <span class="help-block">{0}</span> </div> <div class="entry-encrypt-content"> {1} </div> </div> '''
其中{0}
是提示信息,{1}
是加密后的内容,具体样式可以自定义css
客户端验证
将密码和加密后的内容发送到服务端,由服务端进行验证后解析
$(".entry-decrypt").click(function(e) { var _this = $(this); $.post("your decrypt api", { password:_this.prev().val(), content:_this.parent().next().text() }, function(response){ var _parent = _this.parent().parent(); _parent.hide(); _parent.after(response.data); }, 'json').fail(function() { _next.css("color","#C74451"); _next.text("密码错误 !"); }); });