feat(api): REST на chi + huma с auth-ручками и OpenAPI 3.1
- переход на chi + huma (решение D-006): huma отдаёт типизированные ручки и генерирует документ, auth-ручки живут на chi (cookie и заголовки напрямую) - единый формат ошибок: код (auth.invalid_credentials, auth.2fa_required, perm.denied и т.д.) + человекочитаемое сообщение (AGENT.md 8.5) - cookie сессии __Host-session: HttpOnly, SameSite=Lax, Secure при TLS; альтернатива — Bearer-токен для desktop/CLI (AGENT.md 8.1) - ручки: register, login, logout, logout-all, sessions, step-up, 2fa/setup, 2fa/enable, users/@me; IP и User-Agent прокидываются из запроса в контекст - /api/v1/openapi.json: объединённый документ (схемы huma + контракт auth) - тесты: регистрация через API с cookie, ошибки входа, обязательная сессия, валидация, наличие всех путей в OpenAPI
This commit is contained in:
@@ -7,31 +7,6 @@ import (
|
||||
"glchat/internal/httpx"
|
||||
)
|
||||
|
||||
// methodOfPattern splits a Go 1.22 routing pattern such as "GET /api/v1/meta"
|
||||
// into its method and path parts. Patterns without a method apply to all.
|
||||
func methodOfPattern(pattern string) (method, path string) {
|
||||
if i := strings.IndexByte(pattern, ' '); i > 0 {
|
||||
return pattern[:i], pattern[i+1:]
|
||||
}
|
||||
return "", pattern
|
||||
}
|
||||
|
||||
func (s *Server) routeExists(method, path string) bool {
|
||||
for _, pattern := range s.patterns {
|
||||
patternMethod, patternPath := methodOfPattern(pattern)
|
||||
if patternMethod == "" || patternMethod == method {
|
||||
continue
|
||||
}
|
||||
if patternPath == path {
|
||||
return true
|
||||
}
|
||||
if strings.HasSuffix(patternPath, "/") && strings.HasPrefix(path, patternPath) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// reservedPrefixes are handled by the API, the gateway or the file CDN; an
|
||||
// unknown path under them is a real 404 and must not receive the SPA shell.
|
||||
var reservedPrefixes = []string{"/api/", "/gateway", "/files/", "/rtc"}
|
||||
@@ -46,10 +21,6 @@ func isReservedPath(path string) bool {
|
||||
}
|
||||
|
||||
func (s *Server) handleFallback(w http.ResponseWriter, r *http.Request) {
|
||||
if s.routeExists(r.Method, r.URL.Path) {
|
||||
httpx.WriteErrorStatus(w, http.StatusMethodNotAllowed, httpx.CodeBadRequest, "method not allowed")
|
||||
return
|
||||
}
|
||||
if isReservedPath(r.URL.Path) {
|
||||
httpx.WriteError(w, httpx.NewError(httpx.CodeNotFound, "resource not found"))
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user