··

使用'hugo encryptor'加密博客文章

Tip

通过本文,你将了解:

  • 如何更方便的使用Li4n0/hugo_encryptor
  • “PY_SSIZE_T_CLEAN macro must be defined for ’#’ formats” 报错的解决方法
  • 简易修改
Note

建议先参考本文利用Github Action将博客部署到Github Page上获得最佳体验。

前言

博客偶尔想放些涉及个人生活比较深入的东西,但又只希望与接触比较深的人或者部分相关人士查看。这种情况下设置个大家心知肚明的密码最好。

原理

简单来说,hugo-encryptor加密流程如下:

  1. 利用shortcode渲染待加密内容
  2. 用一段python程序对渲染结果(/public文件夹下所有文件)进行匹配,加密待加密内容
  3. 部署 因此,如果只是配置了shortcode而没有运行加密程序的话,文章内容不会被加密。而具体配置过程也因此分成了配置主题配置部署两部分。

为主题引入hugo_encryptor

原作者给出的办法个人感觉不是很好看:

### Step 1: Install all the requirements of Hugo-Encryptor
$ git clone https://github.com/Li4n0/hugo_encryptor.git
$ cd hugo_encryptor
$ chmod +x hugo-encryptor.py
$ pip install -r requirements.txt
### Step 2: Create a symlink (Optional)
$ ln -s /absolute/path/to/hugo_encryptor/hugo-encryptor.py hugo-encryptor.py
### Step 3: Symlink `shortcodes/hugo-encryptor.html` into the shortcode directory of your blog:
$ mkdir -p /path/to/your/blog/layouts/shortcodes
$ ln -s /absolute/path/to/hugo_encryptor/shortcodes/hugo-encryptor.html /path/to/your/blog/layouts/shortcodes/hugo-encryptor.html

我更倾向于将其直接放入主题中去,我的方法如下:

  1. 找到主题对应的layouts/partials/shortcodes文件夹,在里面新建一个文件夹hugo-encryptor.html
  2. 将以下代码复制粘贴入其中:{{< accordion “点击查看代码” >}}
{{ $_hugo_config := `{ "version": 1 }` }} {{/* ## Hugo Encrypt ### Params: -
`password`: require param - Simple {{% hugo-encryptor "your password" %}} your
content {{% /hugo-encryptor %}} */}} {{/* DEFAULTS */}}
<div class="hugo-encryptor-container">
<div class="hugo-encryptor-prompt">
{{ if eq .Site.Params.hugoEncryptorLanguage "en-us" }}
<p>Part of this article is encrypted with password:</p>
{{ else }}
<p>文章的部分内容被密码保护:</p>
{{ end }}
</div>
<div class="hugo-encryptor-form">
<input
class="hugo-encryptor-input"
placeholder='{{ if eq .Site.Params.hugoEncryptorLanguage "en-us" }}Please input the password{{ else }}请输入密码{{ end }}'
/>
<input
class="hugo-encryptor-button"
type="button"
value='{{ if eq .Site.Params.hugoEncryptorLanguage "en-us" }}Click to verify{{ else }}点击验证{{ end }}'
onclick="_click_handler(this)"
/>
</div>
<div
class="hugo-encryptor-cipher-text"
data-password="{{ .Get 0 }}"
style="display: none;"
>
<span style="display: none;">--- DON'T MODIFY THIS LINE ---</span>
{{ .Inner }}
</div>
</div>

{{}}

  1. 找到主题对应header部分的模板,在其末尾添加:{{< accordion “点击查看代码” >}}
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
<script>
const _do_decrypt = function (encrypted, password) {
let key = CryptoJS.enc.Utf8.parse(password);
let iv = CryptoJS.enc.Utf8.parse(password.substr(16));
let decrypted_data = CryptoJS.AES.decrypt(encrypted, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
});
return decrypted_data.toString(CryptoJS.enc.Utf8);
};
const _click_handler = function (element) {
let parent = element.parentNode.parentNode;
let encrypted = parent.querySelector(
".hugo-encryptor-cipher-text",
).innerText;
let password = parent.querySelector(".hugo-encryptor-input").value;
password = CryptoJS.MD5(password).toString();
let index = -1;
let elements = document.querySelectorAll(".hugo-encryptor-container");
for (index = 0; index < elements.length; ++index) {
if (elements[index].isSameNode(parent)) {
break;
}
}
let decrypted = "";
try {
decrypted = _do_decrypt(encrypted, password);
} catch (err) {
console.error(err);
alert("Failed to decrypt.");
return;
}
if (!decrypted.includes("--- DON'T MODIFY THIS LINE ---")) {
alert("Incorrect password.");
return;
}
let storage = localStorage;
let key = location.pathname + ".password." + index;
storage.setItem(key, password);
parent.innerHTML = decrypted;
};
window.onload = () => {
let index = -1;
let elements = document.querySelectorAll(".hugo-encryptor-container");
while (1) {
++index;
let key = location.pathname + ".password." + index;
let password = localStorage.getItem(key);
if (!password) {
break;
} else {
console.log("Found password for part " + index);
let parent = elements[index];
let encrypted = parent.querySelector(
".hugo-encryptor-cipher-text",
).innerText;
let decrypted = _do_decrypt(encrypted, password);
elements[index].innerHTML = decrypted;
}
}
};
</script>

{{}}

Warning

请注意,此时文章还未被加密,需完成python的配置才行。

即可完成主题部分的配置。

配置部署

Note

建议先参考本文利用Github Action将博客部署到Github Page上获得最佳体验。本地运行属实麻烦,下文假设你使用Github Action将博客部署到Github Page上。

我们再回顾一下hugo-encryptor的工作原理:

  1. 利用shortcode渲染待加密内容
  2. 用一段python程序对渲染结果(/public文件夹下所有文件)进行匹配,加密待加密内容
  3. 部署

上一小节中,我们已经实现了1. 利用shortcode渲染待加密内容,而由于我们使用Github Action,我们可以将23两步结合起来,实现全自动加密,避免忘记运行加密程序导致隐私泄漏。

步骤如下:

  1. 在博客仓库创建一个文件夹hugo_encryptor,将Li4n0/hugo_encryptor中的hugo-encryptor.pyrequirements.txt放入其中。
  2. 对原有的部署工作流如此修改:
...
env:
...
HUGO_ENCRYPTOR_PATH: ./hugo_encryptor
...
jobs:
build:
steps:
...
- uses: actions/setup-python@v4
with:
python-version: '3.9'
- name: Install Python and Dependencies
run: |
sudo apt-get update
sudo apt-get install -y python3 python3-pip
pip3 install -r ${{ env.HUGO_ENCRYPTOR_PATH }}/requirement.txt
- name: Build Hugo site
run: hugo --minify --gc
- name: Encrypt private posts
run: |
python3 ${{ env.HUGO_ENCRYPTOR_PATH }}/hugo-encryptor.py
env:
HUGO_ENCRYPTOR_PATH: ./hugo_encryptor # Adjust this path based on where your `hugo_encryptor.py` script is located
...

其中,python版本选择3.9最佳,3.10及以上会报错:“PY_SSIZE_T_CLEAN macro must be defined for ’#’ formats”。此时可以选择以下两种做法:

  • 回退3.9版本python(推荐)
  • 重新用pip卸载再安装pycryptodome

至此,基本配置结束。 {{< accordion “参考workflow” >}}

name: Deploy Hugo site to Pages
on:
# Runs on pushes targeting the default branch
workflow_dispatch:
push:
branches: ["master"]
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Environment variables available to all jobs and steps in this workflow
env:
HUGO_ENV: production
HUGO_VERSION: "0.115.4"
GO_VERSION: "1.20.5"
NODE_VERSION: "18.15.0"
TINA_CLIENT_ID: ${{ vars.TINA_CLIENT_ID }}
TINA_TOKEN: ${{ vars.TINA_TOKEN }}
HUGO_ENCRYPTOR_PATH: ./hugo_encryptor
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: write # Allow write access to commit changes to the repository
steps:
- uses: actions/checkout@v4
with:
submodules: "recursive"
- name: Cache Hugo resources
uses: actions/cache@v4
env:
cache-name: cache-hugo-resources
with:
path: resources
key: ${{ env.cache-name }}
- uses: actions/setup-go@v5
with:
go-version: "^1.17.0"
- run: go version
- name: Setup Hugo
uses: peaceiris/actions-hugo@v2
with:
hugo-version: "latest"
extended: true
- uses: actions/setup-python@v4
with:
python-version: "3.9"
- name: Install Python and Dependencies
run: |
sudo apt-get update
sudo apt-get install -y python3 python3-pip
pip3 install -r ${{ env.HUGO_ENCRYPTOR_PATH }}/requirement.txt
- name: Build Hugo site
run: hugo --minify --gc
- name: Encrypt private posts
run: |
python3 ${{ env.HUGO_ENCRYPTOR_PATH }}/hugo-encryptor.py
env:
HUGO_ENCRYPTOR_PATH: ./hugo_encryptor # Adjust this path based on where your `hugo_encryptor.py` script is located
- name: Upload artifact
uses: actions/upload-pages-artifact@v1
with:
path: ./public
- name: Echo CNAME
run: echo ${{ secrets.CNAME }} > ./public/CNAME
- name: Deploy Web
uses: peaceiris/actions-gh-pages@v3
with:
PERSONAL_TOKEN: ${{ secrets.PERSONAL_TOKEN }}
EXTERNAL_REPOSITORY: HaleyCH/HaleyCH.github.io
PUBLISH_BRANCH: master
PUBLISH_DIR: ./public
commit_message: ${{ github.event.head_commit.message }}

{{}}

为encryptor添加密码提示

为了让目标受众知道我设置的密码是什么,有必要增加密码提示功能,这比较简单,只需将

{{ else }}
<p>文章的部分内容被密码保护:</p>
{{ end }}

改为

{{ else }}
<p>文章的部分内容被密码保护{{ if .Get 1 }},提示 “{{ .Get 1 }}”{{ end }}:</p>
{{ end }}

即可。最终成果如下所示(密码hugo)。

{{% hugo-encryptor “hugo” “此博客用的框架” %}}

对,就是hugo。 {{% /hugo-encryptor %}}

至此,我们完成了hugo-encryptor的配置与简单修改。