# Hugo 加密文章简单尝试

> [Hugo 加密文章简单尝试](https://www.ftls.xyz/posts/2023-11-20-hugo-crypto-articles/)
> Penned by [恐咖兵糖](https://www.ftls.xyz/) on 2023-11-20


关于 Hugo 加密文章的简单尝试。

<!--more-->

## 前言

我在使用 Hexo 的时候，注意到有一些加密文章相关插件。加密文章，在 Wordpress 等等有服务器支持的博客程序中是一个比较容易实现的功能，用户把密码口令发送到服务器验证，然后返回相关资源。但是静态博客，无后端的情况下，解密过程是在前端的，也就是无法对尝试次数之类的进行任何限制。这其实并不算很安全的一种方案。

即使如此也有其用途。在 Hexo 插件中，使用方法就是在文章 Metadata 加上一些字段就行了。也就说这种方法如果想保密不能公开源码。在 Hugo 这里要麻烦一些，Hugo 本身似乎并没有提供插件功能，也没有不修改源码就增加内置函数的功能。倒是找到了使用 python 处理的一些方法。

因此，我进行了以下尝试。

1. 把所有需要加密的初始文本片段，加入一个被 git 忽略的文件夹。
2. 运行一个脚本，或者手动使用加密工具加密，然后生成的密文填入一个 txt 文件中。
3. 生成的加密文件作为静态文件附件公开，一同随网站发布。
4. 写了个 Hugo 的 Shortcode 用于生成用户端解密显示，填入加密文件 URL 。

## 实现

我使用的加密算法是 Xxtea ，这是一个很容易实现的算法。就博客文章加密场景，或许一个异或运算加密就足够了，这样能少引入一个 js 。不过 Xxtea 在网络上也有不少现成的加解密工具可以使用，也挺不错的。

Hugo shortcode 代码贴在下面，或者在我网站源码里也能找到。引入的 js 在 https://github.com/xxtea/xxtea-js

## 代码

Shortcode 代码 

```html
{{- $url := .Get "url" -}}
{{- $md5Hash := md5 $url -}}
{{- $md5Short := substr $md5Hash 0 8 -}}

<div id="{{- $md5Short -}}-bar" style="display: none;">
    <input id="password" placeholder="请输入口令..."></input>
    <div><button id="submitBtn">解密</button></div>
</div>
<div id="{{- $md5Short -}}">
</div>
<script type="text/javascript" src="https://cdn.ftls.xyz/js/crypto/xxtea.js"></script>
<script>
    const msg = document.getElementById("{{- $md5Short -}}");
    const submitBtn = document.getElementById("submitBtn");
    let newText = "";
    function getNewText() {
        fetch("{{ $url }}")
            .then(response => response.text())
            .then(text => {
                console.log("加载密文: " + text);
                msg.innerHTML = "已加载密文";
                newText = text;
                document.getElementById("{{- $md5Short -}}-bar").style.display = "block";
            });
    }
    getNewText();
    submitBtn.addEventListener("click", () => {
        const password = document.getElementById("password").value;
        console.log("口令: " + password, "密文: " + newText);
        try {
            let decrypt_data = XXTEA.decryptFromBase64(newText.trim(), password);
            msg.innerHTML = decrypt_data;
        } catch (error) {
            msg.innerHTML = "口令错误";
        }
    });
</script>
```

一个加密小程序，可以使用 Deno 运行

```js
// XXTEA 方法 XXTEA.encryptToBase64 XXTEA.decryptFromBase64
// https://github.com/xxtea/xxtea-js  MIT license
// https://github.com/zhaidw/xxtea-ts MIT license

import XXTEA from "https://deno.land/x/xxtea@v0.1.0/mod.ts";

const fileName = "README.md";
const text = Deno.readTextFileSync(fileName);
const encrypted = XXTEA.encryptToBase64(text, "password");
Deno.writeTextFileSync(fileName + ".xxtea.txt", encrypted);


//  deno run --allow-read --allow-write test.js 
```

或者将一个文件夹内的文本文件，批量加密

```ts
// deno run --allow-read --allow-write xxtea-utils.ts
console.log("XXTEA 加密 CLI")
console.log(Deno.args);

import XXTEA from "https://deno.land/x/xxtea@v0.1.0/mod.ts";

const basePath = ""

const inputFilesPath = basePath + "kkbt/xxtea/"
for (const file of Deno.readDirSync(inputFilesPath)) {
    console.log(file.name);
    if (file.isFile) {
        const text = Deno.readTextFileSync(inputFilesPath + file.name)
        const data = XXTEA.encryptToBase64(text, "password");
        Deno.writeTextFileSync(basePath + "kkbt/xxtea/output/" + file.name + ".xxtea.txt", data);
    }

}
```