Files
orbit/internal/transport/httpserver/console_applications.go

141 lines
4.3 KiB
Go
Raw 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 httpserver
import (
"net/http"
"net/url"
"strings"
"git.yuntuo.hk/k2safe/orbit/internal/consoleauth"
"git.yuntuo.hk/k2safe/orbit/internal/fault"
core "git.yuntuo.hk/k2safe/orbit/model"
"git.yuntuo.hk/k2safe/orbit/platform/auth"
)
// RegisterConsoleApplications 只接受登录 Cookie;业务 Bearer 不能访问跨应用管理。
func RegisterConsoleApplications(server *http.Server, consoleAuth consoleauth.Store, store consoleauth.Applications) {
if server == nil || consoleAuth == nil || store == nil {
return
}
mux, ok := server.Handler.(*http.ServeMux)
if !ok {
return
}
check := func(w http.ResponseWriter, r *http.Request) (auth.Token, bool) {
w.Header().Set("Cache-Control", "no-store")
w.Header().Set("X-Content-Type-Options", "nosniff")
token, ok := consoleCookieToken(r)
if !ok || consoleAuth.ValidateSession(r.Context(), token) != nil {
writeError(w, "", fault.Unauthorized)
return auth.Token{}, false
}
// 自定义请求头触发跨域预检;不开放 CORS,另校验浏览器 Origin 和 Fetch Metadata。
if r.Method != "GET" {
if r.Header.Get("X-Orbit-Console") != "1" || r.Header.Get("Sec-Fetch-Site") == "cross-site" {
writeError(w, "", fault.Forbidden)
return auth.Token{}, false
}
if origin := r.Header.Get("Origin"); origin != "" {
u, err := url.Parse(origin)
if err != nil || (u.Scheme != "http" && u.Scheme != "https") || !strings.EqualFold(u.Host, r.Host) || u.User != nil {
writeError(w, "", fault.Forbidden)
return auth.Token{}, false
}
}
}
return token, true
}
if auditor, ok := store.(consoleauth.LoginAuditor); ok {
mux.HandleFunc("GET /console/auth/audit", func(w http.ResponseWriter, r *http.Request) {
token, ok := check(w, r)
if !ok {
return
}
out, err := auditor.ListLoginAudit(r.Context(), token, r.URL.Query().Get("before"))
if err != nil {
writeError(w, "", err)
return
}
writeConsoleJSON(w, 200, map[string]any{"data": out})
})
}
mux.HandleFunc("GET /console/applications", func(w http.ResponseWriter, r *http.Request) {
token, ok := check(w, r)
if !ok {
return
}
out, err := store.ListApplications(r.Context(), token, core.ID(r.URL.Query().Get("after")))
if err != nil {
writeError(w, "", err)
return
}
writeConsoleJSON(w, 200, map[string]any{"data": out})
})
mux.HandleFunc("GET /console/applications/{namespace}", func(w http.ResponseWriter, r *http.Request) {
token, ok := check(w, r)
if !ok {
return
}
out, err := store.GetApplication(r.Context(), token, core.ID(r.PathValue("namespace")))
if err != nil {
writeError(w, "", err)
return
}
writeConsoleJSON(w, 200, map[string]any{"data": out})
})
mux.HandleFunc("POST /console/applications/prepare", func(w http.ResponseWriter, r *http.Request) {
token, ok := check(w, r)
if !ok {
return
}
var in consoleauth.ApplicationInput
if err := decodeBody(r, &in); err != nil {
writeError(w, "", err)
return
}
out, err := store.PrepareApplication(r.Context(), token, in)
if err != nil {
writeError(w, "", err)
return
}
writeConsoleJSON(w, 200, map[string]any{"data": out})
})
mux.HandleFunc("POST /console/applications/apply", func(w http.ResponseWriter, r *http.Request) {
token, ok := check(w, r)
if !ok {
return
}
var in consoleauth.ApplicationOperation
if err := decodeBody(r, &in); err != nil {
writeError(w, "", err)
return
}
out, err := store.ApplyApplication(r.Context(), token, in)
if err != nil {
writeError(w, "", err)
return
}
writeConsoleJSON(w, 200, map[string]any{"data": out})
})
if secrets, ok := store.(consoleauth.CredentialTokens); ok {
for _, action := range []string{"reveal", "import"} {
mux.HandleFunc("POST /console/applications/{namespace}/credentials/{credential}/token/"+action, func(w http.ResponseWriter, r *http.Request) {
token, ok := check(w, r)
if !ok {
return
}
var in consoleauth.CredentialTokenInput
if err := decodeBody(r, &in); err != nil {
writeError(w, "", err)
return
}
out, err := secrets.AccessCredentialToken(r.Context(), token, core.ID(r.PathValue("namespace")), core.ID(r.PathValue("credential")), in, action == "import")
if err != nil {
writeError(w, "", err)
return
}
writeConsoleJSON(w, 200, map[string]any{"data": out})
})
}
}
}