Skip to content

Commit

Permalink
Refactor passport verification to share legacy and new logic
Browse files Browse the repository at this point in the history
  • Loading branch information
violog committed Jul 16, 2024
1 parent d00bace commit c8cefee
Show file tree
Hide file tree
Showing 13 changed files with 124 additions and 245 deletions.
18 changes: 18 additions & 0 deletions docs/spec/components/schemas/CreateBalance.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
allOf:
- $ref: '#/components/schemas/CreateBalanceKey'
- type: object
x-go-is-request: true
required:
- attributes
properties:
attributes:
type: object
properties:
referred_by:
type: string
description: |
Referral code from the link. Supply it to create the active balance,
otherwise disabled balance is created, and it can be activated later.
Disabled balance is only allowed to verify passport and get.
example: "rCx18MZ4"
13 changes: 13 additions & 0 deletions docs/spec/components/schemas/CreateBalanceKey.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
type: object
required:
- id
- type
properties:
id:
type: string
description: Nullifier of the points owner
example: "0x123...abc"
pattern: '^0x[0-9a-fA-F]{64}$'
type:
type: string
enum: [ create_balance ]
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@ post:
- Points balance
summary: Verify passport
description: |
Verify passport with ZKP, fulfilling the event.
Verify passport to unlock event claiming and get reward.
One passport can't be verified twice.
There are two verification flows:
1) Legacy flow is done through Query ZK-proof
2) New flow is done via JWT, received from Auth service after providing ZK-proof
Some events will be automatically claimed in case if balance is active.
operationId: verifyPassport
parameters:
- $ref: '#/components/parameters/pathNullifier'
Expand Down Expand Up @@ -42,14 +48,20 @@ post:
$ref: '#/components/responses/invalidParameter'
401:
$ref: '#/components/responses/invalidAuth'
403:
description: Invalid signature
content:
application/vnd.api+json:
schema:
$ref: '#/components/schemas/Errors'
404:
description: Balance not exists.
description: Balance not exists
content:
application/vnd.api+json:
schema:
$ref: '#/components/schemas/Errors'
409:
description: Passport already verified or event absent for user.
description: Passport already verified or anonymous ID exists
content:
application/vnd.api+json:
schema:
Expand Down

This file was deleted.

2 changes: 1 addition & 1 deletion internal/service/handlers/activate_balance.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func ActivateBalance(w http.ResponseWriter, r *http.Request) {
// Adds a friend event for the referrer. If the event
// is inactive, then nothing happens. If active, the
// fulfilled event is added and, if possible, the event claimed
if err = addEventForReferrer(r, evTypeRef, *balance); err != nil {
if err = addEventForReferrer(r, *evTypeRef, *balance); err != nil {
return fmt.Errorf("add event for referrer: %w", err)
}

Expand Down
31 changes: 16 additions & 15 deletions internal/service/handlers/verify_passport.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ import (
"gitlab.com/distributed_lab/ape/problems"
)

// VerifyPassport handler processes 3 different flows:
// - Old passport verification with proof for the current release
// - New passport verification with JWT for the future
// - Legacy joining program logic when the client fails to generate query proof
func VerifyPassport(w http.ResponseWriter, r *http.Request) {
req, err := requests.NewVerifyPassport(r)
if err != nil {
Expand Down Expand Up @@ -77,7 +81,8 @@ func VerifyPassport(w http.ResponseWriter, r *http.Request) {
return
}

var sharedHash *string
// UserClaims(r)[0] will not panic because of authorization validation
sharedHash := UserClaims(r)[0].SharedHash
if proof != nil {
sig := zk.PubSignalGetter{
ProofType: zk.GeorgianPassport,
Expand Down Expand Up @@ -182,10 +187,7 @@ func getAndVerifyBalanceEligibility(
if balance == nil {
Log(r).Debug("Balance absent")
return nil, append(errs, problems.NotFound())

}

// for withdrawal and joining program
if proof == nil {
return balance, nil
}
Expand All @@ -206,13 +208,16 @@ func getAndVerifyBalanceEligibility(
}

// doPassportScanUpdates performs all the necessary updates when the passport
// scan proof is provided. This logic is shared between verification and
// withdrawal handlers.
// scan proof is provided
func doPassportScanUpdates(r *http.Request, balance data.Balance, anonymousID string, sharedHash *string) error {
err := updateBalanceVerification(r, balance, anonymousID, sharedHash)
if err != nil {
return fmt.Errorf("update balance country: %w", err)
}
// must not auto-claim or add referral events for disabled balance
if balance.ReferredBy == nil {
return nil
}

// Fulfill passport scan event for user if event active
// Event can be automatically claimed if auto-claim is enabled
Expand All @@ -238,7 +243,7 @@ func doPassportScanUpdates(r *http.Request, balance data.Balance, anonymousID st
// could not be claimed. And now that user has scanned the passport,
// it is necessary to claim events for user's friends if auto-claim
// is enabled
if err = claimReferralSpecificEvents(r, evTypeRef, balance.Nullifier); err != nil {
if err = claimReferralSpecificEvents(r, *evTypeRef, balance.Nullifier); err != nil {
return fmt.Errorf("failed to claim referral specific events: %w", err)
}

Expand All @@ -250,7 +255,7 @@ func doPassportScanUpdates(r *http.Request, balance data.Balance, anonymousID st
// Adds a friend event for the referrer. If the event
// is inactive, then nothing happens. If active, the
// fulfilled event is added and, if possible, the event claimed
if err = addEventForReferrer(r, evTypeRef, balance); err != nil {
if err = addEventForReferrer(r, *evTypeRef, balance); err != nil {
return fmt.Errorf("add event for referrer: %w", err)
}

Expand Down Expand Up @@ -322,9 +327,9 @@ func fulfillOrClaimPassportScanEvent(r *http.Request, balance data.Balance) erro
}

// evTypeRef must not be nil
func claimReferralSpecificEvents(r *http.Request, evTypeRef *models.EventType, nullifier string) error {
func claimReferralSpecificEvents(r *http.Request, evTypeRef models.EventType, nullifier string) error {
if !evTypeRef.AutoClaim {
Log(r).Debugf("auto claim for referral specific disabled")
Log(r).Debugf("Auto claim for referral specific disabled")
return nil
}

Expand Down Expand Up @@ -406,11 +411,7 @@ func claimBeReferredEvent(r *http.Request, balance data.Balance) error {
return nil
}

func addEventForReferrer(r *http.Request, evTypeRef *models.EventType, balance data.Balance) error {
if evTypeRef == nil {
return nil
}

func addEventForReferrer(r *http.Request, evTypeRef models.EventType, balance data.Balance) error {
// ReferredBy always non-nil because of the previous logic
referral, err := ReferralsQ(r).Get(*balance.ReferredBy)
if err != nil {
Expand Down
126 changes: 0 additions & 126 deletions internal/service/handlers/verify_passport_v2.go

This file was deleted.

9 changes: 3 additions & 6 deletions internal/service/requests/verify_passport.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ var (
nullifierRegexp = regexp.MustCompile("^0x[0-9a-fA-F]{64}$")
hex32bRegexp = regexp.MustCompile("^[0-9a-f]{64}$")
// endpoint is hardcoded to reuse handlers.VerifyPassport
verifyPassportPathRegexp = regexp.MustCompile("^/integrations/geo-points-svc/v1/public/balances/0x[0-9a-fA-F]{64}/verifypassport$")
joinProgramPathRegexp = regexp.MustCompile("^/integrations/geo-points-svc/v1/public/balances/0x[0-9a-fA-F]{64}/join_program$")
joinProgramPathRegexp = regexp.MustCompile("^/integrations/geo-points-svc/v1/public/balances/0x[0-9a-fA-F]{64}/join_program$")
)

func NewVerifyPassport(r *http.Request) (req resources.VerifyPassportRequest, err error) {
Expand All @@ -43,10 +42,8 @@ func NewVerifyPassport(r *http.Request) (req resources.VerifyPassportRequest, er
"data/type": val.Validate(req.Data.Type,
val.Required,
val.In(resources.VERIFY_PASSPORT)),
"data/attributes/anonymous_id": val.Validate(attr.AnonymousId, val.Required, val.Match(hex32bRegexp)),
"data/attributes/proof": val.Validate(attr.Proof,
val.When(verifyPassportPathRegexp.MatchString(r.URL.Path), val.Required),
val.When(joinProgramPathRegexp.MatchString(r.URL.Path), val.Nil)),
"data/attributes/anonymous_id": val.Validate(attr.AnonymousId, val.Required, val.Match(hex32bRegexp)),
"data/attributes/proof": val.Validate(attr.Proof, val.When(joinProgramPathRegexp.MatchString(r.URL.Path), val.Nil)),
"data/attributes/proof/proof": val.Validate(proof.Proof, val.When(attr.Proof != nil, val.Required)),
"data/attributes/proof/pub_signals": val.Validate(proof.PubSignals, val.When(attr.Proof != nil, val.Required, val.Length(24, 24))),
}.Filter()
Expand Down
Loading

0 comments on commit c8cefee

Please sign in to comment.