补齐手机动态码版本接口并自动核对前端路由
This commit is contained in:
parent
a47f50c04e
commit
f9d1a858d1
@ -32,6 +32,7 @@ func registerV1Routes(mux *http.ServeMux) {
|
||||
registerV1MethodRoute(mux, "/api/v1/security/recovery/verify", "/api/security/recovery/verify", http.MethodPost, 16<<10, controllers.VerifyPasswordRecovery)
|
||||
registerV1MethodRoute(mux, "/api/v1/security/recovery/complete", "/api/security/recovery/complete", http.MethodPost, 16<<10, controllers.CompletePasswordRecovery)
|
||||
registerV1CredentialsQuestionRoute(mux)
|
||||
registerV1TOTPRoute(mux)
|
||||
registerV1MethodRoute(mux, "/api/v1/security/credentials/recovery-codes", "/api/security/credentials/recovery-codes", http.MethodGet, 0, controllers.GetRecoveryCodeStatus)
|
||||
registerV1MethodRoute(mux, "/api/v1/security/credentials/recovery-codes/generate", "/api/security/credentials/recovery-codes/generate", http.MethodPost, 16<<10, controllers.GenerateRecoveryCodes)
|
||||
registerV1MethodRoute(mux, "/api/v1/security/credentials/recovery-codes/revoke", "/api/security/credentials/recovery-codes/revoke", http.MethodPost, 4<<10, controllers.RevokeRecoveryCodes)
|
||||
@ -133,6 +134,19 @@ func registerV1CredentialsQuestionRoute(mux *http.ServeMux) {
|
||||
})
|
||||
}
|
||||
|
||||
func registerV1TOTPRoute(mux *http.ServeMux) {
|
||||
handler := limitBody(4<<10, contextIterceptor(rewriteV1Path("/api/security/totp", controllers.TOTPSettings)))
|
||||
mux.HandleFunc("/api/v1/security/totp", func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.Method {
|
||||
case http.MethodGet, http.MethodPost:
|
||||
handler.ServeHTTP(w, r)
|
||||
default:
|
||||
w.Header().Set("Allow", "GET, POST")
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func registerV1PluginRoutes(mux *http.ServeMux) {
|
||||
getUserSettings := contextIterceptor(controllers.GetTelegramUserSettings)
|
||||
updateUserSettings := limitBody(16<<10, contextIterceptor(controllers.UpdateTelegramUserSettings))
|
||||
|
||||
@ -1,8 +1,12 @@
|
||||
package http_server
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"git.pcux.cn/xuans/Smail/config"
|
||||
@ -201,6 +205,7 @@ func TestFrontendV1RoutesAreRegistered(t *testing.T) {
|
||||
"/api/v1/security/login/resend",
|
||||
"/api/v1/security/login/status",
|
||||
"/api/v1/security/login/verify",
|
||||
"/api/v1/security/totp",
|
||||
"/api/v1/security/recovery/begin",
|
||||
"/api/v1/security/recovery/complete",
|
||||
"/api/v1/security/recovery/verify",
|
||||
@ -235,3 +240,72 @@ func TestFrontendV1RoutesAreRegistered(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFrontendSourceV1RoutesAreRegistered(t *testing.T) {
|
||||
mux := http.NewServeMux()
|
||||
setupMux := http.NewServeMux()
|
||||
registerSetupAPIRoutes(setupMux, withSetupSecurity(t, "0123456789abcdefghijklmnop"), func(http.ResponseWriter, *http.Request) {})
|
||||
if err := router(mux); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pattern := regexp.MustCompile("[\x22\x27\x60](/api/v1/[a-zA-Z0-9_/-]+)[\x22\x27\x60]")
|
||||
count := 0
|
||||
err := filepath.WalkDir("../../../frontend/src", func(path string, entry fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if entry.IsDir() || (filepath.Ext(path) != ".js" && filepath.Ext(path) != ".vue" && filepath.Ext(path) != ".mjs") {
|
||||
return nil
|
||||
}
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, match := range pattern.FindAllSubmatch(content, -1) {
|
||||
endpoint := string(match[1])
|
||||
_, route := mux.Handler(httptest.NewRequest(http.MethodGet, endpoint, nil))
|
||||
if endpoint == "/api/v1/setup" {
|
||||
_, route = setupMux.Handler(httptest.NewRequest(http.MethodGet, endpoint, nil))
|
||||
}
|
||||
if route == "" || route == "/" {
|
||||
t.Errorf("%s: endpoint %s is not registered", path, endpoint)
|
||||
}
|
||||
count++
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if count == 0 {
|
||||
t.Fatal("no frontend API calls inspected")
|
||||
}
|
||||
}
|
||||
|
||||
func TestV1TOTPRouteMethods(t *testing.T) {
|
||||
oldInit := config.IsInit
|
||||
t.Cleanup(func() { config.SetInitState(oldInit) })
|
||||
config.SetInitState(false)
|
||||
mux := http.NewServeMux()
|
||||
registerV1TOTPRoute(mux)
|
||||
for _, method := range []string{http.MethodGet, http.MethodPost, http.MethodDelete, http.MethodPut} {
|
||||
recorder := httptest.NewRecorder()
|
||||
mux.ServeHTTP(recorder, httptest.NewRequest(method, "/api/v1/security/totp", nil))
|
||||
want := http.StatusOK
|
||||
if method == http.MethodDelete || method == http.MethodPut {
|
||||
want = http.StatusMethodNotAllowed
|
||||
if recorder.Header().Get("Allow") != "GET, POST" {
|
||||
t.Fatal("incorrect allowed methods")
|
||||
}
|
||||
}
|
||||
if recorder.Code != want {
|
||||
t.Errorf("%s returned %d, want %d", method, recorder.Code, want)
|
||||
}
|
||||
if recorder.Header().Get("Deprecation") != "" {
|
||||
t.Fatal("versioned TOTP route marked as legacy")
|
||||
}
|
||||
}
|
||||
if publicSecurityPath("/api/v1/security/totp") {
|
||||
t.Fatal("TOTP settings must require a session")
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user