审计修复:后端(安全 / 数据一致性 / 性能)
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:
@@ -97,8 +97,9 @@ func (s *Server) pageBase(r *http.Request, nav, title string) (Page, error) {
|
||||
p.FilterBase = r.URL.Path
|
||||
p.Presets = buildPresets(p.From, p.To)
|
||||
// 「回到哪」的两个参数:Back 是别人挂给我们的(详情页/编辑页的返回按钮用),
|
||||
// BackQS 是把自己挂给别人的(列表页生成详情链接用)。
|
||||
// BackQS 是把自己挂给别人的(列表页生成详情链接用),SelfPath 是它的未编码原文。
|
||||
p.Back = backFromRequest(r)
|
||||
p.SelfPath = selfPath(r)
|
||||
p.BackQS = backQS(r)
|
||||
return p, nil
|
||||
}
|
||||
@@ -715,10 +716,6 @@ func (s *Server) statsPage(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if d.Weekday, err = s.q.Weekday(ctx, f); err != nil {
|
||||
s.serverError(w, r, err)
|
||||
return
|
||||
}
|
||||
for _, m := range d.Monthly {
|
||||
if m.Count > d.MaxMonthly {
|
||||
d.MaxMonthly = m.Count
|
||||
@@ -1101,10 +1098,31 @@ type GPXTrack struct {
|
||||
|
||||
// apiGpx 返回已导入的 GPX 轨迹。库里存的是 WGS-84(GPX 标准),
|
||||
// 底图是 GCJ-02 时按点转成火星坐标,保证和足迹点对齐。
|
||||
//
|
||||
// 轨迹按**当前生效数据集的属主**圈定,不是把整张表端出去:gpx_tracks 带 user_id,
|
||||
// 这是公开接口、不带登录态,不按属主过滤就等于把别人的轨迹一起露给访客。
|
||||
// 没有生效数据集时返回空集——和页面其余部分「没数据就没有」的口径一致。
|
||||
func (s *Server) apiGpx(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
empty := func() {
|
||||
s.json(w, struct {
|
||||
Tracks []GPXTrack `json:"tracks"`
|
||||
}{Tracks: []GPXTrack{}})
|
||||
}
|
||||
var owner int64
|
||||
err := s.db.QueryRowContext(ctx, `SELECT user_id FROM datasets
|
||||
WHERE is_active AND status='done' ORDER BY uploaded_at DESC LIMIT 1`).Scan(&owner)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
empty()
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
s.json(w, map[string]string{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
crs := r.URL.Query().Get("crs")
|
||||
rows, err := s.db.QueryContext(r.Context(), `SELECT id, name, points, length_km, started_at
|
||||
FROM gpx_tracks ORDER BY started_at DESC NULLS LAST, id DESC`)
|
||||
rows, err := s.db.QueryContext(ctx, `SELECT id, name, points, length_km, started_at
|
||||
FROM gpx_tracks WHERE user_id=$1 ORDER BY started_at DESC NULLS LAST, id DESC`, owner)
|
||||
if err != nil {
|
||||
s.json(w, map[string]string{"error": err.Error()})
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user