183 lines
5.6 KiB
Go
183 lines
5.6 KiB
Go
![]() |
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)
|
||
|
}
|