mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-02 17:31:39 +00:00
@@ -0,0 +1,446 @@
|
||||
//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")
|
||||
}
|
||||
Reference in New Issue
Block a user