为pelican添加文章加密功能


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("密码错误 !");
    });
});

Author: honmaple

NO CONTENTS

lin.jiang

风落花语风落天,花落风雨花落田.