Files
ChuBlog/docs/publishing.md
T

7.5 KiB

账户授权与文章发布

返回项目首页

用户与发布授权

完整接口见 API 文档。

  1. 注册:POST /api/auth/register,正文 { "username": "alice", "password": "至少12字节的口令" }。默认角色 reader,绝不接受客户端指定角色。ALLOW_REGISTRATION=false 可关闭注册。
  2. 登录:POST /api/auth/login,相同字段。浏览器保存 HttpOnly Cookie;返回 csrf。所有修改请求必须携带站点 Origin 和 X-CSRF-Token。
  3. 本地生成 ssh-keygen -t ed25519 或 ssh-keygen -t rsa -b 3072;登录后 PUT /api/account/ssh-key 提交 { "public_key": "ssh-ed25519 AAAA..." },只交公钥。RSA 使用标准 ssh-rsa AAAA... 公钥文本,支持 2048–8192 位;实际认证使用 RSA/SHA-256 或 RSA/SHA-512,不启用旧的 SHA-1 签名。见 OpenSSH 说明。
  4. 管理员登录后调用 PATCH /api/admin/users/alice,正文 { "enabled": true, "role": "publisher" }。服务器按公钥绑定的用户分配独立仓库。
  5. 此时 SSH 才接受该用户的密钥;reader、停用用户、未绑密钥的用户均不能访问 Git。管理员也需登记公钥才能发布。旧 prefixes 字段仅为兼容保留,不再用于文章隔离。
  • 授权与密钥独立:知道服务器地址、有网站账户、上传了公钥都不足以推送。
  • 设回 reader 或 enabled:false 会撤回发布授权,并使现有网站会话失效。
  • 禁止管理员停用自己或取消自己的管理角色。

克隆个人文章仓库

先通过可信渠道核对服务器主机密钥指纹,再在本机 ~/.ssh/config 配置连接:

Host chublog
    HostName blog.example.com
    Port 2222
    User git
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes

将域名、端口和私钥路径替换为部署者提供的值。主机密钥检查应保持开启。服务器根据公钥识别作者,不使用 Git 的 author/email 判定身份。

git clone chublog:content.git my-articles
cd my-articles

每位作者都使用 content.git 别名。服务器将别名映射到该作者的独立仓库,并在首次访问时创建裸仓库,作者无需服务器 shell。仓库已有提交时,每轮编辑前先执行 git pull --ff-only。

创建 TOML 索引

在仓库根目录创建 UTF-8 文件 index.toml,每篇文章使用一个 [[articles]] 表:

[[articles]]
id = "first"
folder = "posts/first"
title = "第一篇文章"
description = "文章简介"
tags = ["Rust", "随笔"]
public = true
# cover = "cover.png"
# entry = "main.md"

id 和 folder 用于标识文章及其目录。文章元信息仅接受以下字段:

字段 含义与默认值
title 必填标题,最多 240 字节
description 简介,省略时为空,最多 1000 字节
tags 标签,默认空数组,最多 12 项,每项最多 80 字节
cover 可选封面,填写同文章目录中的图片文件名
public 是否公开,默认 false
entry 入口文档名,默认 main.md

作者身份由 SSH 公钥绑定的账户确定。创建时间、首次公开时间和修改时间由服务端生成,以 UTC 时间保存。索引不接受 author、date、updated、精华或权限等额外字段。正文不再使用 Frontmatter。

文章 ID 在作者内唯一,允许 1 到 40 位小写字母、数字和中间短横线。目录为 posts/<目录名>,目录名最多 80 字节并遵循 slug 规则。ID 和目录名不能使用保留名称,例如 admin 或 api。同一目录不能登记多次。

文件名只允许 ASCII 字母、数字、短横线、下划线和点,最多 100 字节,不能以点开头或含 ..。入口允许 .md、.markdown 和 .txt,扩展名须为小写。索引最多 64 KiB、1000 篇文章。要撤回全部文章,明确写入 articles = [];空文件缺少文章字段,会暂存并保留原文章。

编写多页文章

示例目录:

index.toml
posts/
└── first/
    ├── main.md
    ├── chapter.md
    └── cover.png

main.md 内容:

# 第一篇文章

[阅读第二页](chapter.md#details)

![封面](cover.png)

chapter.md 内容:

# 第二页

## Details

[返回入口](./main.md)

服务端从入口沿文章内相对链接收集页面,允许循环链接,每篇最多 64 个可达页面。链接目标必须是同目录的文本文件,可以带 #锚点,不支持子目录、../、编码路径和查询参数。相对链接缺少目标文件时,整份索引暂存,原文章不更新。普通 HTTP、HTTPS、mailto 和站内绝对链接继续受安全检查。

未登记目录、从入口无法到达的文档,以及未被页面引用的图片不进入阅读快照或数据库。封面即使未在正文引用,也作为文章资源导入。所有上传文件仍受白名单、安全检查和仓库配额约束。.txt 页面通过 format: text 返回,阅读端须作为纯文本显示。

参考索引样例、入口样例和第二页样例。

提交并验证发布

git add index.toml posts/first
git commit -m 'Publish first article'
git push -u origin main

服务端会校验提交并自动导入。站内文章 ID 为 作者名~文章ID,例如 /api/posts/alice~first。文章 API 返回入口正文、页面列表和资源地址;页面通过 /api/posts/alice~first/pages/chapter.md 读取。前端需将文档相对链接映射到返回的页面 URL,并保留锚点。

提交内容 结果
有效索引、新增文章且入口存在 导入文章并创建数据库元信息与页面记录
有效索引、修改正文或元信息 更新文章,保留首次公开时间;内容实际变化时更新修改时间
有效索引、删除文章表 撤回文章、页面、资源入口及数据库派生记录
有效索引、入口文件或目录缺失 将该文章视为不存在,撤回旧版本;其他有效文章仍可导入
TOML 缺失、语法错误、未知字段或元信息无效 Git 提交暂存,不修改该作者原有文章,等待修复后的下一次推送
脚本、非法文件类型、危险路径或内容超限 拒绝整个推送,远端分支不前进

public = false 的内容不会由公共文章、页面或资源接口返回。登录后查看内部文章的功能仍在待办中。删除和撤回不擦除个人 Git 历史,也不收回作者已克隆的副本。

提交限制与状态查询

每次推送只接受一个直接继承个人远端 main 的提交,首次必须是根提交。禁止 merge、force push、删除 main、标签和其他分支。多次本地提交须先整理为一次提交,再变基到最新远端。同一作者在多台电脑操作仍需处理冲突,不同作者使用不同仓库锁。

管理员通过 GET /api/admin/status 查看状态。commit 是当前生效作者提交映射的集合摘要,indexed_commit 是数据库已同步的集合版本。pending 按作者返回暂存提交和索引错误。暂存提交不会替换生效版本,API 重启后仍保留原文章和暂存状态。

同步通常在下一轮后台处理时完成。数据库失败至少间隔 30 秒重试,作者较多或索引重建时可能延迟。Git 接受不代表文章已公开或数据库已同步。站长审核尚未启用,计划见 TODO。