mirror of
https://github.com/DeBrosOfficial/orama.git
synced 2026-03-17 10:26:57 +00:00
121 lines
3.5 KiB
Go
121 lines
3.5 KiB
Go
package auth
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"strings"
|
|
|
|
authsvc "github.com/DeBrosOfficial/network/pkg/gateway/auth"
|
|
)
|
|
|
|
// WhoamiHandler returns the authenticated user's identity and method.
|
|
// This endpoint shows whether the request is authenticated via JWT or API key,
|
|
// and provides details about the authenticated principal.
|
|
//
|
|
// GET /v1/auth/whoami
|
|
// Response: { "authenticated", "method", "subject", "namespace", ... }
|
|
func (h *Handlers) WhoamiHandler(w http.ResponseWriter, r *http.Request) {
|
|
ctx := r.Context()
|
|
// Determine namespace (may be overridden by auth layer)
|
|
ns := h.defaultNS
|
|
if v := ctx.Value(CtxKeyNamespaceOverride); v != nil {
|
|
if s, ok := v.(string); ok && s != "" {
|
|
ns = s
|
|
}
|
|
}
|
|
|
|
// Prefer JWT if present
|
|
if v := ctx.Value(CtxKeyJWT); v != nil {
|
|
if claims, ok := v.(*authsvc.JWTClaims); ok && claims != nil {
|
|
writeJSON(w, http.StatusOK, map[string]any{
|
|
"authenticated": true,
|
|
"method": "jwt",
|
|
"subject": claims.Sub,
|
|
"issuer": claims.Iss,
|
|
"audience": claims.Aud,
|
|
"issued_at": claims.Iat,
|
|
"not_before": claims.Nbf,
|
|
"expires_at": claims.Exp,
|
|
"namespace": ns,
|
|
})
|
|
return
|
|
}
|
|
}
|
|
|
|
// Fallback: API key identity
|
|
var key string
|
|
if v := ctx.Value(CtxKeyAPIKey); v != nil {
|
|
if s, ok := v.(string); ok {
|
|
key = s
|
|
}
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]any{
|
|
"authenticated": key != "",
|
|
"method": "api_key",
|
|
"api_key": key,
|
|
"namespace": ns,
|
|
})
|
|
}
|
|
|
|
// RegisterHandler registers a new application/client after wallet signature verification.
|
|
// This allows wallets to register applications and obtain client credentials.
|
|
//
|
|
// POST /v1/auth/register
|
|
// Request body: RegisterRequest
|
|
// Response: { "client_id", "app": { ... }, "signature_verified" }
|
|
func (h *Handlers) RegisterHandler(w http.ResponseWriter, r *http.Request) {
|
|
if h.authService == nil {
|
|
writeError(w, http.StatusServiceUnavailable, "auth service not initialized")
|
|
return
|
|
}
|
|
if r.Method != http.MethodPost {
|
|
writeError(w, http.StatusMethodNotAllowed, "method not allowed")
|
|
return
|
|
}
|
|
|
|
r.Body = http.MaxBytesReader(w, r.Body, 64*1024) // 64KB
|
|
var req RegisterRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeError(w, http.StatusBadRequest, "invalid json body")
|
|
return
|
|
}
|
|
if strings.TrimSpace(req.Wallet) == "" || strings.TrimSpace(req.Nonce) == "" || strings.TrimSpace(req.Signature) == "" {
|
|
writeError(w, http.StatusBadRequest, "wallet, nonce and signature are required")
|
|
return
|
|
}
|
|
|
|
ctx := r.Context()
|
|
verified, err := h.authService.VerifySignature(ctx, req.Wallet, req.Nonce, req.Signature, req.ChainType)
|
|
if err != nil || !verified {
|
|
writeError(w, http.StatusUnauthorized, "signature verification failed")
|
|
return
|
|
}
|
|
|
|
// Mark nonce used
|
|
nsID, _ := h.resolveNamespace(ctx, req.Namespace)
|
|
h.markNonceUsed(ctx, nsID, strings.ToLower(req.Wallet), req.Nonce)
|
|
|
|
// In a real app we'd derive the public key from the signature, but for simplicity here
|
|
// we just use a placeholder or expect it in the request if needed.
|
|
// For Ethereum, we can recover it.
|
|
publicKey := "recovered-pk"
|
|
|
|
appID, err := h.authService.RegisterApp(ctx, req.Wallet, req.Namespace, req.Name, publicKey)
|
|
if err != nil {
|
|
writeError(w, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
|
|
writeJSON(w, http.StatusCreated, map[string]any{
|
|
"client_id": appID,
|
|
"app": map[string]any{
|
|
"app_id": appID,
|
|
"name": req.Name,
|
|
"namespace": req.Namespace,
|
|
"wallet": strings.ToLower(req.Wallet),
|
|
},
|
|
"signature_verified": true,
|
|
})
|
|
}
|
|
|