166 lines
5.0 KiB
Go
166 lines
5.0 KiB
Go
![]() |
package identity
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"log"
|
||
|
)
|
||
|
|
||
|
// UserVerificationStatus represents the current verification status of a user
|
||
|
type UserVerificationStatus string
|
||
|
|
||
|
const (
|
||
|
// StatusUnverified means the user has not been verified at all
|
||
|
StatusUnverified UserVerificationStatus = "Unverified"
|
||
|
|
||
|
// StatusVerified means the user's citizenship is verified but not necessarily eligible
|
||
|
StatusVerified UserVerificationStatus = "Verified"
|
||
|
|
||
|
// StatusFullyEligible means the user is both verified and eligible
|
||
|
StatusFullyEligible UserVerificationStatus = "Fully Eligible"
|
||
|
)
|
||
|
|
||
|
// VerificationResult holds the results of a verification attempt
|
||
|
type VerificationResult struct {
|
||
|
// Status indicates the verification level achieved
|
||
|
Status UserVerificationStatus
|
||
|
|
||
|
// CitizenshipVerified indicates if the citizenship verification passed
|
||
|
CitizenshipVerified bool
|
||
|
|
||
|
// EligibilityVerified indicates if the eligibility verification passed
|
||
|
EligibilityVerified bool
|
||
|
|
||
|
// Error contains any error that occurred during verification
|
||
|
Error error
|
||
|
}
|
||
|
|
||
|
// VerificationError defines a structured error for verification failures
|
||
|
type VerificationError struct {
|
||
|
Code string
|
||
|
Message string
|
||
|
}
|
||
|
|
||
|
// Common error codes
|
||
|
const (
|
||
|
ErrorCodeInvalidInput = "INVALID_INPUT"
|
||
|
ErrorCodeServiceUnavailable = "SERVICE_UNAVAILABLE"
|
||
|
ErrorCodeInvalidZKP = "INVALID_ZKP"
|
||
|
ErrorCodeProviderNotFound = "PROVIDER_NOT_FOUND"
|
||
|
)
|
||
|
|
||
|
// NewVerificationError creates a new verification error
|
||
|
func NewVerificationError(code, message string) *VerificationError {
|
||
|
return &VerificationError{
|
||
|
Code: code,
|
||
|
Message: message,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Error implements the error interface
|
||
|
func (e *VerificationError) Error() string {
|
||
|
return fmt.Sprintf("%s: %s", e.Code, e.Message)
|
||
|
}
|
||
|
|
||
|
// VerificationService manages the verification process
|
||
|
type VerificationService struct {
|
||
|
providers map[string]VerificationProvider
|
||
|
}
|
||
|
|
||
|
// NewVerificationService creates a new verification service
|
||
|
func NewVerificationService() *VerificationService {
|
||
|
return &VerificationService{
|
||
|
providers: make(map[string]VerificationProvider),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// RegisterProvider adds a verification provider to the service
|
||
|
func (s *VerificationService) RegisterProvider(provider VerificationProvider) {
|
||
|
country := provider.GetCountry()
|
||
|
s.providers[country] = provider
|
||
|
log.Printf("Registered verification provider for %s", country)
|
||
|
}
|
||
|
|
||
|
// VerifyUser verifies a user's identity and eligibility
|
||
|
func (s *VerificationService) VerifyUser(ctx context.Context, country string, userData map[string]string) VerificationResult {
|
||
|
result := VerificationResult{
|
||
|
Status: StatusUnverified,
|
||
|
}
|
||
|
|
||
|
// Validate input
|
||
|
if country == "" {
|
||
|
result.Error = NewVerificationError(ErrorCodeInvalidInput, "country is required")
|
||
|
return result
|
||
|
}
|
||
|
|
||
|
// Get the appropriate provider for the requested country
|
||
|
provider, exists := s.providers[country]
|
||
|
if !exists {
|
||
|
// If no provider is registered, get a default one
|
||
|
provider = GetVerificationProvider(country)
|
||
|
s.RegisterProvider(provider)
|
||
|
}
|
||
|
|
||
|
// Verify citizenship
|
||
|
citizenshipVerified, err := provider.VerifyCitizenship(ctx, userData)
|
||
|
if err != nil {
|
||
|
log.Printf("Citizenship verification failed: %v", err)
|
||
|
|
||
|
// Check for specific error types
|
||
|
if ve, ok := err.(*VerificationError); ok {
|
||
|
result.Error = ve
|
||
|
} else if errors.Is(err, context.DeadlineExceeded) {
|
||
|
result.Error = NewVerificationError(ErrorCodeServiceUnavailable, "verification service timed out")
|
||
|
} else if errors.Is(err, context.Canceled) {
|
||
|
result.Error = NewVerificationError(ErrorCodeServiceUnavailable, "verification request was canceled")
|
||
|
} else {
|
||
|
// Generic error handling
|
||
|
if errStr := err.Error(); len(errStr) > 0 {
|
||
|
if errStr == "invalid ZKP proof" {
|
||
|
result.Error = NewVerificationError(ErrorCodeInvalidZKP, errStr)
|
||
|
} else if errStr == "verification service unavailable" {
|
||
|
result.Error = NewVerificationError(ErrorCodeServiceUnavailable, errStr)
|
||
|
} else {
|
||
|
result.Error = NewVerificationError(ErrorCodeServiceUnavailable, errStr)
|
||
|
}
|
||
|
} else {
|
||
|
result.Error = NewVerificationError(ErrorCodeServiceUnavailable, "unknown verification error")
|
||
|
}
|
||
|
}
|
||
|
return result
|
||
|
}
|
||
|
|
||
|
result.CitizenshipVerified = citizenshipVerified
|
||
|
|
||
|
// If citizenship is verified, update the status
|
||
|
if citizenshipVerified {
|
||
|
result.Status = StatusVerified
|
||
|
|
||
|
// Verify eligibility
|
||
|
eligibilityVerified, err := provider.VerifyEligibility(ctx, userData)
|
||
|
if err != nil {
|
||
|
log.Printf("Eligibility verification failed: %v", err)
|
||
|
// Still keep the verified status, but note the eligibility failure
|
||
|
if ve, ok := err.(*VerificationError); ok {
|
||
|
result.Error = ve
|
||
|
} else {
|
||
|
result.Error = NewVerificationError(ErrorCodeInvalidInput, err.Error())
|
||
|
}
|
||
|
return result
|
||
|
}
|
||
|
|
||
|
result.EligibilityVerified = eligibilityVerified
|
||
|
|
||
|
// If both citizenship and eligibility are verified, user is fully eligible
|
||
|
if eligibilityVerified {
|
||
|
result.Status = StatusFullyEligible
|
||
|
}
|
||
|
}
|
||
|
|
||
|
log.Printf("Verification completed for %s: Status=%s, Citizenship=%v, Eligibility=%v",
|
||
|
country, result.Status, result.CitizenshipVerified, result.EligibilityVerified)
|
||
|
|
||
|
return result
|
||
|
}
|