diff --git a/docs/spec/components/schemas/UserParams.yaml b/docs/spec/components/schemas/UserParams.yaml index e41ffcf..731b136 100644 --- a/docs/spec/components/schemas/UserParams.yaml +++ b/docs/spec/components/schemas/UserParams.yaml @@ -7,10 +7,15 @@ allOf: properties: attributes: required: + - nullifier - age_lower_bound - nationality - sex properties: + nullifier: + type: string + example: "2fe34ac35a35d0672dd9759aaee5e052d978e41b062c9da33aea9914c3a386a3" + description: "User nullifier" age_lower_bound: type: integer example: 18 diff --git a/internal/data/pg/verify_users.go b/internal/data/pg/verify_users.go index 8af75c6..60b46de 100644 --- a/internal/data/pg/verify_users.go +++ b/internal/data/pg/verify_users.go @@ -153,3 +153,8 @@ func (q *VerifyUsersQ) FilterByInternalAID(aid string) data.VerifyUsersQ { q.sel = q.sel.Where(sq.Eq{"anonymous_id": aid}) return q } + +func (q *VerifyUsersQ) FilterByNullifier(nullifier string) data.VerifyUsersQ { + q.sel = q.sel.Where(sq.Eq{"nullifier": nullifier}) + return q +} diff --git a/internal/data/verify_users.go b/internal/data/verify_users.go index 7a2c7f5..fb372d5 100644 --- a/internal/data/verify_users.go +++ b/internal/data/verify_users.go @@ -35,4 +35,5 @@ type VerifyUsersQ interface { WhereHashID(userId string) VerifyUsersQ WhereCreatedAtLt(createdAt time.Time) VerifyUsersQ FilterByInternalAID(aid string) VerifyUsersQ + FilterByNullifier(nullifier string) VerifyUsersQ } diff --git a/internal/service/handlers/verification_callback.go b/internal/service/handlers/verification_callback.go index 1c90696..e6fbe15 100644 --- a/internal/service/handlers/verification_callback.go +++ b/internal/service/handlers/verification_callback.go @@ -1,6 +1,7 @@ package handlers import ( + "encoding/hex" "encoding/json" "errors" "github.com/ethereum/go-ethereum/log" @@ -11,6 +12,7 @@ import ( zk "github.com/rarimo/zkverifier-kit" "gitlab.com/distributed_lab/ape" "gitlab.com/distributed_lab/ape/problems" + "math/big" "net/http" "strconv" ) @@ -63,6 +65,16 @@ func VerificationCallback(w http.ResponseWriter, r *http.Request) { return } + nullifier, ok := new(big.Int).SetString(getter.Get(zk.Nullifier), 10) + if !ok { + Log(r).Error("failed to parse nullifier") + ape.RenderErr(w, problems.BadRequest(err)...) + return + } + var nullifierBytes [32]byte + nullifier.FillBytes(nullifierBytes[:]) + nullifierHex := hex.EncodeToString(nullifierBytes[:]) + userIDHash, err := helpers.ExtractEventData(getter) if err != nil { Log(r).WithError(err).Errorf("failed to extract user hash from event data") @@ -88,6 +100,22 @@ func VerificationCallback(w http.ResponseWriter, r *http.Request) { eventID = verifiedUser.EventId } + if verifiedUser.Uniqueness { + byNullifier, dbErr := VerifyUsersQ(r).FilterByNullifier(nullifierHex).Get() + if dbErr != nil { + Log(r).Error("Failed to get user by nullifier") + ape.RenderErr(w, problems.BadRequest(dbErr)...) + return + } + + if byNullifier != nil && byNullifier.UserIDHash != verifiedUser.UserIDHash { + Log(r).WithError(err).Errorf("User with this nullifier [%s] but a different userIDHash already exists", nullifierHex) + verifiedUser.Status = "failed_verification" + } else { + verifiedUser.Nullifier = nullifierHex + } + } + var verifyOpts = []zk.VerifyOption{ zk.WithProofSelectorValue(getter.Get(zk.Selector)), zk.WithAgeAbove(verifiedUser.AgeLowerBound), // if not required -1 diff --git a/internal/service/handlers/verification_callback_light.go b/internal/service/handlers/verification_callback_light.go index 4313aed..32f73b2 100644 --- a/internal/service/handlers/verification_callback_light.go +++ b/internal/service/handlers/verification_callback_light.go @@ -97,13 +97,6 @@ func VerificationSignatureCallback(w http.ResponseWriter, r *http.Request) { anonymousID.FillBytes(anonymousIDBytes[:]) anonymousIDHex := hex.EncodeToString(anonymousIDBytes[:]) - byAnonymousID, err := VerifyUsersQ(r).FilterByInternalAID(anonymousIDHex).Get() - if err != nil { - Log(r).Error("Failed to get user by anonymous_id") - ape.RenderErr(w, problems.BadRequest(err)...) - return - } - verifiedUser, err := VerifyUsersQ(r).WhereHashID(userIDHash).Get() if err != nil { Log(r).WithError(err).Errorf("failed to get user with userHashID [%s]", userIDHash) @@ -124,13 +117,43 @@ func VerificationSignatureCallback(w http.ResponseWriter, r *http.Request) { } verifiedUser.Status = "verified" - if byAnonymousID != nil && byAnonymousID.UserIDHash != verifiedUser.UserIDHash { - Log(r).WithError(err).Errorf("User with anonymous_id [%s] but a different userIDHash already exists", anonymousIDHex) - verifiedUser.Status = "failed_verification" - } else { - verifiedUser.Nullifier = nullifierHex - verifiedUser.AnonymousID = anonymousIDHex + + if verifiedUser.Uniqueness { + byAnonymousID, dbErr := VerifyUsersQ(r).FilterByInternalAID(anonymousIDHex).Get() + if dbErr != nil { + Log(r).Error("Failed to get user by anonymous_id") + ape.RenderErr(w, problems.BadRequest(dbErr)...) + return + } + + byNullifier, dbErr := VerifyUsersQ(r).FilterByNullifier(nullifierHex).Get() + if dbErr != nil { + Log(r).Error("Failed to get user by nullifier") + ape.RenderErr(w, problems.BadRequest(dbErr)...) + return + } + + if byAnonymousID != nil { + if byAnonymousID.UserIDHash != verifiedUser.UserIDHash { + Log(r).WithError(err).Errorf("User with anonymous_id [%s] but a different userIDHash already exists", anonymousIDHex) + verifiedUser.Status = "failed_verification" + return + } + } else { + verifiedUser.AnonymousID = anonymousIDHex + } + + if byNullifier != nil { + if byNullifier.UserIDHash != verifiedUser.UserIDHash { + Log(r).WithError(err).Errorf("User with nullifier [%s] but a different userIDHash already exists", nullifierHex) + verifiedUser.Status = "failed_verification" + return + } + } else { + verifiedUser.Nullifier = nullifierHex + } } + if eventData != userIDHash { Log(r).WithError(err).Errorf("failed to verify user: EventData from pub-signals [%s] != userIdHash from db [%s]", eventData, userIDHash) verifiedUser.Status = "failed_verification" diff --git a/internal/service/responses/get_user.go b/internal/service/responses/get_user.go index 2c470f2..ac3510c 100644 --- a/internal/service/responses/get_user.go +++ b/internal/service/responses/get_user.go @@ -13,6 +13,7 @@ func NewGetUsersByIdResponse(user data.VerifyUsers) resources.UserParamsRequest Type: resources.USER, }, Attributes: resources.UserParamsAttributes{ + Nullifier: user.Nullifier, AgeLowerBound: int32(user.AgeLowerBound), Nationality: user.Nationality, Sex: user.Sex, diff --git a/resources/model_user_params_attributes.go b/resources/model_user_params_attributes.go index 09f731a..9b0f87a 100644 --- a/resources/model_user_params_attributes.go +++ b/resources/model_user_params_attributes.go @@ -9,6 +9,8 @@ type UserParamsAttributes struct { AgeLowerBound int32 `json:"age_lower_bound"` // User nationality Nationality string `json:"nationality"` + // User nullifier + Nullifier string `json:"nullifier"` // User sex Sex string `json:"sex"` }