mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-02 17:31:39 +00:00
447 lines
11 KiB
Go
447 lines
11 KiB
Go
//go:build js && wasm
|
|
// +build js,wasm
|
|
|
|
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// Health & Status Handlers
|
|
|
|
// handleHealth returns service health status
|
|
func handleHealth(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == "OPTIONS" {
|
|
handleCORS(w)
|
|
return
|
|
}
|
|
|
|
writeJSON(w, http.StatusOK, map[string]interface{}{
|
|
"status": "healthy",
|
|
"service": "motor-gateway",
|
|
"timestamp": time.Now().Unix(),
|
|
})
|
|
}
|
|
|
|
// handleStatus returns detailed service status
|
|
func handleStatus(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == "OPTIONS" {
|
|
handleCORS(w)
|
|
return
|
|
}
|
|
|
|
writeJSON(w, http.StatusOK, map[string]interface{}{
|
|
"status": "operational",
|
|
"version": "1.0.0",
|
|
"services": map[string]string{
|
|
"payment_gateway": "active",
|
|
"oidc_provider": "active",
|
|
},
|
|
"uptime": time.Now().Unix(),
|
|
})
|
|
}
|
|
|
|
// W3C Payment Handler API Handlers
|
|
|
|
// handlePaymentInstruments returns available payment instruments
|
|
func handlePaymentInstruments(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == "OPTIONS" {
|
|
handleCORS(w)
|
|
return
|
|
}
|
|
|
|
if r.Method != "GET" {
|
|
writeError(w, http.StatusMethodNotAllowed, "Method not allowed")
|
|
return
|
|
}
|
|
|
|
instruments := paymentHandler.GetInstruments()
|
|
writeJSON(w, http.StatusOK, map[string]interface{}{
|
|
"instruments": instruments,
|
|
})
|
|
}
|
|
|
|
// handleCanMakePayment checks if payment can be made
|
|
func handleCanMakePayment(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == "OPTIONS" {
|
|
handleCORS(w)
|
|
return
|
|
}
|
|
|
|
if r.Method != "POST" {
|
|
writeError(w, http.StatusMethodNotAllowed, "Method not allowed")
|
|
return
|
|
}
|
|
|
|
var req struct {
|
|
MethodData []PaymentMethod `json:"methodData"`
|
|
}
|
|
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeError(w, http.StatusBadRequest, "Invalid request body")
|
|
return
|
|
}
|
|
|
|
canMakePayment := paymentHandler.CanMakePayment(req.MethodData)
|
|
writeJSON(w, http.StatusOK, map[string]interface{}{
|
|
"canMakePayment": canMakePayment,
|
|
})
|
|
}
|
|
|
|
// handlePaymentRequest handles W3C PaymentRequestEvent
|
|
func handlePaymentRequest(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == "OPTIONS" {
|
|
handleCORS(w)
|
|
return
|
|
}
|
|
|
|
if r.Method != "POST" {
|
|
writeError(w, http.StatusMethodNotAllowed, "Method not allowed")
|
|
return
|
|
}
|
|
|
|
// Parse payment request event
|
|
var reqData json.RawMessage
|
|
if err := json.NewDecoder(r.Body).Decode(&reqData); err != nil {
|
|
writeError(w, http.StatusBadRequest, "Invalid request body")
|
|
return
|
|
}
|
|
|
|
paymentReq, err := SerializePaymentRequest(reqData)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadRequest, "Invalid payment request")
|
|
return
|
|
}
|
|
|
|
// Process payment request
|
|
tx, err := paymentHandler.ProcessPayment(paymentReq)
|
|
if err != nil {
|
|
writeError(w, http.StatusInternalServerError, "Payment processing failed")
|
|
return
|
|
}
|
|
|
|
// Return payment response
|
|
if tx.Response != nil {
|
|
writeJSON(w, http.StatusOK, tx.Response)
|
|
} else {
|
|
writeJSON(w, http.StatusAccepted, map[string]interface{}{
|
|
"transactionId": tx.ID,
|
|
"status": tx.Status,
|
|
})
|
|
}
|
|
}
|
|
|
|
// Payment Gateway Handlers
|
|
|
|
// handlePaymentProcess processes a payment transaction using W3C Payment Handler API
|
|
func handlePaymentProcess(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == "OPTIONS" {
|
|
handleCORS(w)
|
|
return
|
|
}
|
|
|
|
if r.Method != "POST" {
|
|
writeError(w, http.StatusMethodNotAllowed, "Method not allowed")
|
|
return
|
|
}
|
|
|
|
// Parse payment request
|
|
var reqData json.RawMessage
|
|
if err := json.NewDecoder(r.Body).Decode(&reqData); err != nil {
|
|
writeError(w, http.StatusBadRequest, "Invalid request body")
|
|
return
|
|
}
|
|
|
|
paymentReq, err := SerializePaymentRequest(reqData)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadRequest, "Invalid payment request")
|
|
return
|
|
}
|
|
|
|
// Process payment
|
|
tx, err := paymentHandler.ProcessPayment(paymentReq)
|
|
if err != nil {
|
|
writeError(w, http.StatusInternalServerError, "Payment processing failed")
|
|
return
|
|
}
|
|
|
|
writeJSON(w, http.StatusOK, tx)
|
|
}
|
|
|
|
// handlePaymentValidate validates a payment method
|
|
func handlePaymentValidate(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == "OPTIONS" {
|
|
handleCORS(w)
|
|
return
|
|
}
|
|
|
|
if r.Method != "POST" {
|
|
writeError(w, http.StatusMethodNotAllowed, "Method not allowed")
|
|
return
|
|
}
|
|
|
|
// Parse validation request
|
|
var req struct {
|
|
Method string `json:"method"`
|
|
Data map[string]interface{} `json:"data"`
|
|
}
|
|
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeError(w, http.StatusBadRequest, "Invalid request body")
|
|
return
|
|
}
|
|
|
|
// Validate payment method
|
|
valid, err := paymentHandler.ValidatePaymentMethod(req.Method, req.Data)
|
|
if err != nil {
|
|
writeError(w, http.StatusInternalServerError, "Validation failed")
|
|
return
|
|
}
|
|
|
|
writeJSON(w, http.StatusOK, map[string]interface{}{
|
|
"valid": valid,
|
|
"method": req.Method,
|
|
"message": "Payment method validation complete",
|
|
})
|
|
}
|
|
|
|
// handlePaymentStatus returns payment transaction status
|
|
func handlePaymentStatus(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == "OPTIONS" {
|
|
handleCORS(w)
|
|
return
|
|
}
|
|
|
|
if r.Method != "GET" {
|
|
writeError(w, http.StatusMethodNotAllowed, "Method not allowed")
|
|
return
|
|
}
|
|
|
|
// Extract transaction ID from path
|
|
txID := strings.TrimPrefix(r.URL.Path, "/api/payment/status/")
|
|
if txID == "" {
|
|
writeError(w, http.StatusBadRequest, "Transaction ID required")
|
|
return
|
|
}
|
|
|
|
// Get transaction from handler
|
|
tx, exists := paymentHandler.GetTransaction(txID)
|
|
if !exists {
|
|
writeError(w, http.StatusNotFound, "Transaction not found")
|
|
return
|
|
}
|
|
|
|
writeJSON(w, http.StatusOK, tx)
|
|
}
|
|
|
|
// handlePaymentRefund processes a refund
|
|
func handlePaymentRefund(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == "OPTIONS" {
|
|
handleCORS(w)
|
|
return
|
|
}
|
|
|
|
if r.Method != "POST" {
|
|
writeError(w, http.StatusMethodNotAllowed, "Method not allowed")
|
|
return
|
|
}
|
|
|
|
// TODO: Implement refund processing
|
|
writeJSON(w, http.StatusOK, map[string]interface{}{
|
|
"refund_id": "ref_" + generateID(),
|
|
"status": "processing",
|
|
"message": "Refund initiated",
|
|
})
|
|
}
|
|
|
|
// OIDC Handlers
|
|
|
|
// handleOIDCDiscovery returns OIDC discovery document
|
|
func handleOIDCDiscovery(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == "OPTIONS" {
|
|
handleCORS(w)
|
|
return
|
|
}
|
|
|
|
discovery := oidcProvider.GetDiscovery()
|
|
writeJSON(w, http.StatusOK, discovery)
|
|
}
|
|
|
|
// handleJWKS returns JSON Web Key Set
|
|
func handleJWKS(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == "OPTIONS" {
|
|
handleCORS(w)
|
|
return
|
|
}
|
|
|
|
jwk := jwtManager.GetPublicKeyJWK()
|
|
writeJSON(w, http.StatusOK, map[string]interface{}{
|
|
"keys": []map[string]interface{}{jwk},
|
|
})
|
|
}
|
|
|
|
// handleAuthorize handles authorization requests
|
|
func handleAuthorize(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == "OPTIONS" {
|
|
handleCORS(w)
|
|
return
|
|
}
|
|
|
|
if r.Method != "GET" && r.Method != "POST" {
|
|
writeError(w, http.StatusMethodNotAllowed, "Method not allowed")
|
|
return
|
|
}
|
|
|
|
// Parse authorization request
|
|
clientID := r.FormValue("client_id")
|
|
redirectURI := r.FormValue("redirect_uri")
|
|
responseType := r.FormValue("response_type")
|
|
scope := r.FormValue("scope")
|
|
state := r.FormValue("state")
|
|
nonce := r.FormValue("nonce")
|
|
codeChallenge := r.FormValue("code_challenge")
|
|
codeChallengeMethod := r.FormValue("code_challenge_method")
|
|
|
|
// Validate request
|
|
if clientID == "" || redirectURI == "" || responseType == "" {
|
|
writeError(w, http.StatusBadRequest, "Missing required parameters")
|
|
return
|
|
}
|
|
|
|
// For demo, auto-approve with test user
|
|
userID := "test-user"
|
|
|
|
// Generate authorization code
|
|
authCode, err := oidcProvider.GenerateAuthorizationCode(
|
|
clientID, redirectURI, scope, state, nonce, userID,
|
|
codeChallenge, codeChallengeMethod,
|
|
)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadRequest, err.Error())
|
|
return
|
|
}
|
|
|
|
// Return authorization code
|
|
writeJSON(w, http.StatusOK, map[string]interface{}{
|
|
"code": authCode.Code,
|
|
"state": state,
|
|
"redirect_uri": redirectURI,
|
|
})
|
|
}
|
|
|
|
// handleToken handles token requests
|
|
func handleToken(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == "OPTIONS" {
|
|
handleCORS(w)
|
|
return
|
|
}
|
|
|
|
if r.Method != "POST" {
|
|
writeError(w, http.StatusMethodNotAllowed, "Method not allowed")
|
|
return
|
|
}
|
|
|
|
// Parse token request
|
|
var req TokenRequest
|
|
req.GrantType = r.FormValue("grant_type")
|
|
req.Code = r.FormValue("code")
|
|
req.RedirectURI = r.FormValue("redirect_uri")
|
|
req.ClientID = r.FormValue("client_id")
|
|
req.ClientSecret = r.FormValue("client_secret")
|
|
req.RefreshToken = r.FormValue("refresh_token")
|
|
req.Scope = r.FormValue("scope")
|
|
req.CodeVerifier = r.FormValue("code_verifier")
|
|
|
|
// Handle based on grant type
|
|
var resp *TokenResponse
|
|
var err error
|
|
|
|
switch req.GrantType {
|
|
case "authorization_code":
|
|
resp, err = oidcProvider.ExchangeCode(&req)
|
|
case "refresh_token":
|
|
// TODO: Implement refresh token flow
|
|
writeError(w, http.StatusNotImplemented, "Refresh token not yet implemented")
|
|
return
|
|
default:
|
|
writeError(w, http.StatusBadRequest, "Unsupported grant type")
|
|
return
|
|
}
|
|
|
|
if err != nil {
|
|
writeError(w, http.StatusBadRequest, err.Error())
|
|
return
|
|
}
|
|
|
|
writeJSON(w, http.StatusOK, resp)
|
|
}
|
|
|
|
// handleUserInfo returns user information
|
|
func handleUserInfo(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == "OPTIONS" {
|
|
handleCORS(w)
|
|
return
|
|
}
|
|
|
|
if r.Method != "GET" && r.Method != "POST" {
|
|
writeError(w, http.StatusMethodNotAllowed, "Method not allowed")
|
|
return
|
|
}
|
|
|
|
// Get bearer token from Authorization header
|
|
authHeader := r.Header.Get("Authorization")
|
|
if authHeader == "" {
|
|
writeError(w, http.StatusUnauthorized, "Missing authorization header")
|
|
return
|
|
}
|
|
|
|
// Extract token
|
|
parts := strings.Split(authHeader, " ")
|
|
if len(parts) != 2 || parts[0] != "Bearer" {
|
|
writeError(w, http.StatusUnauthorized, "Invalid authorization header")
|
|
return
|
|
}
|
|
|
|
accessToken := parts[1]
|
|
|
|
// Get user info
|
|
userInfo, err := oidcProvider.GetUserInfo(accessToken)
|
|
if err != nil {
|
|
writeError(w, http.StatusUnauthorized, err.Error())
|
|
return
|
|
}
|
|
|
|
writeJSON(w, http.StatusOK, userInfo)
|
|
}
|
|
|
|
// Helper Functions
|
|
|
|
// handleCORS handles CORS preflight requests
|
|
func handleCORS(w http.ResponseWriter) {
|
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
|
|
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
|
|
w.WriteHeader(http.StatusOK)
|
|
}
|
|
|
|
// writeJSON writes JSON response
|
|
func writeJSON(w http.ResponseWriter, status int, data interface{}) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
w.WriteHeader(status)
|
|
json.NewEncoder(w).Encode(data)
|
|
}
|
|
|
|
// writeError writes error response
|
|
func writeError(w http.ResponseWriter, status int, message string) {
|
|
writeJSON(w, status, map[string]string{"error": message})
|
|
}
|
|
|
|
// generateID generates a simple ID
|
|
func generateID() string {
|
|
return time.Now().Format("20060102150405")
|
|
}
|