183 lines
5.6 KiB
Go
Raw Permalink Normal View History

2025-03-25 03:52:30 -04:00
package identity
import (
"context"
"net/http"
"os"
"time"
"github.com/gin-gonic/gin"
)
// VerificationHandler manages HTTP requests for identity verification
type VerificationHandler struct {
service *VerificationService
}
// NewVerificationHandler creates a new verification handler
func NewVerificationHandler() *VerificationHandler {
service := NewVerificationService()
// Get Privado API key and URL from environment
privadoAPIKey := os.Getenv("PRIVADO_API_KEY")
privadoAPIURL := os.Getenv("PRIVADO_API_URL")
if privadoAPIKey == "" {
privadoAPIKey = "development-key"
}
if privadoAPIURL == "" {
privadoAPIURL = "https://api.privado.ai"
}
// Register default providers with Privado integration
service.RegisterProvider(NewUSVerificationProvider(privadoAPIKey, privadoAPIURL))
service.RegisterProvider(NewCanadaVerificationProvider(privadoAPIKey, privadoAPIURL))
return &VerificationHandler{
service: service,
}
}
// VerificationRequest represents the JSON payload for verification requests
type VerificationRequest struct {
Country string `json:"country" binding:"required"`
ZKPProof string `json:"zkpProof" binding:"required"`
SelfAttestedEligible string `json:"selfAttestedEligible"`
LegalDisclaimerAcknowledged bool `json:"legalDisclaimerAcknowledged"`
AdditionalData map[string]string `json:"additionalData"`
}
// VerificationResponse represents the JSON response for verification requests
type VerificationResponse struct {
Status string `json:"status"`
CitizenshipVerified bool `json:"citizenshipVerified"`
EligibilityVerified bool `json:"eligibilityVerified"`
Error *ErrorResponse `json:"error,omitempty"`
}
// ErrorResponse provides a structured error response
type ErrorResponse struct {
Code string `json:"code"`
Message string `json:"message"`
}
// LegalDisclaimerResponse provides the legal disclaimer text
type LegalDisclaimerResponse struct {
DisclaimerText string `json:"disclaimerText"`
}
// HandleVerify handles the verification endpoint
func (h *VerificationHandler) HandleVerify(c *gin.Context) {
var request VerificationRequest
// Parse the request body
if err := c.ShouldBindJSON(&request); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": ErrorResponse{
Code: ErrorCodeInvalidInput,
Message: "Invalid request format",
},
})
return
}
// Create a timeout context
ctx, cancel := context.WithTimeout(c.Request.Context(), 10*time.Second)
defer cancel()
// Prepare userData map from the request
userData := make(map[string]string)
// Add ZKP proof
userData["zkpProof"] = request.ZKPProof
// Add eligibility self-attestation if provided
if request.SelfAttestedEligible != "" {
userData["selfAttestedEligible"] = request.SelfAttestedEligible
} else {
userData["selfAttestedEligible"] = "false"
}
// Add legal disclaimer acknowledgment
if request.LegalDisclaimerAcknowledged {
userData["legalDisclaimerAcknowledged"] = "true"
} else {
userData["legalDisclaimerAcknowledged"] = "false"
}
// Add any additional data
if request.AdditionalData != nil {
for key, value := range request.AdditionalData {
userData[key] = value
}
}
// Verify the user
result := h.service.VerifyUser(ctx, request.Country, userData)
// Prepare the response
response := VerificationResponse{
Status: string(result.Status),
CitizenshipVerified: result.CitizenshipVerified,
EligibilityVerified: result.EligibilityVerified,
}
// Handle errors
if result.Error != nil {
if ve, ok := result.Error.(*VerificationError); ok {
response.Error = &ErrorResponse{
Code: ve.Code,
Message: ve.Message,
}
} else {
response.Error = &ErrorResponse{
Code: ErrorCodeServiceUnavailable,
Message: result.Error.Error(),
}
}
}
c.JSON(http.StatusOK, response)
}
// HandleGetLegalDisclaimer provides the legal disclaimer text
func (h *VerificationHandler) HandleGetLegalDisclaimer(c *gin.Context) {
disclaimer := `By selecting "I agree" below, I attest that I am eligible to participate
in this platform under applicable laws and regulations. I understand that false statements
may result in account suspension and potentially other consequences.
The verification process uses zero-knowledge proofs to verify my citizenship
without exposing my personal data.`
c.JSON(http.StatusOK, LegalDisclaimerResponse{
DisclaimerText: disclaimer,
})
}
// RegisterRoutes registers the verification routes with the provided router
func (h *VerificationHandler) RegisterRoutes(router *gin.Engine) {
// Add CORS OPTIONS handlers
router.OPTIONS("/verify", handleCORS)
router.OPTIONS("/verify/disclaimer", handleCORS)
// Add the main verification handlers
router.POST("/verify", h.corsMiddleware(h.HandleVerify))
router.GET("/verify/disclaimer", h.corsMiddleware(h.HandleGetLegalDisclaimer))
}
// corsMiddleware applies CORS headers to routes
func (h *VerificationHandler) corsMiddleware(handlerFunc gin.HandlerFunc) gin.HandlerFunc {
return func(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization")
handlerFunc(c)
}
}
// handleCORS is a standalone handler for OPTIONS requests
func handleCORS(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization")
c.Status(http.StatusOK)
}