审计修复:后端(安全 / 数据一致性 / 性能)
audit-2026-09-21.md 里的后端条目落地。每条都配了回归守卫,并逐条做过变异验证 (注入原 bug → 确认按正确理由变红 → 还原 → 变绿)。 安全 - CSRF 只加同源 Origin/Referer 守卫(csrf.go),不动模板 - 会话 cookie 的 Secure 按请求判断;两步验证两闸(loginGuard + 验证码一次性) - 跳转收口到 safeInternalPath;clientIP 只认 XFF 最后一段 - GPX 按属主圈定且查 RowsAffected;下载名走 downloadDisposition - 上传口统一 MaxBytesReader;落盘后的失败路径清掉半成品 数据一致性 - 区域判定两端各过一遍再 AND(apiTrack 与 movementsWhere 对齐) - Filter.Verdict 全域一致(下推到 visitsWhere);聚合刷新必须返回 error - 附属数据改挂坐标键,Go 与 SQL 两套表达式逐位一致 - 脏备份的伪时间/越界坐标不再进领域模型;rows 循环统一 drainRows - 合并与导出:writeRawRow 上抛错误、悬空引用清理、原生列补全 性能 - placeCols 相关子查询带 dataset_id 前导列;findSourceArchive 先按大小筛 - 批量勾选改 ANY($3::bigint[]);fillupCache 加上限;同一查询不再查两遍 另:新增「全新库」冒烟测试 —— 空库跑完 Migrate 再用应用侧读查询真打一遍, 迁移块排到依赖表之前这种错只有新库会炸,老库毫无症状。
This commit is contained in:
+17
-8
@@ -16,6 +16,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"rond-with-you/internal/fog"
|
||||
@@ -26,22 +27,27 @@ const maxFogUploadBytes = 64 << 20 // .fwss 快照一般几 MB,放宽到 64MB
|
||||
|
||||
// 迷雾是站点级数据(与公开页读数据不区分归属的约定一致),
|
||||
// 内存里只持一份索引,首次访问时从库里加载。
|
||||
//
|
||||
// 指针用 atomic 而不是普通变量:清空迷雾(fogResetIndex)会在请求 goroutine 里换掉它,
|
||||
// 而瓦片/导出/统计同时在读 —— 直接赋值就是一个真的 data race。
|
||||
var (
|
||||
fogOnce sync.Once
|
||||
fogIndexV *fog.Index
|
||||
fogIndexV atomic.Pointer[fog.Index]
|
||||
)
|
||||
|
||||
func (s *Server) fogIndex() (*fog.Index, error) {
|
||||
fogOnce.Do(func() {
|
||||
fogIndexV = fog.NewIndex()
|
||||
if err := fogIndexV.LoadAll(s.db); err != nil {
|
||||
fogIndexV = nil
|
||||
ix := fog.NewIndex()
|
||||
// 加载完才发布:中途的实例不能被别的 goroutine 看到(这也是Once的意义)
|
||||
if err := ix.LoadAll(s.db); err == nil {
|
||||
fogIndexV.Store(ix)
|
||||
}
|
||||
})
|
||||
if fogIndexV == nil {
|
||||
ix := fogIndexV.Load()
|
||||
if ix == nil {
|
||||
return nil, fmt.Errorf("迷雾数据加载失败")
|
||||
}
|
||||
return fogIndexV, nil
|
||||
return ix, nil
|
||||
}
|
||||
|
||||
// handleFogTile 渲染迷雾透明瓦片。迷雾网格是 WGS-84;当前激活底图若是
|
||||
@@ -441,8 +447,11 @@ func (s *Server) fogCoverage(ctx context.Context, datasetID int64, regions []str
|
||||
|
||||
// fogResetIndex 丢弃内存里的迷雾索引(清空迷雾后调用),
|
||||
// 下次访问时按空库重建。
|
||||
//
|
||||
// 被清掉的那个索引对象可能还有请求正拿着用(Import/View/All 都走它自己的锁),
|
||||
// 这里只换指针、不动旧对象,那些请求会安全地跑完。
|
||||
func fogResetIndex() {
|
||||
fogIndexV = fog.NewIndex()
|
||||
fogIndexV.Store(fog.NewIndex())
|
||||
}
|
||||
|
||||
// adminFogClear 清空全部迷雾数据。迷雾是站点级数据,一次清空影响所有展示。
|
||||
@@ -483,7 +492,7 @@ func (s *Server) adminFogExport(w http.ResponseWriter, r *http.Request) {
|
||||
_, cells := ix.Stats()
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
w.Header().Set("Content-Disposition",
|
||||
fmt.Sprintf(`attachment; filename="fog-export-%s.fwss"`, time.Now().Format("20060102-150405")))
|
||||
downloadDisposition("fog-export-"+time.Now().Format("20060102-150405")+".fwss"))
|
||||
w.Header().Set("X-Fog-Cells", strconv.Itoa(cells))
|
||||
w.Write(out)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user