127 lines
3.9 KiB
Go
127 lines
3.9 KiB
Go
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
|
||
}
|
||
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})
|
||
})
|
||
}
|
||
}
|
||
}
|