package httpapi import ( "errors" "net/http" "data-terminal-cloud/internal/deviceauth" ) type DeviceRequestVerifier interface { Verify(*http.Request) (deviceauth.Identity, error) } func DeviceAuth(verifier DeviceRequestVerifier, next http.Handler) http.Handler { return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { identity, err := verifier.Verify(request) if err != nil { if errors.Is(err, deviceauth.ErrCredentialsMissing) || errors.Is(err, deviceauth.ErrCredentialInvalid) || errors.Is(err, deviceauth.ErrDeviceInactive) || errors.Is(err, deviceauth.ErrRequestExpired) || errors.Is(err, deviceauth.ErrReplayDetected) { WriteError(writer, request, http.StatusUnauthorized, "DEVICE_AUTHENTICATION_FAILED", "设备身份验证失败") return } WriteAPIError(writer, request, http.StatusServiceUnavailable, Error{ Code: "DEVICE_AUTHENTICATION_UNAVAILABLE", Message: "设备身份服务暂时不可用", Retryable: true, }) return } next.ServeHTTP(writer, request.WithContext(deviceauth.WithIdentity(request.Context(), identity))) }) } func RequireDeviceActivation(allowed []string, next http.Handler) http.Handler { allowedSet := make(map[string]struct{}, len(allowed)) for _, state := range allowed { allowedSet[state] = struct{}{} } return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { identity, ok := deviceauth.FromContext(r.Context()) if !ok { WriteError(w, r, http.StatusUnauthorized, "DEVICE_AUTHENTICATION_FAILED", "设备身份验证失败") return } state := identity.ActivationState if state == "" { state = "ACTIVE" } if _, ok := allowedSet[state]; !ok { WriteAPIError(w, r, http.StatusConflict, Error{Code: "DEVICE_ACTIVATION_REQUIRED", Message: "当前设备激活状态不能执行该操作", Details: map[string]any{"activation_state": state, "allowed_states": allowed}}) return } next.ServeHTTP(w, r) }) } func RequireHardwareLicense(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { identity, ok := deviceauth.FromContext(r.Context()) if !ok { WriteError(w, r, http.StatusUnauthorized, "DEVICE_AUTHENTICATION_FAILED", "设备身份验证失败") return } if identity.VoiceRuntime == "volc_hardware_agent" && !identity.HardwareLicenseReady { WriteError(w, r, http.StatusConflict, "HARDWARE_LICENSE_REQUIRED", "设备没有已激活且未到期的硬件智能体License") return } next.ServeHTTP(w, r) }) }