package main import ( "context" "crypto/rand" "encoding/hex" "encoding/json" "errors" "fmt" "log" "math/big" "net/http" "regexp" "strconv" "strings" "time" ) var ( reDigits = regexp.MustCompile(`^[0-9]+$`) ) type app struct { cfg Config store *store } func newApp(cfg Config, st *store) *app { return &app{cfg: cfg, store: st} } func (a *app) routes() http.Handler { mux := http.NewServeMux() mux.HandleFunc("/healthz", a.withCORS(a.handleHealth)) mux.HandleFunc("/secret/wallet/intent", a.withCORS(a.handleWalletIntent)) mux.HandleFunc("/secret/wallet/verify", a.withCORS(a.handleWalletVerify)) mux.HandleFunc("/secret/membership/quote", a.withCORS(a.handleMembershipQuote)) mux.HandleFunc("/secret/membership/confirm", a.withCORS(a.handleMembershipConfirm)) mux.HandleFunc("/secret/membership/status", a.withCORS(a.handleMembershipStatus)) mux.HandleFunc("/marketplace/offers", a.withCORS(a.handleMarketplaceOffers)) mux.HandleFunc("/marketplace/offers/", a.withCORS(a.handleMarketplaceOfferByID)) mux.HandleFunc("/marketplace/checkout/quote", a.withCORS(a.handleMarketplaceCheckoutQuote)) mux.HandleFunc("/marketplace/checkout/confirm", a.withCORS(a.handleMarketplaceCheckoutConfirm)) mux.HandleFunc("/marketplace/entitlements", a.withCORS(a.handleMarketplaceEntitlements)) mux.HandleFunc("/governance/install/token", a.withCORS(a.handleGovernanceInstallToken)) mux.HandleFunc("/governance/install/confirm", a.withCORS(a.handleGovernanceInstallConfirm)) mux.HandleFunc("/governance/install/status", a.withCORS(a.handleGovernanceInstallStatus)) mux.HandleFunc("/governance/lease/heartbeat", a.withCORS(a.handleGovernanceLeaseHeartbeat)) mux.HandleFunc("/governance/lease/offline-renew", a.withCORS(a.handleGovernanceOfflineRenew)) mux.HandleFunc("/member/channel/device/register", a.withCORS(a.handleMemberChannelDeviceRegister)) mux.HandleFunc("/member/channel/device/unregister", a.withCORS(a.handleMemberChannelDeviceUnregister)) mux.HandleFunc("/member/channel/events", a.withCORS(a.handleMemberChannelEvents)) mux.HandleFunc("/member/channel/events/", a.withCORS(a.handleMemberChannelEventAck)) mux.HandleFunc("/member/channel/support/ticket", a.withCORS(a.handleMemberChannelSupportTicket)) return mux } func (a *app) withCORS(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { origin := strings.TrimSpace(r.Header.Get("Origin")) if origin == "" { origin = a.cfg.AllowedOrigin } if a.cfg.AllowedOrigin == "*" || strings.EqualFold(origin, a.cfg.AllowedOrigin) { w.Header().Set("Access-Control-Allow-Origin", origin) w.Header().Set("Vary", "Origin") } w.Header().Set("Access-Control-Allow-Headers", "Content-Type") w.Header().Set("Access-Control-Allow-Methods", "GET,POST,OPTIONS") if r.Method == http.MethodOptions { w.WriteHeader(http.StatusNoContent) return } next(w, r) } } func (a *app) handleHealth(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { writeError(w, http.StatusMethodNotAllowed, "method not allowed") return } writeJSON(w, http.StatusOK, map[string]string{"status": "ok"}) } func (a *app) handleWalletIntent(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { writeError(w, http.StatusMethodNotAllowed, "method not allowed") return } var req walletIntentRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } address, err := normalizeAddress(req.Address) if err != nil { writeError(w, http.StatusBadRequest, err.Error()) return } if req.ChainID != a.cfg.ChainID { writeError(w, http.StatusBadRequest, fmt.Sprintf("unsupported chain_id: %d", req.ChainID)) return } intentID, err := randomHex(16) if err != nil { writeError(w, http.StatusInternalServerError, "failed to generate intent id") return } nonce, err := randomHex(16) if err != nil { writeError(w, http.StatusInternalServerError, "failed to generate nonce") return } code, displayToken, err := newDesignationCode() if err != nil { writeError(w, http.StatusInternalServerError, "failed to generate designation code") return } issuedAt := time.Now().UTC() expiresAt := issuedAt.Add(a.cfg.IntentTTL) record := designationRecord{ Code: code, DisplayToken: displayToken, IntentID: intentID, Nonce: nonce, Origin: strings.TrimSpace(req.Origin), Locale: strings.TrimSpace(req.Locale), Address: address, ChainID: req.ChainID, IssuedAt: issuedAt, ExpiresAt: expiresAt, MembershipStatus: "none", IdentityAssurance: assuranceNone, } if record.Origin == "" { record.Origin = "https://edut.ai" } if record.Locale == "" { record.Locale = "en" } if err := a.store.putDesignation(r.Context(), record); err != nil { writeError(w, http.StatusInternalServerError, "failed to persist designation intent") return } writeJSON(w, http.StatusOK, walletIntentResponse{ IntentID: intentID, DesignationCode: code, DisplayToken: displayToken, Nonce: nonce, IssuedAt: issuedAt.Format(time.RFC3339Nano), ExpiresAt: expiresAt.Format(time.RFC3339Nano), DomainName: a.cfg.DomainName, ChainID: a.cfg.ChainID, VerifyingContract: a.cfg.VerifyingContract, }) } func (a *app) handleWalletVerify(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { writeError(w, http.StatusMethodNotAllowed, "method not allowed") return } var req walletVerifyRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } address, err := normalizeAddress(req.Address) if err != nil { writeError(w, http.StatusBadRequest, err.Error()) return } if req.ChainID != a.cfg.ChainID { writeError(w, http.StatusBadRequest, fmt.Sprintf("unsupported chain_id: %d", req.ChainID)) return } rec, err := a.store.getDesignationByIntent(r.Context(), strings.TrimSpace(req.IntentID)) if err != nil { if errors.Is(err, errNotFound) { writeError(w, http.StatusNotFound, "intent not found") return } writeError(w, http.StatusInternalServerError, "failed to load intent") return } if time.Now().UTC().After(rec.ExpiresAt) { writeError(w, http.StatusBadRequest, "intent expired") return } if strings.ToLower(rec.Address) != address { writeError(w, http.StatusBadRequest, "address does not match intent") return } typedData := buildTypedData(a.cfg, rec) recovered, err := recoverSignerAddress(typedData, req.Signature) if err != nil { writeError(w, http.StatusBadRequest, fmt.Sprintf("signature verification failed: %v", err)) return } if recovered != address { writeError(w, http.StatusBadRequest, "signature signer does not match address") return } now := time.Now().UTC() rec.VerifiedAt = &now if err := a.store.putDesignation(r.Context(), rec); err != nil { writeError(w, http.StatusInternalServerError, "failed to store verification status") return } writeJSON(w, http.StatusOK, walletVerifyResponse{ Status: "signature_verified", DesignationCode: rec.Code, DisplayToken: rec.DisplayToken, VerifiedAt: now.Format(time.RFC3339Nano), }) } func (a *app) handleMembershipQuote(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { writeError(w, http.StatusMethodNotAllowed, "method not allowed") return } var req membershipQuoteRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } address, err := normalizeAddress(req.Address) if err != nil { writeError(w, http.StatusBadRequest, err.Error()) return } if req.ChainID != a.cfg.ChainID { writeError(w, http.StatusBadRequest, fmt.Sprintf("unsupported chain_id: %d", req.ChainID)) return } payerAddress := address if strings.TrimSpace(req.PayerWallet) != "" { payerAddress, err = normalizeAddress(req.PayerWallet) if err != nil { writeError(w, http.StatusBadRequest, err.Error()) return } } rec, err := a.store.getDesignationByCode(r.Context(), strings.TrimSpace(req.DesignationCode)) if err != nil { if errors.Is(err, errNotFound) { writeError(w, http.StatusNotFound, "designation not found") return } writeError(w, http.StatusInternalServerError, "failed to load designation") return } if rec.VerifiedAt == nil { writeError(w, http.StatusConflict, "designation not verified") return } if strings.ToLower(rec.Address) != address { writeError(w, http.StatusBadRequest, "address does not match designation") return } sponsorshipMode := "self" if payerAddress != address { sponsorOrgRoot := strings.TrimSpace(req.SponsorOrgRoot) if strings.TrimSpace(req.PayerProof) != "" { if err := verifyDistinctPayerProof(rec.Code, address, payerAddress, req.ChainID, req.PayerProof); err != nil { writeError(w, http.StatusForbidden, fmt.Sprintf("invalid ownership proof: %v", err)) return } sponsorshipMode = "sponsored" } else if sponsorOrgRoot != "" { payerPrincipal, principalErr := a.store.getGovernancePrincipal(r.Context(), payerAddress) if principalErr != nil { writeErrorCode(w, http.StatusForbidden, "sponsor_not_authorized", "sponsor wallet is not authorized for org root") return } if !strings.EqualFold(strings.TrimSpace(payerPrincipal.OrgRootID), sponsorOrgRoot) { writeErrorCode(w, http.StatusForbidden, "sponsor_not_authorized", "sponsor org root mismatch") return } if !strings.EqualFold(strings.TrimSpace(payerPrincipal.PrincipalRole), "org_root_owner") { writeErrorCode(w, http.StatusForbidden, "sponsor_not_authorized", "sponsor wallet requires org_root_owner role") return } if !strings.EqualFold(strings.TrimSpace(payerPrincipal.EntitlementStatus), "active") { writeErrorCode(w, http.StatusForbidden, "sponsor_not_authorized", "sponsor entitlement is not active") return } hasWorkspaceCore, entErr := a.store.hasActiveEntitlement(r.Context(), payerAddress, offerIDWorkspaceCore, sponsorOrgRoot) if entErr != nil { writeErrorCode(w, http.StatusInternalServerError, "store_error", "failed to validate sponsor entitlement") return } if !hasWorkspaceCore { writeErrorCode(w, http.StatusForbidden, "sponsor_not_authorized", "workspace core entitlement required for sponsored member onboarding") return } sponsorshipMode = "sponsored_company" } else { writeError(w, http.StatusForbidden, "distinct payer requires ownership proof") return } } quoteID, err := randomHex(16) if err != nil { writeError(w, http.StatusInternalServerError, "failed to generate quote id") return } calldata, err := encodeMintMembershipCalldata(address) if err != nil { writeError(w, http.StatusInternalServerError, "failed to encode mint calldata") return } now := time.Now().UTC() expiresAt := now.Add(a.cfg.QuoteTTL) valueHex := "0x0" if strings.EqualFold(a.cfg.MintCurrency, "ETH") { amount, ok := new(big.Int).SetString(a.cfg.MintAmountAtomic, 10) if !ok { writeError(w, http.StatusInternalServerError, "invalid mint amount configuration") return } valueHex = "0x" + amount.Text(16) } quote := quoteRecord{ QuoteID: quoteID, DesignationCode: rec.Code, Address: address, PayerAddress: payerAddress, ChainID: a.cfg.ChainID, Currency: a.cfg.MintCurrency, AmountAtomic: a.cfg.MintAmountAtomic, Decimals: a.cfg.MintDecimals, ContractAddress: strings.ToLower(a.cfg.MembershipContract), Method: "mintMembership(address)", Calldata: calldata, ValueHex: valueHex, SponsorshipMode: sponsorshipMode, SponsorOrgRootID: strings.TrimSpace(req.SponsorOrgRoot), CreatedAt: now, ExpiresAt: expiresAt, } if err := a.store.putQuote(r.Context(), quote); err != nil { writeError(w, http.StatusInternalServerError, "failed to persist quote") return } tx := map[string]any{ "from": payerAddress, "to": quote.ContractAddress, "data": quote.Calldata, "value": quote.ValueHex, } writeJSON(w, http.StatusOK, membershipQuoteResponse{ QuoteID: quote.QuoteID, ChainID: quote.ChainID, Currency: quote.Currency, AmountAtomic: quote.AmountAtomic, Decimals: quote.Decimals, Deadline: quote.ExpiresAt.Format(time.RFC3339Nano), ContractAddress: quote.ContractAddress, Method: quote.Method, Calldata: quote.Calldata, Value: quote.ValueHex, OwnerWallet: address, PayerWallet: payerAddress, SponsorshipMode: sponsorshipMode, SponsorOrgRoot: strings.TrimSpace(req.SponsorOrgRoot), Tx: tx, }) } func (a *app) handleMembershipConfirm(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { writeError(w, http.StatusMethodNotAllowed, "method not allowed") return } var req membershipConfirmRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } address, err := normalizeAddress(req.Address) if err != nil { writeError(w, http.StatusBadRequest, err.Error()) return } if req.ChainID != a.cfg.ChainID { writeError(w, http.StatusBadRequest, fmt.Sprintf("unsupported chain_id: %d", req.ChainID)) return } if !isTxHash(req.TxHash) { writeError(w, http.StatusBadRequest, "invalid tx_hash") return } quote, err := a.store.getQuote(r.Context(), strings.TrimSpace(req.QuoteID)) if err != nil { if errors.Is(err, errNotFound) { writeError(w, http.StatusNotFound, "quote not found") return } writeError(w, http.StatusInternalServerError, "failed to load quote") return } if time.Now().UTC().After(quote.ExpiresAt) { writeError(w, http.StatusConflict, "quote expired") return } if !strings.EqualFold(quote.Address, address) || !strings.EqualFold(quote.DesignationCode, req.DesignationCode) || quote.ChainID != req.ChainID { writeError(w, http.StatusBadRequest, "quote context mismatch") return } if a.cfg.RequireOnchainTxVerify && strings.TrimSpace(a.cfg.ChainRPCURL) == "" { writeErrorCode(w, http.StatusServiceUnavailable, "chain_verification_unavailable", "chain rpc required for membership confirmation") return } if err := verifyMintedOnChain(context.Background(), a.cfg, req.TxHash, address); err != nil { writeError(w, http.StatusConflict, fmt.Sprintf("tx verification pending/failed: %v", err)) return } rec, err := a.store.getDesignationByCode(r.Context(), quote.DesignationCode) if err != nil { if errors.Is(err, errNotFound) { writeError(w, http.StatusNotFound, "designation not found") return } writeError(w, http.StatusInternalServerError, "failed to load designation") return } now := time.Now().UTC() identityAssurance, identityAttestedBy, identityAttestationID, identityAttestedAt, assuranceErr := resolveMembershipAssurance(quote, req, now) if assuranceErr != nil { writeErrorCode(w, http.StatusBadRequest, "invalid_identity_assurance", assuranceErr.Error()) return } rec.MembershipStatus = "active" rec.MembershipTxHash = strings.ToLower(req.TxHash) rec.ActivatedAt = &now rec.IdentityAssurance = identityAssurance rec.IdentityAttestedBy = identityAttestedBy rec.IdentityAttestationID = identityAttestationID rec.IdentityAttestedAt = identityAttestedAt if err := a.store.putDesignation(r.Context(), rec); err != nil { writeError(w, http.StatusInternalServerError, "failed to persist membership activation") return } quote.ConfirmedAt = &now quote.ConfirmedTxHash = strings.ToLower(req.TxHash) if err := a.store.putQuote(r.Context(), quote); err != nil { writeError(w, http.StatusInternalServerError, "failed to persist quote confirmation") return } writeJSON(w, http.StatusOK, membershipConfirmResponse{ Status: "membership_active", DesignationCode: rec.Code, DisplayToken: rec.DisplayToken, TxHash: strings.ToLower(req.TxHash), ActivatedAt: now.Format(time.RFC3339Nano), IdentityAssurance: rec.IdentityAssurance, IdentityAttestedBy: rec.IdentityAttestedBy, IdentityAttestationID: rec.IdentityAttestationID, }) } func (a *app) handleMembershipStatus(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { writeError(w, http.StatusMethodNotAllowed, "method not allowed") return } wallet := strings.TrimSpace(r.URL.Query().Get("wallet")) code := strings.TrimSpace(r.URL.Query().Get("designation_code")) if wallet == "" && code == "" { writeError(w, http.StatusBadRequest, "wallet or designation_code required") return } var ( rec designationRecord err error ) if code != "" { rec, err = a.store.getDesignationByCode(r.Context(), code) } else { normalized, normalizeErr := normalizeAddress(wallet) if normalizeErr != nil { writeError(w, http.StatusBadRequest, normalizeErr.Error()) return } rec, err = a.store.getDesignationByAddress(r.Context(), normalized) } if err != nil { if errors.Is(err, errNotFound) { writeJSON(w, http.StatusOK, membershipStatusResponse{Status: "none"}) return } writeError(w, http.StatusInternalServerError, "failed to resolve membership status") return } status := strings.ToLower(strings.TrimSpace(rec.MembershipStatus)) if status == "" { status = "none" } writeJSON(w, http.StatusOK, membershipStatusResponse{ Status: status, Wallet: rec.Address, DesignationCode: rec.Code, IdentityAssurance: normalizeAssuranceLevel(rec.IdentityAssurance), IdentityAttestedBy: strings.TrimSpace(rec.IdentityAttestedBy), IdentityAttestationID: strings.TrimSpace(rec.IdentityAttestationID), }) } func (a *app) handleGovernanceInstallToken(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { writeError(w, http.StatusMethodNotAllowed, "method not allowed") return } var req governanceInstallTokenRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeErrorCode(w, http.StatusBadRequest, "invalid_request", "invalid request body") return } wallet, err := normalizeAddress(req.Wallet) if err != nil { writeErrorCode(w, http.StatusBadRequest, "invalid_wallet", err.Error()) return } if strings.TrimSpace(req.DeviceID) == "" || strings.TrimSpace(req.Platform) == "" || strings.TrimSpace(req.LauncherVersion) == "" { writeErrorCode(w, http.StatusBadRequest, "invalid_request", "device_id, platform, launcher_version required") return } rec, err := a.store.getDesignationByAddress(r.Context(), wallet) if err != nil { if errors.Is(err, errNotFound) { writeErrorCode(w, http.StatusForbidden, "membership_inactive", "membership not active") return } writeErrorCode(w, http.StatusInternalServerError, "store_error", "failed to resolve membership") return } if strings.ToLower(strings.TrimSpace(rec.MembershipStatus)) != "active" { writeErrorCode(w, http.StatusForbidden, "membership_inactive", "membership not active") return } if !isOnrampAttested(rec.IdentityAssurance) { writeErrorCode(w, http.StatusForbidden, "identity_assurance_insufficient", "workspace admin operations require onramp_attested identity assurance") return } principal, err := a.resolveOrCreatePrincipal(r.Context(), wallet, req.OrgRootID, req.PrincipalID, req.PrincipalRole) if err != nil { writeErrorCode(w, http.StatusInternalServerError, "principal_resolve_failed", err.Error()) return } if !strings.EqualFold(strings.TrimSpace(principal.PrincipalRole), "org_root_owner") { writeErrorCode(w, http.StatusForbidden, "role_insufficient", "install/update controls require org_root_owner") return } if strings.ToLower(strings.TrimSpace(principal.EntitlementStatus)) != "active" { writeErrorCode(w, http.StatusForbidden, "entitlement_inactive", "governance entitlement inactive") return } if strings.ToLower(strings.TrimSpace(principal.AvailabilityState)) == "parked" { writeErrorCode(w, http.StatusForbidden, "availability_parked", "availability state parked blocks activation") return } installToken, err := randomHex(24) if err != nil { writeErrorCode(w, http.StatusInternalServerError, "token_generation_failed", "failed to issue install token") return } now := time.Now().UTC() expiresAt := now.Add(a.cfg.InstallTokenTTL) tokenRec := governanceInstallTokenRecord{ InstallToken: installToken, Wallet: wallet, OrgRootID: principal.OrgRootID, PrincipalID: principal.PrincipalID, PrincipalRole: principal.PrincipalRole, DeviceID: strings.TrimSpace(req.DeviceID), EntitlementID: principal.EntitlementID, PackageHash: a.cfg.GovernancePackageHash, RuntimeVersion: a.cfg.GovernanceRuntimeVersion, PolicyHash: a.cfg.GovernancePolicyHash, IssuedAt: now, ExpiresAt: expiresAt, } if err := a.store.putGovernanceInstallToken(r.Context(), tokenRec); err != nil { writeErrorCode(w, http.StatusInternalServerError, "store_error", "failed to persist install token") return } writeJSON(w, http.StatusOK, governanceInstallTokenResponse{ InstallToken: installToken, InstallTokenExpiresAt: expiresAt.Format(time.RFC3339Nano), Wallet: wallet, EntitlementID: principal.EntitlementID, Package: governancePackage{ RuntimeVersion: a.cfg.GovernanceRuntimeVersion, PackageURL: a.cfg.GovernancePackageURL, PackageHash: a.cfg.GovernancePackageHash, Signature: a.cfg.GovernancePackageSig, SignerKeyID: a.cfg.GovernanceSignerKeyID, PolicyHash: a.cfg.GovernancePolicyHash, RolloutChannel: a.cfg.GovernanceRolloutChannel, }, }) } func (a *app) handleGovernanceInstallConfirm(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { writeError(w, http.StatusMethodNotAllowed, "method not allowed") return } var req governanceInstallConfirmRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeErrorCode(w, http.StatusBadRequest, "invalid_request", "invalid request body") return } wallet, err := normalizeAddress(req.Wallet) if err != nil { writeErrorCode(w, http.StatusBadRequest, "invalid_wallet", err.Error()) return } if strings.TrimSpace(req.InstallToken) == "" || strings.TrimSpace(req.DeviceID) == "" { writeErrorCode(w, http.StatusBadRequest, "invalid_request", "install_token and device_id required") return } tokenRec, err := a.store.getGovernanceInstallToken(r.Context(), strings.TrimSpace(req.InstallToken)) if err != nil { if errors.Is(err, errNotFound) { writeErrorCode(w, http.StatusNotFound, "install_token_not_found", "install token not found") return } writeErrorCode(w, http.StatusInternalServerError, "store_error", "failed to load install token") return } if time.Now().UTC().After(tokenRec.ExpiresAt) { writeErrorCode(w, http.StatusConflict, "install_token_expired", "install token expired") return } if tokenRec.ConsumedAt != nil { if existing, existingErr := a.store.getGovernanceInstallByToken(r.Context(), tokenRec.InstallToken); existingErr == nil { writeJSON(w, http.StatusOK, governanceInstallConfirmResponse{ Status: "governance_active", Wallet: existing.Wallet, DeviceID: existing.DeviceID, EntitlementID: existing.EntitlementID, RuntimeVersion: existing.RuntimeVersion, ActivatedAt: existing.ActivatedAt.Format(time.RFC3339Nano), }) return } writeErrorCode(w, http.StatusConflict, "install_token_consumed", "install token already consumed") return } if tokenRec.Wallet != wallet || tokenRec.DeviceID != strings.TrimSpace(req.DeviceID) { writeErrorCode(w, http.StatusBadRequest, "context_mismatch", "install token context mismatch") return } if !strings.EqualFold(strings.TrimSpace(req.EntitlementID), tokenRec.EntitlementID) { writeErrorCode(w, http.StatusBadRequest, "context_mismatch", "entitlement mismatch") return } if !strings.EqualFold(strings.TrimSpace(req.PackageHash), tokenRec.PackageHash) { writeErrorCode(w, http.StatusConflict, "package_hash_mismatch", "package hash mismatch") return } if !strings.EqualFold(strings.TrimSpace(req.RuntimeVersion), tokenRec.RuntimeVersion) { writeErrorCode(w, http.StatusConflict, "runtime_version_mismatch", "runtime version mismatch") return } principal, err := a.store.getGovernancePrincipal(r.Context(), wallet) if err != nil { writeErrorCode(w, http.StatusInternalServerError, "principal_lookup_failed", "failed to resolve principal") return } if strings.ToLower(strings.TrimSpace(principal.EntitlementStatus)) != "active" { writeErrorCode(w, http.StatusConflict, "entitlement_inactive", "entitlement inactive") return } if strings.ToLower(strings.TrimSpace(principal.AvailabilityState)) == "parked" { writeErrorCode(w, http.StatusConflict, "availability_parked", "availability parked") return } installedAt := time.Now().UTC() if parsed, err := time.Parse(time.RFC3339Nano, strings.TrimSpace(req.InstalledAt)); err == nil { installedAt = parsed.UTC() } activatedAt := time.Now().UTC() installRec := governanceInstallRecord{ InstallToken: tokenRec.InstallToken, Wallet: wallet, DeviceID: strings.TrimSpace(req.DeviceID), EntitlementID: tokenRec.EntitlementID, RuntimeVersion: tokenRec.RuntimeVersion, PackageHash: tokenRec.PackageHash, PolicyHash: tokenRec.PolicyHash, LauncherReceiptRef: strings.TrimSpace(req.LauncherReceiptRef), InstalledAt: installedAt, ActivatedAt: activatedAt, } if err := a.store.putGovernanceInstall(r.Context(), installRec); err != nil { writeErrorCode(w, http.StatusInternalServerError, "store_error", "failed to persist install confirmation") return } tokenRec.ConsumedAt = &activatedAt if err := a.store.putGovernanceInstallToken(r.Context(), tokenRec); err != nil { writeErrorCode(w, http.StatusInternalServerError, "store_error", "failed to mark install token consumed") return } writeJSON(w, http.StatusOK, governanceInstallConfirmResponse{ Status: "governance_active", Wallet: wallet, DeviceID: installRec.DeviceID, EntitlementID: installRec.EntitlementID, RuntimeVersion: installRec.RuntimeVersion, ActivatedAt: activatedAt.Format(time.RFC3339Nano), }) } func (a *app) handleGovernanceInstallStatus(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { writeError(w, http.StatusMethodNotAllowed, "method not allowed") return } walletRaw := strings.TrimSpace(r.URL.Query().Get("wallet")) deviceID := strings.TrimSpace(r.URL.Query().Get("device_id")) wallet, err := normalizeAddress(walletRaw) if err != nil { writeErrorCode(w, http.StatusBadRequest, "invalid_wallet", err.Error()) return } membershipStatus := "none" identityAssurance := assuranceNone if rec, err := a.store.getDesignationByAddress(r.Context(), wallet); err == nil { membershipStatus = strings.ToLower(strings.TrimSpace(rec.MembershipStatus)) if membershipStatus == "" { membershipStatus = "none" } identityAssurance = normalizeAssuranceLevel(rec.IdentityAssurance) } resp := governanceInstallStatusResponse{ Wallet: wallet, MembershipStatus: membershipStatus, IdentityAssurance: identityAssurance, EntitlementStatus: "unknown", AccessClass: "unknown", AvailabilityState: "unknown", ActivationStatus: "not_installed", LatestRuntimeVersion: a.cfg.GovernanceRuntimeVersion, PolicyHash: a.cfg.GovernancePolicyHash, } principal, err := a.store.getGovernancePrincipal(r.Context(), wallet) if err == nil { resp.OrgRootID = principal.OrgRootID resp.PrincipalID = principal.PrincipalID resp.PrincipalRole = principal.PrincipalRole resp.EntitlementStatus = strings.ToLower(strings.TrimSpace(principal.EntitlementStatus)) resp.AccessClass = strings.ToLower(strings.TrimSpace(principal.AccessClass)) resp.AvailabilityState = strings.ToLower(strings.TrimSpace(principal.AvailabilityState)) } else if !errors.Is(err, errNotFound) { writeErrorCode(w, http.StatusInternalServerError, "store_error", "failed to load principal status") return } if deviceID != "" { if installRec, err := a.store.getGovernanceInstallByDevice(r.Context(), wallet, deviceID); err == nil { resp.ActivationStatus = "active" resp.LatestRuntimeVersion = installRec.RuntimeVersion } } if resp.AvailabilityState == "parked" { resp.ActivationStatus = "blocked" resp.Reason = "availability_parked" } if resp.EntitlementStatus != "" && resp.EntitlementStatus != "unknown" && resp.EntitlementStatus != "active" { resp.ActivationStatus = "blocked" resp.Reason = "entitlement_inactive" } if resp.MembershipStatus != "active" { resp.Reason = "membership_inactive" } writeJSON(w, http.StatusOK, resp) } func (a *app) handleGovernanceLeaseHeartbeat(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { writeError(w, http.StatusMethodNotAllowed, "method not allowed") return } var req governanceLeaseHeartbeatRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeErrorCode(w, http.StatusBadRequest, "invalid_request", "invalid request body") return } wallet, err := normalizeAddress(req.Wallet) if err != nil { writeErrorCode(w, http.StatusBadRequest, "invalid_wallet", err.Error()) return } principal, err := a.store.getGovernancePrincipal(r.Context(), wallet) if err != nil { writeErrorCode(w, http.StatusForbidden, "principal_missing", "principal state missing") return } if principal.OrgRootID != strings.TrimSpace(req.OrgRootID) || principal.PrincipalID != strings.TrimSpace(req.PrincipalID) { writeErrorCode(w, http.StatusForbidden, "boundary_mismatch", "principal boundary mismatch") return } if strings.ToLower(strings.TrimSpace(principal.EntitlementStatus)) != "active" { writeErrorCode(w, http.StatusForbidden, "entitlement_inactive", "entitlement inactive") return } leaseExpires := time.Now().UTC().Add(a.cfg.LeaseTTL) principal.LeaseExpiresAt = &leaseExpires principal.AvailabilityState = "active" principal.UpdatedAt = time.Now().UTC() if err := a.store.putGovernancePrincipal(r.Context(), principal); err != nil { writeErrorCode(w, http.StatusInternalServerError, "store_error", "failed to persist lease heartbeat") return } writeJSON(w, http.StatusOK, governanceLeaseHeartbeatResponse{ Status: "lease_refreshed", AvailabilityState: "active", LeaseExpiresAt: leaseExpires.Format(time.RFC3339Nano), }) } func (a *app) handleGovernanceOfflineRenew(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { writeError(w, http.StatusMethodNotAllowed, "method not allowed") return } var req governanceOfflineRenewRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeErrorCode(w, http.StatusBadRequest, "invalid_request", "invalid request body") return } wallet, err := normalizeAddress(req.Wallet) if err != nil { writeErrorCode(w, http.StatusBadRequest, "invalid_wallet", err.Error()) return } principal, err := a.store.getGovernancePrincipal(r.Context(), wallet) if err != nil { writeErrorCode(w, http.StatusForbidden, "principal_missing", "principal state missing") return } if principal.OrgRootID != strings.TrimSpace(req.OrgRootID) || principal.PrincipalID != strings.TrimSpace(req.PrincipalID) { writeErrorCode(w, http.StatusForbidden, "boundary_mismatch", "principal boundary mismatch") return } if strings.ToLower(strings.TrimSpace(principal.EntitlementStatus)) != "active" { writeErrorCode(w, http.StatusForbidden, "entitlement_inactive", "entitlement inactive") return } isSoloRoot := strings.EqualFold(strings.TrimSpace(principal.OrgRootID), defaultSoloOrgRootID(wallet)) requiredOfferID := offerIDWorkspaceSovereign if isSoloRoot { requiredOfferID = offerIDSoloCore } hasRequired, entErr := a.store.hasActiveEntitlement(r.Context(), wallet, requiredOfferID, principal.OrgRootID) if entErr != nil { writeErrorCode(w, http.StatusInternalServerError, "store_error", "failed to resolve sovereign entitlement") return } if !hasRequired { writeErrorCode(w, http.StatusForbidden, "sovereign_entitlement_required", "sovereign entitlement required for offline renew") return } renewedUntil := time.Now().UTC().Add(a.cfg.OfflineRenewTTL) principal.AccessClass = "sovereign" principal.AvailabilityState = "active" principal.LeaseExpiresAt = &renewedUntil principal.UpdatedAt = time.Now().UTC() if err := a.store.putGovernancePrincipal(r.Context(), principal); err != nil { writeErrorCode(w, http.StatusInternalServerError, "store_error", "failed to persist offline renewal") return } writeJSON(w, http.StatusOK, governanceOfflineRenewResponse{ Status: "renewal_applied", AvailabilityState: "active", RenewedUntil: renewedUntil.Format(time.RFC3339Nano), }) } func (a *app) handleMemberChannelDeviceRegister(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { writeError(w, http.StatusMethodNotAllowed, "method not allowed") return } var req memberChannelDeviceRegisterRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeErrorCode(w, http.StatusBadRequest, "invalid_request", "invalid request body") return } wallet, err := normalizeAddress(req.Wallet) if err != nil { writeErrorCode(w, http.StatusBadRequest, "invalid_wallet", err.Error()) return } if req.ChainID != a.cfg.ChainID { writeErrorCode(w, http.StatusBadRequest, "unsupported_chain_id", fmt.Sprintf("unsupported chain_id: %d", req.ChainID)) return } req.DeviceID = strings.TrimSpace(req.DeviceID) req.Platform = strings.ToLower(strings.TrimSpace(req.Platform)) req.OrgRootID = strings.TrimSpace(req.OrgRootID) req.PrincipalID = strings.TrimSpace(req.PrincipalID) req.PrincipalRole = strings.ToLower(strings.TrimSpace(req.PrincipalRole)) req.AppVersion = strings.TrimSpace(req.AppVersion) req.PushProvider = strings.ToLower(strings.TrimSpace(req.PushProvider)) req.PushToken = strings.TrimSpace(req.PushToken) if req.DeviceID == "" || req.Platform == "" || req.OrgRootID == "" || req.PrincipalID == "" || req.PrincipalRole == "" || req.AppVersion == "" { writeErrorCode(w, http.StatusBadRequest, "invalid_request", "device_id, platform, org_root_id, principal_id, principal_role, app_version required") return } if req.PushProvider == "" { req.PushProvider = "none" } rec, err := a.store.getDesignationByAddress(r.Context(), wallet) if err != nil || !strings.EqualFold(strings.TrimSpace(rec.MembershipStatus), "active") { writeErrorCode(w, http.StatusForbidden, "membership_inactive", "membership_inactive") return } now := time.Now().UTC() channelBindingID, err := randomHex(12) if err != nil { writeErrorCode(w, http.StatusInternalServerError, "binding_generation_failed", "failed to create channel binding") return } binding := memberChannelBindingRecord{ ChannelBindingID: "ch_" + channelBindingID, Wallet: wallet, ChainID: req.ChainID, DeviceID: req.DeviceID, Platform: req.Platform, OrgRootID: req.OrgRootID, PrincipalID: req.PrincipalID, PrincipalRole: req.PrincipalRole, AppVersion: req.AppVersion, PushProvider: req.PushProvider, PushToken: req.PushToken, Status: "active", CreatedAt: now, UpdatedAt: now, } if err := a.store.putMemberChannelBinding(r.Context(), binding); err != nil { writeErrorCode(w, http.StatusInternalServerError, "store_error", "failed to persist channel binding") return } _ = a.seedMemberChannelEvents(r.Context(), binding) writeJSON(w, http.StatusOK, memberChannelDeviceRegisterResponse{ ChannelBindingID: binding.ChannelBindingID, Status: "active", PollIntervalSeconds: a.cfg.MemberPollIntervalSec, ServerTime: now.Format(time.RFC3339Nano), }) } func (a *app) handleMemberChannelDeviceUnregister(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { writeError(w, http.StatusMethodNotAllowed, "method not allowed") return } var req memberChannelDeviceUnregisterRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeErrorCode(w, http.StatusBadRequest, "invalid_request", "invalid request body") return } wallet, err := normalizeAddress(req.Wallet) if err != nil { writeErrorCode(w, http.StatusBadRequest, "invalid_wallet", err.Error()) return } req.DeviceID = strings.TrimSpace(req.DeviceID) if req.DeviceID == "" { writeErrorCode(w, http.StatusBadRequest, "invalid_request", "device_id required") return } if err := a.store.removeMemberChannelBinding(r.Context(), wallet, req.DeviceID, time.Now().UTC()); err != nil { if errors.Is(err, errNotFound) { writeErrorCode(w, http.StatusNotFound, "channel_binding_not_found", "device channel binding not found") return } writeErrorCode(w, http.StatusInternalServerError, "store_error", "failed to remove channel binding") return } writeJSON(w, http.StatusOK, memberChannelDeviceUnregisterResponse{ Status: "removed", Wallet: wallet, DeviceID: req.DeviceID, }) } func (a *app) handleMemberChannelEvents(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { writeError(w, http.StatusMethodNotAllowed, "method not allowed") return } wallet, err := normalizeAddress(strings.TrimSpace(r.URL.Query().Get("wallet"))) if err != nil { writeErrorCode(w, http.StatusBadRequest, "invalid_wallet", err.Error()) return } deviceID := strings.TrimSpace(r.URL.Query().Get("device_id")) if deviceID == "" { writeErrorCode(w, http.StatusBadRequest, "invalid_request", "device_id required") return } limit := 25 if raw := strings.TrimSpace(r.URL.Query().Get("limit")); raw != "" { parsed, parseErr := strconv.Atoi(raw) if parseErr != nil { writeErrorCode(w, http.StatusBadRequest, "invalid_request", "invalid limit") return } if parsed < 1 { parsed = 1 } if parsed > 100 { parsed = 100 } limit = parsed } cursor := strings.TrimSpace(r.URL.Query().Get("cursor")) rec, err := a.store.getDesignationByAddress(r.Context(), wallet) if err != nil || !strings.EqualFold(strings.TrimSpace(rec.MembershipStatus), "active") { writeErrorCode(w, http.StatusForbidden, "membership_inactive", "membership_inactive") return } binding, err := a.store.getMemberChannelBinding(r.Context(), wallet, deviceID) if err != nil { writeErrorCode(w, http.StatusForbidden, "channel_binding_missing", "channel binding missing") return } ownerVisible := strings.EqualFold(strings.TrimSpace(binding.PrincipalRole), "org_root_owner") events, nextCursor, err := a.store.listMemberChannelEvents(r.Context(), wallet, binding.OrgRootID, ownerVisible, cursor, limit) if err != nil { writeErrorCode(w, http.StatusInternalServerError, "store_error", "failed to list member channel events") return } out := make([]memberChannelEvent, 0, len(events)) for _, event := range events { payload := map[string]any{} if strings.TrimSpace(event.PayloadJSON) != "" { _ = json.Unmarshal([]byte(event.PayloadJSON), &payload) } out = append(out, memberChannelEvent{ EventID: event.EventID, Class: event.Class, CreatedAt: event.CreatedAt.Format(time.RFC3339Nano), Title: event.Title, Body: event.Body, DedupeKey: event.DedupeKey, RequiresAck: event.RequiresAck, PolicyHash: event.PolicyHash, VisibilityScope: event.VisibilityScope, Payload: payload, }) } writeJSON(w, http.StatusOK, memberChannelEventsResponse{ Wallet: wallet, DeviceID: binding.DeviceID, OrgRootID: binding.OrgRootID, PrincipalID: binding.PrincipalID, Events: out, NextCursor: nextCursor, ServerTime: time.Now().UTC().Format(time.RFC3339Nano), }) } func (a *app) handleMemberChannelEventAck(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { writeError(w, http.StatusMethodNotAllowed, "method not allowed") return } const prefix = "/member/channel/events/" path := strings.TrimPrefix(r.URL.Path, prefix) if path == r.URL.Path || !strings.HasSuffix(path, "/ack") { writeErrorCode(w, http.StatusNotFound, "not_found", "route not found") return } eventID := strings.TrimSuffix(path, "/ack") eventID = strings.TrimSpace(strings.TrimSuffix(eventID, "/")) if eventID == "" { writeErrorCode(w, http.StatusBadRequest, "invalid_request", "event_id required") return } var req memberChannelEventAckRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeErrorCode(w, http.StatusBadRequest, "invalid_request", "invalid request body") return } wallet, err := normalizeAddress(req.Wallet) if err != nil { writeErrorCode(w, http.StatusBadRequest, "invalid_wallet", err.Error()) return } deviceID := strings.TrimSpace(req.DeviceID) if deviceID == "" { writeErrorCode(w, http.StatusBadRequest, "invalid_request", "device_id required") return } ackAt, err := time.Parse(time.RFC3339Nano, strings.TrimSpace(req.AcknowledgedAt)) if err != nil { writeErrorCode(w, http.StatusBadRequest, "invalid_request", "acknowledged_at must be RFC3339") return } event, err := a.store.getMemberChannelEventByID(r.Context(), eventID) if err != nil { writeErrorCode(w, http.StatusNotFound, "event_not_found", "event not found") return } binding, err := a.store.getMemberChannelBinding(r.Context(), wallet, deviceID) if err != nil || !strings.EqualFold(event.Wallet, wallet) || !strings.EqualFold(event.OrgRootID, binding.OrgRootID) { writeErrorCode(w, http.StatusForbidden, "channel_binding_missing", "channel binding missing") return } if strings.EqualFold(event.VisibilityScope, "owner_admin") && !strings.EqualFold(strings.TrimSpace(binding.PrincipalRole), "org_root_owner") { writeErrorCode(w, http.StatusForbidden, "owner_role_required", "contact_your_org_admin") return } effectiveAck, err := a.store.putMemberChannelEventAck(r.Context(), eventID, wallet, deviceID, ackAt.UTC()) if err != nil { writeErrorCode(w, http.StatusInternalServerError, "store_error", "failed to persist acknowledgement") return } writeJSON(w, http.StatusOK, memberChannelEventAckResponse{ Status: "acknowledged", EventID: eventID, AcknowledgedAt: effectiveAck.Format(time.RFC3339Nano), }) } func (a *app) handleMemberChannelSupportTicket(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { writeError(w, http.StatusMethodNotAllowed, "method not allowed") return } var req memberChannelSupportTicketRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeErrorCode(w, http.StatusBadRequest, "invalid_request", "invalid request body") return } wallet, err := normalizeAddress(req.Wallet) if err != nil { writeErrorCode(w, http.StatusBadRequest, "invalid_wallet", err.Error()) return } req.OrgRootID = strings.TrimSpace(req.OrgRootID) req.PrincipalID = strings.TrimSpace(req.PrincipalID) req.Category = strings.TrimSpace(req.Category) req.Summary = strings.TrimSpace(req.Summary) if req.OrgRootID == "" || req.PrincipalID == "" || req.Category == "" || req.Summary == "" { writeErrorCode(w, http.StatusBadRequest, "invalid_request", "org_root_id, principal_id, category, summary required") return } rec, err := a.store.getDesignationByAddress(r.Context(), wallet) if err != nil || !strings.EqualFold(strings.TrimSpace(rec.MembershipStatus), "active") { writeErrorCode(w, http.StatusForbidden, "membership_inactive", "membership_inactive") return } if !isOnrampAttested(rec.IdentityAssurance) { writeErrorCode(w, http.StatusForbidden, "identity_assurance_insufficient", "owner support actions require onramp_attested identity assurance") return } role := "" if principal, principalErr := a.store.getGovernancePrincipal(r.Context(), wallet); principalErr == nil && strings.EqualFold(strings.TrimSpace(principal.OrgRootID), req.OrgRootID) && strings.EqualFold(strings.TrimSpace(principal.PrincipalID), req.PrincipalID) { role = strings.ToLower(strings.TrimSpace(principal.PrincipalRole)) } if role == "" { if binding, bindingErr := a.store.getMemberChannelBindingByPrincipal(r.Context(), wallet, req.OrgRootID, req.PrincipalID); bindingErr == nil { role = strings.ToLower(strings.TrimSpace(binding.PrincipalRole)) } } if role != "org_root_owner" { writeErrorCode(w, http.StatusForbidden, "owner_role_required", "contact_your_org_admin") return } contextJSON := "{}" if len(req.Context) > 0 { raw, marshalErr := json.Marshal(req.Context) if marshalErr == nil { contextJSON = string(raw) } } idRaw, err := randomHex(12) if err != nil { writeErrorCode(w, http.StatusInternalServerError, "ticket_generation_failed", "failed to generate ticket id") return } now := time.Now().UTC() ticket := memberChannelSupportTicketRecord{ TicketID: "st_" + idRaw, Wallet: wallet, OrgRootID: req.OrgRootID, PrincipalID: req.PrincipalID, Category: req.Category, Summary: req.Summary, ContextJSON: contextJSON, Status: "accepted", CreatedAt: now, } if err := a.store.putMemberChannelSupportTicket(r.Context(), ticket); err != nil { writeErrorCode(w, http.StatusInternalServerError, "store_error", "failed to persist support ticket") return } writeJSON(w, http.StatusOK, memberChannelSupportTicketResponse{ Status: "accepted", TicketID: ticket.TicketID, CreatedAt: now.Format(time.RFC3339Nano), }) } func (a *app) seedMemberChannelEvents(ctx context.Context, binding memberChannelBindingRecord) error { membershipPayload := map[string]any{ "status": "active", } rawMembershipPayload, _ := json.Marshal(membershipPayload) _ = a.store.putMemberChannelEvent(ctx, memberChannelEventRecord{ Wallet: binding.Wallet, OrgRootID: binding.OrgRootID, PrincipalID: binding.PrincipalID, Class: "membership_policy", CreatedAt: time.Now().UTC(), Title: "Membership active", Body: "Your EDUT membership is active. Governance install is available when you are ready.", DedupeKey: "membership_policy:active", RequiresAck: true, PolicyHash: a.cfg.GovernancePolicyHash, PayloadJSON: string(rawMembershipPayload), VisibilityScope: "member", }) if strings.EqualFold(strings.TrimSpace(binding.PrincipalRole), "org_root_owner") { updatePayload := map[string]any{ "version": a.cfg.GovernanceRuntimeVersion, "channel": a.cfg.GovernanceRolloutChannel, } rawUpdatePayload, _ := json.Marshal(updatePayload) _ = a.store.putMemberChannelEvent(ctx, memberChannelEventRecord{ Wallet: binding.Wallet, OrgRootID: binding.OrgRootID, PrincipalID: binding.PrincipalID, Class: "platform_update", CreatedAt: time.Now().UTC(), Title: "Governance runtime available", Body: "A deterministic governance runtime is available for this organization boundary.", DedupeKey: "platform_update:" + a.cfg.GovernanceRuntimeVersion, RequiresAck: true, PolicyHash: a.cfg.GovernancePolicyHash, PayloadJSON: string(rawUpdatePayload), VisibilityScope: "owner_admin", }) } return nil } func (a *app) resolveOrCreatePrincipal(ctx context.Context, wallet, orgRootID, principalID, principalRole string) (governancePrincipalRecord, error) { principal, err := a.store.getGovernancePrincipal(ctx, wallet) if err == nil { return principal, nil } if !errors.Is(err, errNotFound) { return governancePrincipalRecord{}, err } orgRootID = strings.TrimSpace(orgRootID) principalID = strings.TrimSpace(principalID) principalRole = strings.TrimSpace(strings.ToLower(principalRole)) if orgRootID == "" { orgRootID = "org_" + wallet[2:10] } if principalID == "" { principalID = "principal_" + wallet[2:10] } if principalRole == "" { principalRole = "org_root_owner" } now := time.Now().UTC() leaseExpires := now.Add(a.cfg.LeaseTTL) principal = governancePrincipalRecord{ Wallet: wallet, OrgRootID: orgRootID, PrincipalID: principalID, PrincipalRole: principalRole, EntitlementID: "", EntitlementStatus: "inactive", AccessClass: "connected", AvailabilityState: "active", LeaseExpiresAt: &leaseExpires, UpdatedAt: now, } if err := a.store.putGovernancePrincipal(ctx, principal); err != nil { return governancePrincipalRecord{}, err } return principal, nil } func writeJSON(w http.ResponseWriter, status int, payload any) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) _ = json.NewEncoder(w).Encode(payload) } func writeError(w http.ResponseWriter, status int, message string) { writeErrorCode(w, status, "request_failed", message) } func writeErrorCode(w http.ResponseWriter, status int, code string, message string) { correlationID := "req_unknown" if rid, err := randomHex(8); err == nil { correlationID = "req_" + rid } writeJSON(w, status, map[string]string{ "error": message, "code": strings.TrimSpace(strings.ToLower(code)), "correlation_id": correlationID, }) } func randomHex(byteLen int) (string, error) { buf := make([]byte, byteLen) if _, err := rand.Read(buf); err != nil { return "", err } return hex.EncodeToString(buf), nil } func newDesignationCode() (code string, displayToken string, err error) { // 13-digit deterministic shape: unix millis + random suffix. now := time.Now().UTC().UnixMilli() suffix, err := randomInt(1000, 9999) if err != nil { return "", "", err } raw := fmt.Sprintf("%d%d", now, suffix) if len(raw) > 13 { raw = raw[len(raw)-13:] } if len(raw) < 13 { raw = strings.Repeat("0", 13-len(raw)) + raw } if !reDigits.MatchString(raw) { return "", "", fmt.Errorf("invalid designation code") } return raw, buildDisplayToken(raw), nil } func buildDisplayToken(code string) string { if len(code) < 13 { return code } return code[0:4] + "-" + code[4:8] + "-" + code[8:12] + "-" + code[12:] } func randomInt(min int, max int) (int, error) { if min >= max { return min, nil } span := big.NewInt(int64(max - min + 1)) n, err := rand.Int(rand.Reader, span) if err != nil { return 0, err } return min + int(n.Int64()), nil } func isTxHash(value string) bool { value = strings.TrimSpace(strings.ToLower(value)) if !strings.HasPrefix(value, "0x") || len(value) != 66 { return false } _, err := strconv.ParseUint(value[2:18], 16, 64) return err == nil } func logConfig(cfg Config) { log.Printf("secret api listening on %s chain_id=%d contract=%s currency=%s amount_atomic=%s", cfg.ListenAddr, cfg.ChainID, cfg.MembershipContract, cfg.MintCurrency, cfg.MintAmountAtomic) }