Scert/backend/internal/httpapi/password_reset_guidance_test.go
xuans 6f702cdc36 完成公网密码重置安全阻断
关闭公开密码重置流程,统一显示运维协助提示,保留本机受保护重置方向,并更新前端回归测试与整改清单。
2026-10-04 13:01:52 +08:00

78 lines
3.2 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package httpapi
import (
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func TestPublicPasswordResetGuidanceDoesNotEnumerateAccounts(t *testing.T) {
cfg := readyTestConfig(t.TempDir())
cfg.Admin.Username = "owner"
cfg.Admin.Email = "owner@example.test"
server := New(Dependencies{Config: cfg})
var baseline string
for _, identifier := range []string{"owner", "owner@example.test", "OWNER", "OWNER@EXAMPLE.TEST", "not-an-account", "absent@example.test", " owner "} {
t.Run(identifier, func(t *testing.T) {
body, err := json.Marshal(map[string]string{"identifier": identifier})
if err != nil {
t.Fatal(err)
}
request := httptest.NewRequest(http.MethodPost, "/api/v1/password-reset/resolve", strings.NewReader(string(body)))
request.Header.Set("Content-Type", "application/json")
response := httptest.NewRecorder()
server.Handler().ServeHTTP(response, request)
if response.Code != http.StatusOK {
t.Fatalf("公开查询应返回通用成功响应:%d %s", response.Code, response.Body.String())
}
if baseline == "" {
baseline = response.Body.String()
} else if response.Body.String() != baseline {
t.Fatalf("不同合法标识不得产生可区分的响应:%s", response.Body.String())
}
var payload map[string]any
if err := json.Unmarshal(response.Body.Bytes(), &payload); err != nil {
t.Fatal(err)
}
if len(payload) != 3 || payload["action"] != "contact_administrator" || payload["title"] != "密码重置" || payload["description"] != "当前方式无法使用,请联系运维人员辅助解决。" {
t.Fatalf("公开响应必须仅包含通用处理提示:%v", payload)
}
if response.Header().Get("Cache-Control") != "no-store" {
t.Fatal("密码处理提示不得被缓存")
}
if len(response.Result().Cookies()) != 0 || len(server.authSessions) != 0 || len(server.loginPending) != 0 {
t.Fatal("公开查询不得创建会话或登录状态")
}
})
}
}
func TestPublicPasswordResetGuidancePreservesInputBoundary(t *testing.T) {
for _, ready := range []bool{false, true} {
cfg := readyTestConfig(t.TempDir())
cfg.SetupReady = ready
server := New(Dependencies{Config: cfg})
for _, body := range []string{`{}`, `{"identifier":""}`, `{"identifier":17}`, `{"identifier":"owner","unexpected":true}`, `{"identifier":"owner"}{"identifier":"owner"}`, `{"identifier":"` + strings.Repeat("a", passwordResetResolveBodyLimit) + `"}`} {
request := httptest.NewRequest(http.MethodPost, "/api/v1/password-reset/resolve", strings.NewReader(body))
request.Header.Set("Content-Type", "application/json")
response := httptest.NewRecorder()
server.Handler().ServeHTTP(response, request)
if response.Code != http.StatusBadRequest {
t.Fatalf("无效请求必须被拒绝:ready=%t status=%d", ready, response.Code)
}
}
request := httptest.NewRequest(http.MethodPost, "/api/v1/password-reset/resolve", strings.NewReader(`{"identifier":"owner"}`))
response := httptest.NewRecorder()
server.Handler().ServeHTTP(response, request)
want := http.StatusOK
if !ready {
want = http.StatusConflict
}
if response.Code != want {
t.Fatalf("初始化边界不正确:ready=%t status=%d", ready, response.Code)
}
}
}