- 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 同源校验
71 lines
1.9 KiB
Go
71 lines
1.9 KiB
Go
package store
|
|
|
|
import (
|
|
"database/sql"
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
// Settings 键白名单(§7.1 SettingsDTO 同源;admin_password_hash 永不进入 API 响应)。
|
|
const (
|
|
KeyAdminPasswordHash = "admin_password_hash"
|
|
KeySiteTitle = "site_title"
|
|
KeySiteDesc = "site_desc"
|
|
KeyPageSize = "page_size"
|
|
)
|
|
|
|
// GetSetting 读取单个设置。
|
|
func (s *Store) GetSetting(key string) (string, bool, error) {
|
|
var v string
|
|
err := s.db.QueryRow(`SELECT value FROM settings WHERE key=?`, key).Scan(&v)
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return "", false, nil
|
|
}
|
|
return v, err == nil, err
|
|
}
|
|
|
|
// SetSetting 写入单个设置(INSERT OR REPLACE)。
|
|
func (s *Store) SetSetting(key, value string) error {
|
|
_, err := s.db.Exec(`INSERT INTO settings (key, value) VALUES (?, ?)
|
|
ON CONFLICT(key) DO UPDATE SET value=excluded.value`, key, value)
|
|
return err
|
|
}
|
|
|
|
// SiteSettings 对外的站点设置白名单视图。
|
|
type SiteSettings struct {
|
|
SiteTitle string `json:"site_title"`
|
|
SiteDesc string `json:"site_desc"`
|
|
PageSize int `json:"page_size"`
|
|
}
|
|
|
|
// Defaults,未初始化时兜底。
|
|
const (
|
|
DefaultSiteTitle = "Pure Note"
|
|
DefaultSiteDesc = ""
|
|
DefaultPageSize = 10
|
|
)
|
|
|
|
// GetSiteSettings 读取站点设置(白名单三键,带默认值)。
|
|
func (s *Store) GetSiteSettings() (*SiteSettings, error) {
|
|
ss := &SiteSettings{SiteTitle: DefaultSiteTitle, SiteDesc: DefaultSiteDesc, PageSize: DefaultPageSize}
|
|
if v, ok, err := s.GetSetting(KeySiteTitle); err != nil {
|
|
return nil, err
|
|
} else if ok && v != "" {
|
|
ss.SiteTitle = v
|
|
}
|
|
if v, ok, err := s.GetSetting(KeySiteDesc); err != nil {
|
|
return nil, err
|
|
} else if ok {
|
|
ss.SiteDesc = v
|
|
}
|
|
if v, ok, err := s.GetSetting(KeyPageSize); err != nil {
|
|
return nil, err
|
|
} else if ok {
|
|
var n int
|
|
if _, err := fmt.Sscanf(v, "%d", &n); err == nil && n >= 1 && n <= 100 {
|
|
ss.PageSize = n
|
|
}
|
|
}
|
|
return ss, nil
|
|
}
|