后端基础层:模块定义、配置解析、SQLite 存储层、Argon2id 认证与 Markdown 渲染

- internal/config:serve/init/backup/gc 子命令参数解析(--dev 强制 loopback 守卫)
- internal/store:user_version 版本化迁移(仅追加式 + 越界拒启 + --allow-newer)、
  笔记/图片/引用/会话/设置 DAO、并集可见性查询、VACUUM INTO 在线备份、
  回收站 30 天 + 孤儿图 7 天宽限 gc
- internal/auth:Argon2id PHC 串(m=19456,t=2,p=1)、256bit token 与 SHA-256 摘要
- internal/markdown:goldmark(默认转义)+ bluemonday 双保险,摘要纯文本提取
- internal/middleware:安全头(CSP/HSTS/nosniff 等)、错误日志、
  有界令牌桶限流(per-IP 桶上限 + TTL 逐出)、Origin/Referer 同源校验
This commit is contained in:
2026-09-08 08:14:12 +08:00
parent 685f628e26
commit 247e88c4fb
17 changed files with 1786 additions and 0 deletions
+54
View File
@@ -0,0 +1,54 @@
package auth
import "testing"
func TestPasswordHashRoundtrip(t *testing.T) {
hash, err := HashPassword("correct-horse-12")
if err != nil {
t.Fatal(err)
}
// PHC 串格式与参数(§7.3-1)
if len(hash) < len("$argon2id$v=19$m=19456,t=2,p=1$") ||
hash[:len("$argon2id$v=19$m=19456,t=2,p=1$")] != "$argon2id$v=19$m=19456,t=2,p=1$" {
t.Errorf("PHC 前缀/参数错误: %s", hash)
}
if !VerifyPassword(hash, "correct-horse-12") {
t.Error("正确口令应通过校验")
}
if VerifyPassword(hash, "wrong-password") {
t.Error("错误口令不应通过")
}
// 盐随机:同口令两次哈希不同
hash2, _ := HashPassword("correct-horse-12")
if hash == hash2 {
t.Error("同口令两次哈希应不同(随机盐)")
}
// 非法串安全返回 false
for _, bad := range []string{"", "$argon2id$", "$bcrypt$x$y$z", "$argon2id$v=19$m=1,t=1,p=1$!!$!!"} {
if VerifyPassword(bad, "x") {
t.Errorf("非法串 %q 不应通过", bad)
}
}
}
func TestTokenAndStrength(t *testing.T) {
tok, err := NewToken()
if err != nil {
t.Fatal(err)
}
if len(tok) != 43 {
t.Errorf("256bit base64url token 应为 43 字符,实际 %d", len(tok))
}
if HashToken(tok) == tok {
t.Error("token 摘要不应等于明文")
}
if HashToken(tok) != HashToken(tok) {
t.Error("摘要应确定")
}
if err := CheckPasswordStrength("short12"); err == nil {
t.Error("弱口令应被拒绝")
}
if err := CheckPasswordStrength("strong-enough-12"); err != nil {
t.Errorf("合格口令不应被拒绝: %v", err)
}
}