package server import ( "encoding/base64" "net/mail" "strings" "galaxy/backend/internal/auth" ) // ed25519PublicKeyLen is the fixed size of a raw Ed25519 public key. The // OpenAPI contract documents `client_public_key` as a "Standard // base64-encoded raw 32-byte Ed25519 public key"; the handler enforces // the length after decode so the auth service always operates on the // canonical shape. const ed25519PublicKeyLen = 32 // deviceSessionPayload is the JSON body the internal session endpoints // emit. It mirrors the `DeviceSession` schema in `openapi.yaml`. type deviceSessionPayload struct { DeviceSessionID string `json:"device_session_id"` UserID string `json:"user_id"` Status string `json:"status"` ClientPublicKey string `json:"client_public_key,omitempty"` CreatedAt string `json:"created_at"` RevokedAt *string `json:"revoked_at,omitempty"` LastSeenAt *string `json:"last_seen_at,omitempty"` } func deviceSessionToWire(s auth.Session) deviceSessionPayload { out := deviceSessionPayload{ DeviceSessionID: s.DeviceSessionID.String(), UserID: s.UserID.String(), Status: s.Status, CreatedAt: s.CreatedAt.UTC().Format("2006-01-02T15:04:05.000Z07:00"), } if len(s.ClientPublicKey) > 0 { out.ClientPublicKey = base64.StdEncoding.EncodeToString(s.ClientPublicKey) } if s.RevokedAt != nil { formatted := s.RevokedAt.UTC().Format("2006-01-02T15:04:05.000Z07:00") out.RevokedAt = &formatted } if s.LastSeenAt != nil { formatted := s.LastSeenAt.UTC().Format("2006-01-02T15:04:05.000Z07:00") out.LastSeenAt = &formatted } return out } // validateEmail returns the trimmed value when raw parses as an // addr-spec, or "" when raw is malformed. Auth normalises to lowercase // internally; the handler only enforces the syntactic shape. func validateEmail(raw string) string { addr, err := mail.ParseAddress(strings.TrimSpace(raw)) if err != nil { return "" } return addr.Address } // decodeClientPublicKey decodes the wire-format client_public_key into // raw bytes and validates the length. Standard base64 (with padding) is // the canonical encoding documented in `openapi.yaml`. func decodeClientPublicKey(raw string) ([]byte, bool) { decoded, err := base64.StdEncoding.DecodeString(strings.TrimSpace(raw)) if err != nil { return nil, false } if len(decoded) != ed25519PublicKeyLen { return nil, false } return decoded, true } // isDecimalCodeOfLength reports whether s is a string of exactly want // ASCII digits. func isDecimalCodeOfLength(s string, want int) bool { if len(s) != want { return false } for i := 0; i < len(s); i++ { if s[i] < '0' || s[i] > '9' { return false } } return true }