refactor(encrypt): rename post-encrypt to encrypt

- Rename package from @hugo-fixit/post-encrypt to @hugo-fixit/encrypt
- Rename bin from post-encrypt to fixit-encrypt
- Update all i18n translations (16 files) to use npx @hugo-fixit/encrypt
- Update CI workflow, publish script, code comments, and docs
- Rewrite README with performance benchmarks and other implementations
This commit is contained in:
Cell
2026-07-19 13:15:57 +08:00
parent 78f1a8583a
commit bfee4041d6
29 changed files with 160 additions and 122 deletions
@@ -1,9 +1,9 @@
name: Publish post-encrypt name: Publish @hugo-fixit/encrypt
on: on:
push: push:
tags: tags:
- 'post-encrypt-v*.*.*' - 'encrypt-v*.*.*'
workflow_dispatch: workflow_dispatch:
permissions: permissions:
@@ -11,7 +11,7 @@ permissions:
id-token: write id-token: write
concurrency: concurrency:
group: publish-post-encrypt-${{ github.ref }} group: publish-encrypt-${{ github.ref }}
cancel-in-progress: false cancel-in-progress: false
jobs: jobs:
@@ -36,8 +36,8 @@ jobs:
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
- name: Build package - name: Build package
run: pnpm -F post-encrypt build run: pnpm -F encrypt build
- name: Publish package to npm - name: Publish package to npm
working-directory: packages/post-encrypt working-directory: packages/encrypt
run: npm publish --access public --provenance run: npm publish --access public --provenance
+1 -1
View File
@@ -12,7 +12,7 @@
* *
* Payload formats: * Payload formats:
* - v2 (current): PBKDF2(SHA-256(password), 100k iterations) → base64(salt).base64(iv).base64(ciphertext+tag) * - v2 (current): PBKDF2(SHA-256(password), 100k iterations) → base64(salt).base64(iv).base64(ciphertext+tag)
* - Password verification: data-password stores PBKDF2(SHA-256(password), data-verify-salt) when post-encrypted * - Password verification: data-password stores PBKDF2(SHA-256(password), data-verify-salt) when fixit-encrypted
*/ */
import { eventBus } from '../core/event-bus' import { eventBus } from '../core/event-bus'
import { flashTooltip } from '../utils' import { flashTooltip } from '../utils'
+1 -1
View File
@@ -146,7 +146,7 @@ password = "Passwort"
enterBtn = "Eintreten" enterBtn = "Eintreten"
encryptyAgain = "Erneut verschlüsseln" encryptyAgain = "Erneut verschlüsseln"
encryptionWarning = "Inhaltsverschlüsselung erkannt, aber sie sind noch im Klartext!" encryptionWarning = "Inhaltsverschlüsselung erkannt, aber sie sind noch im Klartext!"
encryptionCommand = "Führen Sie `npx @hugo-fixit/post-encrypt` nach dem Build aus, um sie tatsächlich zu verschlüsseln." encryptionCommand = "Führen Sie `npx @hugo-fixit/encrypt` nach dem Build aus, um sie tatsächlich zu verschlüsseln."
relatedContent = "Ähnliche Inhalte" relatedContent = "Ähnliche Inhalte"
[single.includedIn] [single.includedIn]
+1 -1
View File
@@ -146,7 +146,7 @@ password = "Password"
enterBtn = "Enter" enterBtn = "Enter"
encryptyAgain = "Encrypt again" encryptyAgain = "Encrypt again"
encryptionWarning = "Content encryption detected, but they are still in plaintext!" encryptionWarning = "Content encryption detected, but they are still in plaintext!"
encryptionCommand = "Run `npx @hugo-fixit/post-encrypt` after building to actually encrypt them." encryptionCommand = "Run `npx @hugo-fixit/encrypt` after building to actually encrypt them."
relatedContent = "Related Content" relatedContent = "Related Content"
[single.includedIn] [single.includedIn]
+1 -1
View File
@@ -146,7 +146,7 @@ password = "Contraseña"
enterBtn = "Entrar" enterBtn = "Entrar"
encryptyAgain = "Encriptar de nuevo" encryptyAgain = "Encriptar de nuevo"
encryptionWarning = "¡Se detectó cifrado de contenido, pero aún están en texto plano!" encryptionWarning = "¡Se detectó cifrado de contenido, pero aún están en texto plano!"
encryptionCommand = "Ejecute `npx @hugo-fixit/post-encrypt` después de la compilación para cifrarlos realmente." encryptionCommand = "Ejecute `npx @hugo-fixit/encrypt` después de la compilación para cifrarlos realmente."
relatedContent = "Contenido relacionado" relatedContent = "Contenido relacionado"
[single.includedIn] [single.includedIn]
+1 -1
View File
@@ -146,7 +146,7 @@ password = "Mot de passe"
enterBtn = "Entrer" enterBtn = "Entrer"
encryptyAgain = "Chiffrer à nouveau" encryptyAgain = "Chiffrer à nouveau"
encryptionWarning = "Chiffrement de contenu détecté, mais ils sont toujours en texte clair !" encryptionWarning = "Chiffrement de contenu détecté, mais ils sont toujours en texte clair !"
encryptionCommand = "Exécutez `npx @hugo-fixit/post-encrypt` après la compilation pour les chiffrer réellement." encryptionCommand = "Exécutez `npx @hugo-fixit/encrypt` après la compilation pour les chiffrer réellement."
relatedContent = "Contenu lié" relatedContent = "Contenu lié"
[single.includedIn] [single.includedIn]
+1 -1
View File
@@ -147,7 +147,7 @@ password = "पासवर्ड"
enterBtn = "दर्ज करें" enterBtn = "दर्ज करें"
encryptyAgain = "फिर से एन्क्रिप्ट करें" encryptyAgain = "फिर से एन्क्रिप्ट करें"
encryptionWarning = "सामग्री एन्क्रिप्शन का पता चला, लेकिन वे अभी भी सादे पाठ में हैं!" encryptionWarning = "सामग्री एन्क्रिप्शन का पता चला, लेकिन वे अभी भी सादे पाठ में हैं!"
encryptionCommand = "उन्हें वास्तव में एन्क्रिप्ट करने के लिए बिल्ड के बाद `npx @hugo-fixit/post-encrypt` चलाएं।" encryptionCommand = "उन्हें वास्तव में एन्क्रिप्ट करने के लिए बिल्ड के बाद `npx @hugo-fixit/encrypt` चलाएं।"
relatedContent = "संबंधित सामग्री" relatedContent = "संबंधित सामग्री"
[single.includedIn] [single.includedIn]
+1 -1
View File
@@ -146,7 +146,7 @@ password = "Password"
enterBtn = "Entra" enterBtn = "Entra"
encryptyAgain = "Crittografa di nuovo" encryptyAgain = "Crittografa di nuovo"
encryptionWarning = "Rilevata crittografia dei contenuti, ma sono ancora in testo in chiaro!" encryptionWarning = "Rilevata crittografia dei contenuti, ma sono ancora in testo in chiaro!"
encryptionCommand = "Eseguire `npx @hugo-fixit/post-encrypt` dopo la compilazione per crittograffarli effettivamente." encryptionCommand = "Eseguire `npx @hugo-fixit/encrypt` dopo la compilazione per crittograffarli effettivamente."
relatedContent = "Contenuti correlati" relatedContent = "Contenuti correlati"
[single.includedIn] [single.includedIn]
+1 -1
View File
@@ -144,7 +144,7 @@ password = "パスワード"
enterBtn = "入る" enterBtn = "入る"
encryptyAgain = "再度暗号化" encryptyAgain = "再度暗号化"
encryptionWarning = "コンテンツの暗号化が検出されましたが、まだ平文です!" encryptionWarning = "コンテンツの暗号化が検出されましたが、まだ平文です!"
encryptionCommand = "実際に暗号化するには、ビルド後に `npx @hugo-fixit/post-encrypt` を実行してください。" encryptionCommand = "実際に暗号化するには、ビルド後に `npx @hugo-fixit/encrypt` を実行してください。"
relatedContent = "関連コンテンツ" relatedContent = "関連コンテンツ"
[single.includedIn] [single.includedIn]
+1 -1
View File
@@ -144,7 +144,7 @@ password = "비밀번호"
enterBtn = "입장" enterBtn = "입장"
encryptyAgain = "다시 암호화" encryptyAgain = "다시 암호화"
encryptionWarning = "콘텐츠 암호화가 감지되었지만 여전히 평문입니다!" encryptionWarning = "콘텐츠 암호화가 감지되었지만 여전히 평문입니다!"
encryptionCommand = "실제로 암호화하려면 빌드 후 `npx @hugo-fixit/post-encrypt`를 실행하세요." encryptionCommand = "실제로 암호화하려면 빌드 후 `npx @hugo-fixit/encrypt`를 실행하세요."
relatedContent = "관련 콘텐츠" relatedContent = "관련 콘텐츠"
[single.includedIn] [single.includedIn]
+1 -1
View File
@@ -146,7 +146,7 @@ password = "Hasło"
enterBtn = "Wejdź" enterBtn = "Wejdź"
encryptyAgain = "Zaszyfruj ponownie" encryptyAgain = "Zaszyfruj ponownie"
encryptionWarning = "Wykryto szyfrowanie treści, ale nadal są w postaci zwykłego tekstu!" encryptionWarning = "Wykryto szyfrowanie treści, ale nadal są w postaci zwykłego tekstu!"
encryptionCommand = "Uruchom `npx @hugo-fixit/post-encrypt` po kompilacji, aby je faktycznie zaszyfrować." encryptionCommand = "Uruchom `npx @hugo-fixit/encrypt` po kompilacji, aby je faktycznie zaszyfrować."
relatedContent = "Powiązane treści" relatedContent = "Powiązane treści"
[single.includedIn] [single.includedIn]
+1 -1
View File
@@ -147,7 +147,7 @@ password = "Senha"
enterBtn = "Entrar" enterBtn = "Entrar"
encryptyAgain = "Encripte novamente" encryptyAgain = "Encripte novamente"
encryptionWarning = "Criptografia de conteúdo detectada, mas ainda estão em texto plano!" encryptionWarning = "Criptografia de conteúdo detectada, mas ainda estão em texto plano!"
encryptionCommand = "Execute `npx @hugo-fixit/post-encrypt` após a compilação para realmente criptografá-los." encryptionCommand = "Execute `npx @hugo-fixit/encrypt` após a compilação para realmente criptografá-los."
relatedContent = "Conteúdo relacionado" relatedContent = "Conteúdo relacionado"
[single.includedIn] [single.includedIn]
+1 -1
View File
@@ -146,7 +146,7 @@ password = "Parolă"
enterBtn = "Intră" enterBtn = "Intră"
encryptyAgain = "Criptează din nou" encryptyAgain = "Criptează din nou"
encryptionWarning = "Criptarea conținutului a fost detectată, dar sunt încă în text clar!" encryptionWarning = "Criptarea conținutului a fost detectată, dar sunt încă în text clar!"
encryptionCommand = "Rulați `npx @hugo-fixit/post-encrypt` după compilare pentru a le cripta efectiv." encryptionCommand = "Rulați `npx @hugo-fixit/encrypt` după compilare pentru a le cripta efectiv."
relatedContent = "Conținut înrudit" relatedContent = "Conținut înrudit"
[single.includedIn] [single.includedIn]
+1 -1
View File
@@ -146,7 +146,7 @@ password = "арготизм"
enterBtn = "Войти" enterBtn = "Войти"
encryptyAgain = "Зашифровать снова" encryptyAgain = "Зашифровать снова"
encryptionWarning = "Обнаружено шифрование контента, но он всё ещё в открытом виде!" encryptionWarning = "Обнаружено шифрование контента, но он всё ещё в открытом виде!"
encryptionCommand = "Запустите `npx @hugo-fixit/post-encrypt` после сборки, чтобы фактически зашифровать их." encryptionCommand = "Запустите `npx @hugo-fixit/encrypt` после сборки, чтобы фактически зашифровать их."
relatedContent = "Связанный контент" relatedContent = "Связанный контент"
[single.includedIn] [single.includedIn]
+1 -1
View File
@@ -146,7 +146,7 @@ password = "Паролица"
enterBtn = "Унеси" enterBtn = "Унеси"
encryptyAgain = "Поново шифруј" encryptyAgain = "Поново шифруј"
encryptionWarning = "Детектовано је шифровање садржаја, али су и даље у обичном тексту!" encryptionWarning = "Детектовано је шифровање садржаја, али су и даље у обичном тексту!"
encryptionCommand = "Покрените `npx @hugo-fixit/post-encrypt` након изградње да бисте их заиста шифровали." encryptionCommand = "Покрените `npx @hugo-fixit/encrypt` након изградње да бисте их заиста шифровали."
relatedContent = "Повезани садржај" relatedContent = "Повезани садржај"
[single.includedIn] [single.includedIn]
+1 -1
View File
@@ -145,7 +145,7 @@ password = "Mật khẩu"
enterBtn = "Nhập" enterBtn = "Nhập"
encryptyAgain = "Mã hóa lại" encryptyAgain = "Mã hóa lại"
encryptionWarning = "Phát hiện mã hóa nội dung, nhưng chúng vẫn ở dạng văn bản thuần!" encryptionWarning = "Phát hiện mã hóa nội dung, nhưng chúng vẫn ở dạng văn bản thuần!"
encryptionCommand = "Chạy `npx @hugo-fixit/post-encrypt` sau khi build để thực sự mã hóa chúng." encryptionCommand = "Chạy `npx @hugo-fixit/encrypt` sau khi build để thực sự mã hóa chúng."
relatedContent = "Nội dung liên quan" relatedContent = "Nội dung liên quan"
[single.includedIn] [single.includedIn]
+1 -1
View File
@@ -144,7 +144,7 @@ password = "密码"
enterBtn = "进入" enterBtn = "进入"
encryptyAgain = "重新加密" encryptyAgain = "重新加密"
encryptionWarning = "检测到内容加密,但仍为明文状态!" encryptionWarning = "检测到内容加密,但仍为明文状态!"
encryptionCommand = "请在构建后执行 `npx @hugo-fixit/post-encrypt` 以实际加密内容。" encryptionCommand = "请在构建后执行 `npx @hugo-fixit/encrypt` 以实际加密内容。"
relatedContent = "相关内容" relatedContent = "相关内容"
[single.includedIn] [single.includedIn]
+1 -1
View File
@@ -144,7 +144,7 @@ password = "密碼"
enterBtn = "進入" enterBtn = "進入"
encryptyAgain = "重新加密" encryptyAgain = "重新加密"
encryptionWarning = "偵測到內容加密,但仍為明文狀態!" encryptionWarning = "偵測到內容加密,但仍為明文狀態!"
encryptionCommand = "請在建構後執行 `npx @hugo-fixit/post-encrypt` 以實際加密內容。" encryptionCommand = "請在建構後執行 `npx @hugo-fixit/encrypt` 以實際加密內容。"
relatedContent = "相關內容" relatedContent = "相關內容"
[single.includedIn] [single.includedIn]
+1 -1
View File
@@ -1,4 +1,4 @@
{{- hugo.Store.Set "version" "v1.0.0-mrpajmty" -}} {{- hugo.Store.Set "version" "v1.0.0-mrrceo88" -}}
{{- .Store.Set "this" dict -}} {{- .Store.Set "this" dict -}}
{{- partial "init/detection-env.html" . -}} {{- partial "init/detection-env.html" . -}}
+1 -1
View File
@@ -159,7 +159,7 @@
</div> </div>
<div class="details-content toc-content" id="toc-content-static"></div> <div class="details-content toc-content" id="toc-content-static"></div>
</div> </div>
{{- /* TOC source (copied to containers by initToc, encrypted by post-encrypt when password is set) */ -}} {{- /* TOC source (copied to containers by initToc, encrypted by fixit-encrypt when password is set) */ -}}
<template data-toc{{ with .Params.password }} data-password="{{ sha256 . }}"{{ end }}>{{ $tableOfContents }}</template> <template data-toc{{ with .Params.password }} data-password="{{ sha256 . }}"{{ end }}>{{ $tableOfContents }}</template>
{{- end -}} {{- end -}}
+1 -1
View File
@@ -35,7 +35,7 @@
"build:demo": "pnpm -F demo build", "build:demo": "pnpm -F demo build",
"build:test": "pnpm -F test build", "build:test": "pnpm -F test build",
"build": "concurrently 'pnpm build:demo' 'pnpm build:test' && pnpm -F integration start && pnpm encrypt && pnpm encrypt --verify", "build": "concurrently 'pnpm build:demo' 'pnpm build:test' && pnpm -F integration start && pnpm encrypt && pnpm encrypt --verify",
"encrypt": "pnpm -F post-encrypt start", "encrypt": "pnpm -F encrypt start",
"clean": "rm -rf public resources/_gen apps/*/public apps/*/resources/_gen", "clean": "rm -rf public resources/_gen apps/*/public apps/*/resources/_gen",
"preview": "serve public", "preview": "serve public",
"lint": "eslint --cache .", "lint": "eslint --cache .",
+113
View File
@@ -0,0 +1,113 @@
# @hugo-fixit/encrypt
Post-build AES-256-GCM encryption tool for the [FixIt](https://github.com/hugo-fixit/FixIt) Hugo theme.
It is designed for HTML generated by FixIt content encryption templates and should be run after your site has already been built.
## Usage
> After building your Hugo site, run the encryption tool from your site root.
Recommended: install as a dev dependency and configure scripts:
```bash
npm install -D @hugo-fixit/encrypt
```
Then in your `package.json`:
```json
{
"scripts": {
"build": "hugo --gc --minify --logLevel info",
"postbuild": "fixit-encrypt && fixit-encrypt --verify"
}
}
```
You can also run it directly via npx:
```bash
npx @hugo-fixit/encrypt
```
Or install globally and run the CLI directly:
```bash
npm install -g @hugo-fixit/encrypt
fixit-encrypt
```
### Options
| Option | Description | Default |
| --------------- | -------------------------------------------------- | -------- |
| `--input <dir>` | Input directory containing HTML files | `public` |
| `--dry-run` | Show which files would be modified without writing | `false` |
| `--verify` | Verify all encryption templates are encrypted | `false` |
| `-h, --help` | Show CLI usage help | |
### Examples
```bash
# Show CLI help
npx @hugo-fixit/encrypt --help
# Encrypt content in the default public/ directory
npx @hugo-fixit/encrypt
# Encrypt content in a custom directory
npx @hugo-fixit/encrypt --input dist
# Verify encryption without modifying files
npx @hugo-fixit/encrypt --verify
# Dry run to see which files would be changed
npx @hugo-fixit/encrypt --dry-run
```
## How It Works
1. Scans all `.html` files in the input directory
2. Finds `<template data-password="...">` elements (encryption placeholders)
3. Encrypts the plaintext content using AES-256-GCM with PBKDF2 key derivation
4. Replaces the `data-password` hash with a PBKDF2-protected version
5. Writes the encrypted payload back to the template element
### Security
- **Algorithm**: AES-256-GCM (authenticated encryption)
- **Key derivation**: PBKDF2 with 100,000 iterations and random 16-byte salt
- **Password verification**: PBKDF2-protected hash (not raw SHA-256)
- **Payload format**: `base64(salt).base64(iv).base64(ciphertext+tag)`
## Performance
The performance bottleneck is **PBKDF2 key derivation** (100,000 iterations), which takes approximately **~53ms per template**. This is CPU-bound cryptographic computation — file I/O is negligible in comparison.
Benchmark results (Node.js v22, Apple M-series):
| Files | Templates | Total Time | Per Template |
| ----- | --------- | ---------- | ------------ |
| 100 | 100 | ~6s | ~59ms |
| 500 | 500 | ~27s | ~53ms |
| 1000 | 1000 | ~53s | ~53ms |
The per-template cost is constant regardless of file count or content size, as PBKDF2 dominates the runtime.
## Other Implementations
The current implementation is in **Node.js (TypeScript)**. For environments where Node.js performance is a bottleneck, community-maintained implementations in other languages are welcome:
| Language | Status | Repository |
| -------- | --------- | ---------------- |
| Node.js | Available | hugo-fixit/FixIt |
| Python | Planned | — |
| Go | Planned | — |
| Rust | Planned | — |
If you have implemented `fixit-encrypt` in another language, please open a PR to add it to this list.
## License
MIT
@@ -1,15 +1,15 @@
{ {
"name": "@hugo-fixit/post-encrypt", "name": "@hugo-fixit/encrypt",
"type": "module", "type": "module",
"version": "0.2.0", "version": "0.2.0",
"description": "Post-build AES-256-GCM encryption tool for the FixIt Hugo theme", "description": "Post-build AES-256-GCM encryption tool for the FixIt Hugo theme",
"author": "Lruihao", "author": "Lruihao",
"license": "MIT", "license": "MIT",
"homepage": "https://github.com/hugo-fixit/FixIt/tree/main/packages/post-encrypt#readme", "homepage": "https://github.com/hugo-fixit/FixIt/tree/main/packages/encrypt#readme",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/hugo-fixit/FixIt.git", "url": "git+https://github.com/hugo-fixit/FixIt.git",
"directory": "packages/post-encrypt" "directory": "packages/encrypt"
}, },
"bugs": { "bugs": {
"url": "https://github.com/hugo-fixit/FixIt/issues" "url": "https://github.com/hugo-fixit/FixIt/issues"
@@ -23,7 +23,7 @@
], ],
"main": "./dist/index.js", "main": "./dist/index.js",
"bin": { "bin": {
"post-encrypt": "./dist/index.js" "fixit-encrypt": "./dist/index.js"
}, },
"files": [ "files": [
"dist" "dist"
@@ -23,7 +23,7 @@ bump="$1"
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
repo_root="$(cd "${script_dir}/../.." && pwd)" repo_root="$(cd "${script_dir}/../.." && pwd)"
package_json_rel="packages/post-encrypt/package.json" package_json_rel="packages/encrypt/package.json"
package_json_abs="${repo_root}/${package_json_rel}" package_json_abs="${repo_root}/${package_json_rel}"
if [[ ! -f "${package_json_abs}" ]]; then if [[ ! -f "${package_json_abs}" ]]; then
@@ -39,9 +39,9 @@ fi
npm --prefix "${script_dir}" version "${bump}" --no-git-tag-version > /dev/null npm --prefix "${script_dir}" version "${bump}" --no-git-tag-version > /dev/null
version="$(node -p "require('${package_json_abs}').version")" version="$(node -p "require('${package_json_abs}').version")"
tag="post-encrypt-v${version}" tag="encrypt-v${version}"
commit_msg="chore(release): post-encrypt ${version}" commit_msg="chore(release): encrypt ${version}"
tag_msg="release: @hugo-fixit/post-encrypt ${version}" tag_msg="release: @hugo-fixit/encrypt ${version}"
if git -C "${repo_root}" rev-parse -q --verify "refs/tags/${tag}" > /dev/null; then if git -C "${repo_root}" rev-parse -q --verify "refs/tags/${tag}" > /dev/null; then
echo "Tag already exists: ${tag}" >&2 echo "Tag already exists: ${tag}" >&2
@@ -52,7 +52,7 @@ git -C "${repo_root}" add "${package_json_rel}"
git -C "${repo_root}" commit -m "${commit_msg}" git -C "${repo_root}" commit -m "${commit_msg}"
git -C "${repo_root}" tag -a "${tag}" -m "${tag_msg}" git -C "${repo_root}" tag -a "${tag}" -m "${tag_msg}"
echo "Released @hugo-fixit/post-encrypt ${version}" echo "Released @hugo-fixit/encrypt ${version}"
echo "Created commit: ${commit_msg}" echo "Created commit: ${commit_msg}"
echo "Created tag: ${tag}" echo "Created tag: ${tag}"
echo "Next: git push origin main --follow-tags" echo "Next: git push origin main --follow-tags"
@@ -72,7 +72,7 @@ function parseArgs(argv: string[]): CliOptions {
function printHelp(): void { function printHelp(): void {
consola.log(`Usage: consola.log(`Usage:
post-encrypt [options] fixit-encrypt [options]
Options: Options:
--input <dir> Input directory containing HTML files (default: public) --input <dir> Input directory containing HTML files (default: public)
@@ -81,10 +81,10 @@ Options:
-h, --help Show this help message -h, --help Show this help message
Examples: Examples:
post-encrypt fixit-encrypt
post-encrypt --input dist fixit-encrypt --input dist
post-encrypt --verify fixit-encrypt --verify
post-encrypt --dry-run`) fixit-encrypt --dry-run`)
} }
function collectHtmlFiles(targetDir: string): string[] { function collectHtmlFiles(targetDir: string): string[] {
@@ -6,7 +6,7 @@ import { fileURLToPath } from 'node:url'
import consola from 'consola' import consola from 'consola'
const __dirname = dirname(fileURLToPath(import.meta.url)) const __dirname = dirname(fileURLToPath(import.meta.url))
const BENCH_DIR = '/tmp/post-encrypt-bench' const BENCH_DIR = '/tmp/fixit-encrypt-bench'
const PASSWORD_HASH = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' const PASSWORD_HASH = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
@@ -54,7 +54,7 @@ function bench(files: number, templatesPerFile: number, templateSize: string): v
) )
} }
consola.info('=== post-encrypt benchmark ===\n') consola.info('=== fixit-encrypt benchmark ===\n')
consola.info('--- Test 1: 1 small template/file, scaling file count ---') consola.info('--- Test 1: 1 small template/file, scaling file count ---')
for (const n of [10, 50, 100, 500, 1000]) { for (const n of [10, 50, 100, 500, 1000]) {
-75
View File
@@ -1,75 +0,0 @@
# @hugo-fixit/post-encrypt
Post-build AES-256-GCM encryption tool for the [FixIt](https://github.com/hugo-fixit/FixIt) Hugo theme.
It is designed for HTML generated by FixIt content encryption templates and should be run after your site has already been built.
## Usage
After building your Hugo site, run the encryption tool from your site root:
```bash
npx @hugo-fixit/post-encrypt
```
You can also install it globally and run the CLI directly:
```bash
npm install -g @hugo-fixit/post-encrypt
post-encrypt
```
Typical build flow:
```bash
hugo build
npx @hugo-fixit/post-encrypt
npx @hugo-fixit/post-encrypt --verify
```
### Options
| Option | Description | Default |
| --------------- | -------------------------------------------------- | -------- |
| `--input <dir>` | Input directory containing HTML files | `public` |
| `--dry-run` | Show which files would be modified without writing | `false` |
| `--verify` | Verify all encryption templates are encrypted | `false` |
| `-h, --help` | Show CLI usage help | |
### Examples
```bash
# Show CLI help
npx @hugo-fixit/post-encrypt --help
# Encrypt content in the default public/ directory
npx @hugo-fixit/post-encrypt
# Encrypt content in a custom directory
npx @hugo-fixit/post-encrypt --input dist
# Verify encryption without modifying files
npx @hugo-fixit/post-encrypt --verify
# Dry run to see which files would be changed
npx @hugo-fixit/post-encrypt --dry-run
```
## How It Works
1. Scans all `.html` files in the input directory
2. Finds `<template data-password="...">` elements (encryption placeholders)
3. Encrypts the plaintext content using AES-256-GCM with PBKDF2 key derivation
4. Replaces the `data-password` hash with a PBKDF2-protected version
5. Writes the encrypted payload back to the template element
### Security
- **Algorithm**: AES-256-GCM (authenticated encryption)
- **Key derivation**: PBKDF2 with 100,000 iterations and random 16-byte salt
- **Password verification**: PBKDF2-protected hash (not raw SHA-256)
- **Payload format**: `base64(salt).base64(iv).base64(ciphertext+tag)`
## License
MIT
+6 -6
View File
@@ -67,6 +67,12 @@ importers:
specifier: ^9.4.1 specifier: ^9.4.1
version: 9.4.1 version: 9.4.1
packages/encrypt:
dependencies:
consola:
specifier: ^3.4.2
version: 3.4.2
packages/integration: packages/integration:
devDependencies: devDependencies:
'@hugo-fixit/shared': '@hugo-fixit/shared':
@@ -79,12 +85,6 @@ importers:
specifier: ^11.3.6 specifier: ^11.3.6
version: 11.3.6 version: 11.3.6
packages/post-encrypt:
dependencies:
consola:
specifier: ^3.4.2
version: 3.4.2
packages/shared: packages/shared:
dependencies: dependencies:
consola: consola: