package question import ( "net/http" "testing" "github.com/tamakyi/TamaBox/internal/context" "github.com/tamakyi/TamaBox/internal/db" ) // stubSession 只实现 pagePasswordAuthorized 用得到的 Get/Set,其余方法给空实现。 type stubSession struct { data map[interface{}]interface{} } func newStubSession() *stubSession { return &stubSession{data: map[interface{}]interface{}{}} } func (s *stubSession) ID() string { return "test-session" } func (s *stubSession) RegenerateID(http.ResponseWriter, *http.Request) error { return nil } func (s *stubSession) Get(key interface{}) interface{} { return s.data[key] } func (s *stubSession) Set(key, val interface{}) { s.data[key] = val } func (s *stubSession) SetFlash(val interface{}) {} func (s *stubSession) Delete(key interface{}) { delete(s.data, key) } func (s *stubSession) Flush() { s.data = map[interface{}]interface{}{} } func (s *stubSession) Encode() ([]byte, error) { return nil, nil } func (s *stubSession) HasChanged() bool { return false } // TestPagePasswordAuthorized 是 2026-11-05 P0 的回归用例。 // // 旧实现 `ver, _ := Session.Get(key).(uint); if ver != user.PagePasswordVer` // 把「session 里没有授权记录」(断言失败 → 0)与「版本号默认值 0」判成相等, // 于是升级瞬间所有存量页面密码失效——匿名访客不带任何 cookie 就能看箱主页。 // 这里把「无 key + ver=0」钉成必须拒绝。 func TestPagePasswordAuthorized(t *testing.T) { const userID = 7 cases := []struct { name string pagePassword string pageVer uint sessionFill func(*stubSession) // 预置 session,nil 表示完全没有授权键 logged bool viewerID uint want bool }{ { name: "未设页面密码时直接放行", pagePassword: "", pageVer: 0, want: true, }, { name: "存量账号 ver=0 且 session 无授权键必须拒绝", pagePassword: "hashed", pageVer: 0, want: false, }, { name: "升级前留下的布尔授权(类型不符)作废", pagePassword: "hashed", pageVer: 0, sessionFill: func(s *stubSession) { s.Set(pagePassKey(userID), true) }, want: false, }, { name: "版本号一致的授权通过", pagePassword: "hashed", pageVer: 1, sessionFill: func(s *stubSession) { s.Set(pagePassKey(userID), uint(1)) }, want: true, }, { name: "改过密码后旧版本授权失效", pagePassword: "hashed", pageVer: 2, sessionFill: func(s *stubSession) { s.Set(pagePassKey(userID), uint(1)) }, want: false, }, { name: "session 里是别的类型(如字符串)一律拒绝", pagePassword: "hashed", pageVer: 1, sessionFill: func(s *stubSession) { s.Set(pagePassKey(userID), "1") }, want: false, }, { name: "箱主本人不受页面密码限制", pagePassword: "hashed", pageVer: 9, logged: true, viewerID: userID, want: true, }, { name: "其他登录用户仍需通过密码", pagePassword: "hashed", pageVer: 9, logged: true, viewerID: userID + 1, want: false, }, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { session := newStubSession() if c.sessionFill != nil { c.sessionFill(session) } ctx := context.Context{ Session: session, IsLogged: c.logged, User: &db.User{ID: c.viewerID}, } owner := &db.User{ID: userID, PagePassword: c.pagePassword, PagePasswordVer: c.pageVer} if got := pagePasswordAuthorized(ctx, owner); got != c.want { t.Fatalf("pagePasswordAuthorized() = %v, want %v", got, c.want) } }) } }