From 98b7784a089b78fba692beb2213c08a1d9cfdce8 Mon Sep 17 00:00:00 2001 From: chabanyknikita <92546152+chabanyknikita@users.noreply.github.com> Date: Mon, 14 Oct 2024 18:26:54 +0300 Subject: [PATCH] add anonymous_id and nullifier for uniqueness (#15) * add anonymous_id and nullifier for uniqueness * use unique index for: aid and nullifier instead of using unique field in table --- config.yaml | 4 +- .../assets/migrations/005_anonymousId.sql | 12 ++++ internal/data/pg/verify_users.go | 17 ++++-- internal/data/verify_users.go | 3 + .../handlers/verification_callback_light.go | 58 +++++++++++++++---- 5 files changed, 76 insertions(+), 18 deletions(-) create mode 100644 internal/assets/migrations/005_anonymousId.sql diff --git a/config.yaml b/config.yaml index 61b234e..8347eb3 100644 --- a/config.yaml +++ b/config.yaml @@ -27,6 +27,6 @@ signature_verification: pub_key: "04e29323ad356ab524fa5dbe3e490244e741b4d445ac7d2ee5f321556b3fda616bb9d2f2216fc27e099ab3019103cca872679e130629b2b90ea16cedb2b2136371" poseidonsmt_root_verifier: - rpc: rpc_url - contract: contract_address + rpc: "https://rpc.evm.mainnet.rarimo.com" + contract: "0xA25a197d26Cad659A8fFf7F268cA4F9e0283de03" request_timeout: 10s \ No newline at end of file diff --git a/internal/assets/migrations/005_anonymousId.sql b/internal/assets/migrations/005_anonymousId.sql new file mode 100644 index 0000000..f62991b --- /dev/null +++ b/internal/assets/migrations/005_anonymousId.sql @@ -0,0 +1,12 @@ +-- +migrate Up +ALTER TABLE verify_users ADD COLUMN anonymous_id TEXT DEFAULT ''; +ALTER TABLE verify_users ADD COLUMN nullifier TEXT DEFAULT ''; + +CREATE UNIQUE INDEX verify_users_anonymous_id_unique ON verify_users(anonymous_id) WHERE anonymous_id != ''; +CREATE UNIQUE INDEX verify_users_nullifier_unique ON verify_users(nullifier) WHERE nullifier != ''; +-- +migrate Down +ALTER TABLE verify_users DROP COLUMN anonymous_id; +ALTER TABLE verify_users DROP COLUMN nullifier; + +DROP INDEX verify_users_anonymous_id_unique; +DROP INDEX verify_users_nullifier_unique; \ No newline at end of file diff --git a/internal/data/pg/verify_users.go b/internal/data/pg/verify_users.go index 0c42979..8af75c6 100644 --- a/internal/data/pg/verify_users.go +++ b/internal/data/pg/verify_users.go @@ -80,6 +80,8 @@ func (q *VerifyUsersQ) Insert(VerifyUsers *data.VerifyUsers) error { "sex": VerifyUsers.Sex, "sex_enable": VerifyUsers.SexEnable, "nationality_enable": VerifyUsers.NationalityEnable, + "anonymous_id": VerifyUsers.AnonymousID, + "nullifier": VerifyUsers.Nullifier, }) if err = q.db.Exec(stmt); err != nil { @@ -93,10 +95,12 @@ func (q *VerifyUsersQ) Update(VerifyUsers *data.VerifyUsers) error { err := q.db.Exec( sq.Update(verifyUsersTableName). SetMap(map[string]interface{}{ - "status": VerifyUsers.Status, - "proof": VerifyUsers.Proof, - "sex": VerifyUsers.Sex, - "nationality": VerifyUsers.Nationality, + "status": VerifyUsers.Status, + "proof": VerifyUsers.Proof, + "sex": VerifyUsers.Sex, + "nationality": VerifyUsers.Nationality, + "anonymous_id": VerifyUsers.AnonymousID, + "nullifier": VerifyUsers.Nullifier, }). Where(sq.Eq{userIdColumnName: VerifyUsers.UserID}), ) @@ -144,3 +148,8 @@ func (q *VerifyUsersQ) WhereCreatedAtLt(createdAt time.Time) data.VerifyUsersQ { q.del = q.del.Where(sq.Lt{createdAtColumnName: &createdAt}) return q } + +func (q *VerifyUsersQ) FilterByInternalAID(aid string) data.VerifyUsersQ { + q.sel = q.sel.Where(sq.Eq{"anonymous_id": aid}) + return q +} diff --git a/internal/data/verify_users.go b/internal/data/verify_users.go index 984325f..7a2c7f5 100644 --- a/internal/data/verify_users.go +++ b/internal/data/verify_users.go @@ -17,6 +17,8 @@ type VerifyUsers struct { Sex string `db:"sex"` SexEnable bool `db:"sex_enable"` NationalityEnable bool `db:"nationality_enable"` + AnonymousID string `db:"anonymous_id"` + Nullifier string `db:"nullifier"` } type VerifyUsersQ interface { @@ -32,4 +34,5 @@ type VerifyUsersQ interface { WhereID(userId string) VerifyUsersQ WhereHashID(userId string) VerifyUsersQ WhereCreatedAtLt(createdAt time.Time) VerifyUsersQ + FilterByInternalAID(aid string) VerifyUsersQ } diff --git a/internal/service/handlers/verification_callback_light.go b/internal/service/handlers/verification_callback_light.go index 324880d..4313aed 100644 --- a/internal/service/handlers/verification_callback_light.go +++ b/internal/service/handlers/verification_callback_light.go @@ -54,18 +54,6 @@ func VerificationSignatureCallback(w http.ResponseWriter, r *http.Request) { return } - verifiedUser, err := VerifyUsersQ(r).WhereHashID(userIDHash).Get() - if err != nil { - Log(r).WithError(err).Errorf("failed to get user with userHashID [%s]", userIDHash) - ape.RenderErr(w, problems.BadRequest(err)...) - return - } - if verifiedUser == nil { - Log(r).Error("user not found or eventData != userHashID") - ape.RenderErr(w, problems.NotFound()) - return - } - userIDHashDecimal, ok := new(big.Int).SetString(pubSignals[10], 10) if !ok { Log(r).Error("failed to parse event data") @@ -89,6 +77,45 @@ func VerificationSignatureCallback(w http.ResponseWriter, r *http.Request) { return } + nullifier, ok := new(big.Int).SetString(pubSignals[0], 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[:]) + + anonymousID, ok := new(big.Int).SetString(pubSignals[11], 10) + if !ok { + Log(r).Error("failed to parse anonymous_id") + ape.RenderErr(w, problems.BadRequest(err)...) + return + } + var anonymousIDBytes [32]byte + 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) + ape.RenderErr(w, problems.BadRequest(err)...) + return + } + if verifiedUser == nil { + Log(r).Error("user not found or eventData != userHashID") + ape.RenderErr(w, problems.NotFound()) + return + } + if verifiedUser.Nationality == "" && pubSignals[6] != "0" { verifiedUser.Nationality = nationality } @@ -97,6 +124,13 @@ 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 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"