2026-09-12 08:57:29 +08:00
|
|
|
package httpapi
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"data-terminal-cloud/internal/onboarding"
|
|
|
|
|
"net/http"
|
|
|
|
|
"strings"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func onboardingCustomerAuth(service *onboarding.Service, bearer, next http.Handler) http.Handler {
|
|
|
|
|
if service == nil {
|
|
|
|
|
return bearer
|
|
|
|
|
}
|
|
|
|
|
cookie := service.CustomerAuth(next)
|
2026-10-08 10:06:44 +08:00
|
|
|
operator := service.OperatorAuth(next)
|
2026-09-12 08:57:29 +08:00
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
2026-10-08 10:06:44 +08:00
|
|
|
if strings.HasPrefix(r.Header.Get("Authorization"), "Mini ") {
|
|
|
|
|
if operatorCookieRequest(r) {
|
|
|
|
|
operator.ServeHTTP(w, r)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if customerCookieRequest(r) {
|
|
|
|
|
cookie.ServeHTTP(w, r)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if r.Header.Get("Authorization") == "" && operatorCookieRequest(r) {
|
|
|
|
|
operator.ServeHTTP(w, r)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
allowed := customerCookieRequest(r)
|
2026-09-12 08:57:29 +08:00
|
|
|
if r.Header.Get("Authorization") == "" && allowed {
|
|
|
|
|
cookie.ServeHTTP(w, r)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
bearer.ServeHTTP(w, r)
|
|
|
|
|
})
|
|
|
|
|
}
|
2026-10-08 10:06:44 +08:00
|
|
|
|
|
|
|
|
func operatorCookieRequest(r *http.Request) bool {
|
|
|
|
|
path := r.URL.Path
|
|
|
|
|
if path == "/api/v1/ops" || strings.HasPrefix(path, "/api/v1/ops/") {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
if path == "/api/v1/content-models" || strings.HasPrefix(path, "/api/v1/content-models/") {
|
|
|
|
|
return r.Method != http.MethodGet || r.Header.Get("X-Login-Portal") == "operator"
|
|
|
|
|
}
|
|
|
|
|
return (path == "/api/v1/me" || path == "/api/v1/events") && r.Header.Get("X-Login-Portal") == "operator"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func customerCookieRequest(r *http.Request) bool {
|
|
|
|
|
// The portal reads the active model after loading a household. Model writes
|
|
|
|
|
// remain under the original operator authentication and authorization.
|
|
|
|
|
return customerCookiePath(r.URL.Path) || (r.Method == http.MethodGet && r.URL.Path == "/api/v1/content-models")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func customerCookiePath(path string) bool {
|
|
|
|
|
// Explicit customer resources only. Operations, provider and device protocol
|
|
|
|
|
// endpoints still require their original authentication.
|
|
|
|
|
for _, resource := range []string{"me", "households", "subjects", "devices", "device-claims", "member-invitations", "events", "conversations", "stories", "memoirs", "memories", "privacy-requests", "exports", "sharing-grants", "recording-access-grants", "media-segments", "firmware-releases", "firmware-rollouts"} {
|
|
|
|
|
root := "/api/v1/" + resource
|
|
|
|
|
if path == root || strings.HasPrefix(path, root+"/") {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|