Tip
通过本文,你将了解:
- 如何更方便的使用Li4n0/hugo_encryptor
- “PY_SSIZE_T_CLEAN macro must be defined for ’#’ formats” 报错的解决方法
- 简易修改
Note
建议先参考本文利用Github Action将博客部署到Github Page上获得最佳体验。
前言
博客偶尔想放些涉及个人生活比较深入的东西,但又只希望与接触比较深的人或者部分相关人士查看。这种情况下设置个大家心知肚明的密码最好。
原理
简单来说,hugo-encryptor加密流程如下:
- 利用shortcode渲染待加密内容
- 用一段python程序对渲染结果(/public文件夹下所有文件)进行匹配,加密待加密内容
- 部署
因此,如果只是配置了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我更倾向于将其直接放入主题中去,我的方法如下:
- 找到主题对应的layouts/partials/shortcodes文件夹,在里面新建一个文件夹hugo-encryptor.html。
- 将以下代码复制粘贴入其中:{{< accordion “点击查看代码” >}}
{{ $_hugo_config := `{ "version": 1 }` }} {{/* ## Hugo Encrypt ### Params: -`password`: require param - Simple {{% hugo-encryptor "your password" %}} yourcontent {{% /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>{{}}
- 找到主题对应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的工作原理:
- 利用shortcode渲染待加密内容
- 用一段python程序对渲染结果(/public文件夹下所有文件)进行匹配,加密待加密内容
- 部署
在上一小节中,我们已经实现了1. 利用shortcode渲染待加密内容,而由于我们使用Github Action,我们可以将23两步结合起来,实现全自动加密,避免忘记运行加密程序导致隐私泄漏。
步骤如下:
- 在博客仓库创建一个文件夹hugo_encryptor,将Li4n0/hugo_encryptor中的hugo-encryptor.py与requirements.txt放入其中。
- 对原有的部署工作流如此修改:
...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 Pagespermissions:  contents: read  pages: write  id-token: write
# Environment variables available to all jobs and steps in this workflowenv:  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 %}}