From 43644d6c358f1b1952c2b60134f69c10680309d5 Mon Sep 17 00:00:00 2001 From: Marcelo Salloum dos Santos Date: Wed, 31 Jan 2024 17:10:47 -0800 Subject: [PATCH 01/12] Sync main into develop (#169) * Hotfix/improve error logs for debugging (#125) ### What Add the client_domain when logging the message where the user with the {phone_number, client_domain} pair could not be found. Also, updated a log from error to warn. ### Why Better debuggability. * [SDP-1022] Hotfix: update Vibrant Assist's `client_domain` (#126) ### What Update client_domain on Vibrant Assist from api.vibrantapp.com to vibrantapp.com. ### Why It was incorrect. --------- Co-authored-by: Marwen Abid From c01b50e028194cc1c2d1353ffb8f79a952d35f14 Mon Sep 17 00:00:00 2001 From: Marcelo Salloum Date: Mon, 5 Feb 2024 12:15:08 -0800 Subject: [PATCH 02/12] Attempt to fix intermittent error in `transactionsubmission/utils/utils_test.go:47`, like https://github.com/stellar/stellar-disbursement-platform-backend/actions/runs/7790057714/job/21243057987?pr=172 --- internal/transactionsubmission/utils/utils_test.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/internal/transactionsubmission/utils/utils_test.go b/internal/transactionsubmission/utils/utils_test.go index 4725aee5c..faee83e2d 100644 --- a/internal/transactionsubmission/utils/utils_test.go +++ b/internal/transactionsubmission/utils/utils_test.go @@ -2,8 +2,10 @@ package utils import ( "context" - "math/rand" + "crypto/rand" + "math/big" "testing" + "time" "github.com/stellar/stellar-disbursement-platform-backend/internal/db" "github.com/stellar/stellar-disbursement-platform-backend/internal/db/dbtest" @@ -17,7 +19,9 @@ func TestAdvisoryLockAndRelease(t *testing.T) { defer dbt.Close() // Creates a database pool - lockKey := rand.Intn(100000) + randBigInt, err := rand.Int(rand.Reader, big.NewInt(90000)) + require.NoError(t, err) + lockKey := int(randBigInt.Int64()) dbConnectionPool1, err := db.OpenDBConnectionPool(dbt.DSN) require.NoError(t, err) @@ -38,7 +42,11 @@ func TestAdvisoryLockAndRelease(t *testing.T) { require.False(t, lockAcquired2) // Close the original connection which releases the lock + sqlQuery := "SELECT pg_advisory_unlock($1)" + _, err = dbConnectionPool1.ExecContext(ctx, sqlQuery, lockKey) + require.NoError(t, err) dbConnectionPool1.Close() + time.Sleep(200 * time.Millisecond) // try to acquire the lock again lockAcquired3, err := AcquireAdvisoryLock(ctx, dbConnectionPool2, lockKey) From 7d6817e5c04c7590ca6b76fa7863390a813c1da6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cec=C3=ADlia=20Rom=C3=A3o?= Date: Wed, 14 Feb 2024 10:13:37 -0300 Subject: [PATCH 03/12] SDP-575: [data] Improve receiver verification error messaging for disbursement instructions (#178) What Clear error message about which receiver (line in CSV & phone number / internal id) that has a mis-matching verification. Why If the user doesn't know which record is causing the error, they won't know where to check to find the original value. --- internal/data/disbursement_instructions.go | 22 ++++++++----- .../data/disbursement_instructions_test.go | 31 ++++++++++++++++--- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/internal/data/disbursement_instructions.go b/internal/data/disbursement_instructions.go index 775c9e09b..373794949 100644 --- a/internal/data/disbursement_instructions.go +++ b/internal/data/disbursement_instructions.go @@ -25,6 +25,11 @@ type DisbursementInstructionModel struct { disbursementModel *DisbursementModel } +type InstructionLine struct { + line int + disbursementInstruction *DisbursementInstruction +} + const MaxInstructionsPerDisbursement = 10000 // TODO: update this number with load testing results [SDP-524] // NewDisbursementInstructionModel creates a new DisbursementInstructionModel. @@ -85,9 +90,12 @@ func (di DisbursementInstructionModel) ProcessAll(ctx context.Context, userID st receiverMap[receiver.PhoneNumber] = receiver } - instructionMap := make(map[string]*DisbursementInstruction) - for _, instruction := range instructions { - instructionMap[instruction.Phone] = instruction + instructionMap := make(map[string]InstructionLine) + for line, instruction := range instructions { + instructionMap[instruction.Phone] = InstructionLine{ + line: line + 1, + disbursementInstruction: instruction, + } } for _, instruction := range instructions { @@ -126,7 +134,7 @@ func (di DisbursementInstructionModel) ProcessAll(ctx context.Context, userID st if !verificationExists { verificationInsert := ReceiverVerificationInsert{ ReceiverID: receiver.ID, - VerificationValue: instruction.VerificationValue, + VerificationValue: instruction.disbursementInstruction.VerificationValue, VerificationField: disbursement.VerificationField, } hashedVerification, insertError := di.receiverVerificationModel.Insert(ctx, dbTx, verificationInsert) @@ -140,11 +148,11 @@ func (di DisbursementInstructionModel) ProcessAll(ctx context.Context, userID st } } else { - if verified := CompareVerificationValue(verification.HashedValue, instruction.VerificationValue); !verified { + if verified := CompareVerificationValue(verification.HashedValue, instruction.disbursementInstruction.VerificationValue); !verified { if verification.ConfirmedAt != nil { - return fmt.Errorf("%w: receiver verification for %s doesn't match", ErrReceiverVerificationMismatch, receiver.PhoneNumber) + return fmt.Errorf("%w: receiver verification for %s doesn't match. Check line %d on CSV file - Internal ID %s.", ErrReceiverVerificationMismatch, receiver.PhoneNumber, instruction.line, instruction.disbursementInstruction.ID) } - err = di.receiverVerificationModel.UpdateVerificationValue(ctx, dbTx, verification.ReceiverID, verification.VerificationField, instruction.VerificationValue) + err = di.receiverVerificationModel.UpdateVerificationValue(ctx, dbTx, verification.ReceiverID, verification.VerificationField, instruction.disbursementInstruction.VerificationValue) if err != nil { return fmt.Errorf("error updating receiver verification for disbursement id %s: %w", disbursement.ID, err) diff --git a/internal/data/disbursement_instructions_test.go b/internal/data/disbursement_instructions_test.go index fa04b253b..c3235caae 100644 --- a/internal/data/disbursement_instructions_test.go +++ b/internal/data/disbursement_instructions_test.go @@ -235,11 +235,34 @@ func Test_DisbursementInstructionModel_ProcessAll(t *testing.T) { }) t.Run("failure - Confirmed Verification Value not matching", func(t *testing.T) { + instruction4 := DisbursementInstruction{ + Phone: "+380-12-345-674", + Amount: "100.04", + ID: "123456784", + VerificationValue: "1990-01-04", + ExternalPaymentId: &externalPaymentID, + } + + instruction5 := DisbursementInstruction{ + Phone: "+380-12-345-675", + Amount: "100.05", + ID: "123456785", + VerificationValue: "1990-01-05", + ExternalPaymentId: &externalPaymentID, + } + + instruction6 := DisbursementInstruction{ + Phone: "+380-12-345-676", + Amount: "100.06", + ID: "123456786", + VerificationValue: "1990-01-06", + ExternalPaymentId: &externalPaymentID, + } // process instructions for the first time err := di.ProcessAll(ctx, "user-id", instructions, disbursement, disbursementUpdate, MaxInstructionsPerDisbursement) require.NoError(t, err) - receivers, err := di.receiverModel.GetByPhoneNumbers(ctx, dbConnectionPool, []string{instruction1.Phone, instruction2.Phone, instruction3.Phone}) + receivers, err := di.receiverModel.GetByPhoneNumbers(ctx, dbConnectionPool, []string{instruction1.Phone, instruction2.Phone, instruction3.Phone, instruction4.Phone, instruction5.Phone, instruction6.Phone}) require.NoError(t, err) receiversMap := make(map[string]*Receiver) for _, receiver := range receivers { @@ -247,13 +270,13 @@ func Test_DisbursementInstructionModel_ProcessAll(t *testing.T) { } // confirm a verification - ConfirmVerificationForRecipient(t, ctx, dbConnectionPool, receiversMap[instruction1.Phone].ID) + ConfirmVerificationForRecipient(t, ctx, dbConnectionPool, receiversMap[instruction3.Phone].ID) // process instructions with mismatched verification values - instruction1.VerificationValue = "1990-01-07" + instruction3.VerificationValue = "1990-01-07" err = di.ProcessAll(ctx, "user-id", instructions, disbursement, disbursementUpdate, MaxInstructionsPerDisbursement) require.Error(t, err) - assert.EqualError(t, err, "running atomic function in RunInTransactionWithResult: receiver verification mismatch: receiver verification for +380-12-345-671 doesn't match") + assert.EqualError(t, err, "running atomic function in RunInTransactionWithResult: receiver verification mismatch: receiver verification for +380-12-345-673 doesn't match. Check line 3 on CSV file - Internal ID 123456783.") }) } From 0f336cd60e628c3e6f8e94ecf2e5f528a6b39cf3 Mon Sep 17 00:00:00 2001 From: Caio Teixeira Date: Thu, 15 Feb 2024 13:48:42 -0300 Subject: [PATCH 04/12] fix: trim spaces from issuers' public key when creating assets (#185) What This PR ensures that there are no spaces on the issuers' public key to avoid typos that can lead to validation errors. Why We need to ensure there are no spaces on the address. --- internal/serve/httphandler/assets_handler.go | 1 + .../serve/httphandler/assets_handler_test.go | 42 ++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/internal/serve/httphandler/assets_handler.go b/internal/serve/httphandler/assets_handler.go index 3a610c5d8..aead7fe38 100644 --- a/internal/serve/httphandler/assets_handler.go +++ b/internal/serve/httphandler/assets_handler.go @@ -77,6 +77,7 @@ func (c AssetsHandler) CreateAsset(w http.ResponseWriter, r *http.Request) { v.Check(assetRequest.Code != "", "code", "code is required") if strings.ToUpper(assetRequest.Code) != stellarNativeAssetCode { v.Check(assetRequest.Issuer != "", "issuer", "issuer is required") + assetRequest.Issuer = strings.TrimSpace(assetRequest.Issuer) v.Check(strkey.IsValidEd25519PublicKey(assetRequest.Issuer), "issuer", "issuer is invalid") } diff --git a/internal/serve/httphandler/assets_handler_test.go b/internal/serve/httphandler/assets_handler_test.go index 62330d0a8..1a177e063 100644 --- a/internal/serve/httphandler/assets_handler_test.go +++ b/internal/serve/httphandler/assets_handler_test.go @@ -386,8 +386,6 @@ func Test_AssetHandler_CreateAsset(t *testing.T) { }) t.Run("failed creating asset, error adding asset trustline", func(t *testing.T) { - ctx := context.Background() - data.DeleteAllAssetFixtures(t, ctx, dbConnectionPool) tx, err := txnbuild.NewTransaction( @@ -469,6 +467,46 @@ func Test_AssetHandler_CreateAsset(t *testing.T) { assert.JSONEq(t, `{"error": "Cannot create new asset"}`, string(respBody)) }) + t.Run("ensures that issuers public key value has spaces trimmed", func(t *testing.T) { + data.DeleteAllAssetFixtures(t, ctx, dbConnectionPool) + + getEntries := log.DefaultLogger.StartTest(log.WarnLevel) + + horizonClientMock. + On("AccountDetail", horizonclient.AccountRequest{ + AccountID: distributionKP.Address(), + }). + Return(horizon.Account{ + AccountID: distributionKP.Address(), + Sequence: 123, + Balances: []horizon.Balance{ + { + Balance: "100", + Asset: base.Asset{ + Code: code, + Issuer: issuer, + }, + }, + }, + }, nil). + Once() + + rr := httptest.NewRecorder() + + requestBody, _ := json.Marshal(AssetRequest{code, fmt.Sprintf(" %s ", issuer)}) + + req, _ := http.NewRequest(http.MethodPost, "/assets", strings.NewReader(string(requestBody))) + http.HandlerFunc(handler.CreateAsset).ServeHTTP(rr, req) + + resp := rr.Result() + + assert.Equal(t, http.StatusCreated, resp.StatusCode) + + entries := getEntries() + assert.Len(t, entries, 2) + assert.Equal(t, "not adding trustline for the asset USDT:GBHC5ADV2XYITXCYC5F6X6BM2OYTYHV4ZU2JF6QWJORJQE2O7RKH2LAQ because it already exists", entries[0].Message) + }) + horizonClientMock.AssertExpectations(t) signatureService.AssertExpectations(t) } From a904ad57fd562c779a6699ad921ecacc6c1f3e12 Mon Sep 17 00:00:00 2001 From: Marcelo Salloum dos Santos Date: Thu, 15 Feb 2024 16:05:53 -0800 Subject: [PATCH 05/12] [SDP-1089] Add rate-limiters both in the application and the k8s deployment (#195) ### What Implement in-memory rate-limiting in the server, sensitive to the pair {IP, endpoint}. It's configured to a max of 10 requests every 20 seconds, which translates to a maximum of 30 requests per minute per IP, segregated per endpoint. Also, add rate-limit to the k8s Ingress manifest. ### Why For increased security against bots. --- .github/workflows/ci.yml | 2 +- go.list | 1 + go.mod | 1 + go.sum | 2 ++ helmchart/sdp/values.yaml | 4 ++++ internal/serve/serve.go | 14 ++++++++++++++ internal/serve/serve_test.go | 34 ++++++++++++++++++++++++++++++++++ 7 files changed, 57 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ebd241ce5..475e3e434 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -115,7 +115,7 @@ jobs: go-version: 1.19 - name: Run tests - run: go test -race -coverpkg=./... -coverprofile=c.out ./... + run: go test -race -timeout 3m -coverpkg=./... -coverprofile=c.out ./... - name: Validate Test Coverage Threshold env: diff --git a/go.list b/go.list index c3a89dfa0..70bba9160 100644 --- a/go.list +++ b/go.list @@ -70,6 +70,7 @@ github.com/gin-contrib/sse v0.1.0 github.com/gin-gonic/gin v1.8.1 github.com/go-chi/chi v4.1.2+incompatible github.com/go-chi/chi/v5 v5.0.10 +github.com/go-chi/httprate v0.8.0 github.com/go-errors/errors v1.5.1 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 diff --git a/go.mod b/go.mod index 50c189701..f2e9c693f 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/getsentry/sentry-go v0.23.0 github.com/go-chi/chi v4.1.2+incompatible github.com/go-chi/chi/v5 v5.0.10 + github.com/go-chi/httprate v0.8.0 github.com/gocarina/gocsv v0.0.0-20230616125104-99d496ca653d github.com/golang-jwt/jwt/v4 v4.5.0 github.com/google/uuid v1.3.1 diff --git a/go.sum b/go.sum index 33915b2c5..9dbc75d3d 100644 --- a/go.sum +++ b/go.sum @@ -90,6 +90,8 @@ github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyN github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/httprate v0.8.0 h1:CyKng28yhGnlGXH9EDGC/Qizj29afJQSNW15W/yj34o= +github.com/go-chi/httprate v0.8.0/go.mod h1:6GOYBSwnpra4CQfAKXu8sQZg+nZ0M1g9QnyFvxrAB8A= github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= diff --git a/helmchart/sdp/values.yaml b/helmchart/sdp/values.yaml index 8cf9efdbd..31ad51b56 100644 --- a/helmchart/sdp/values.yaml +++ b/helmchart/sdp/values.yaml @@ -202,6 +202,8 @@ sdp: className: "nginx" annotations: nginx.ingress.kubernetes.io/custom-response-headers: "X-XSS-Protection: 1; mode=block || X-Frame-Options: DENY || X-Content-Type-Options: nosniff || Strict-Transport-Security: max-age=31536000; includeSubDomains" + nginx.ingress.kubernetes.io/limit-rpm: "120" + nginx.ingress.kubernetes.io/limit-burst-multiplier: "5" tls: - hosts: - '{{ include "sdp.domain" . }}' @@ -345,6 +347,8 @@ anchorPlatform: className: "nginx" annotations: nginx.ingress.kubernetes.io/custom-response-headers: "X-XSS-Protection: 1; mode=block || X-Frame-Options: DENY || X-Content-Type-Options: nosniff || Strict-Transport-Security: max-age=31536000; includeSubDomains" + nginx.ingress.kubernetes.io/limit-rpm: "120" + nginx.ingress.kubernetes.io/limit-burst-multiplier: "5" tls: - hosts: - '{{ include "sdp.ap.domain" . }}' diff --git a/internal/serve/serve.go b/internal/serve/serve.go index 11e89caf3..f72b0c441 100644 --- a/internal/serve/serve.go +++ b/internal/serve/serve.go @@ -9,6 +9,7 @@ import ( "github.com/go-chi/chi/v5" chimiddleware "github.com/go-chi/chi/v5/middleware" + "github.com/go-chi/httprate" "github.com/stellar/go/clients/horizonclient" "github.com/stellar/go/network" supporthttp "github.com/stellar/go/support/http" @@ -207,17 +208,30 @@ func Serve(opts ServeOptions, httpServer HTTPServerInterface) error { return nil } +const ( + rateLimitPer20Seconds = 10 + rateLimitWindow = 20 * time.Second +) + func handleHTTP(o ServeOptions) *chi.Mux { mux := chi.NewMux() // Middleware mux.Use(middleware.CorsMiddleware(o.CorsAllowedOrigins)) + // Rate limits requests made with the pair . + mux.Use(httprate.Limit( + rateLimitPer20Seconds, + rateLimitWindow, + httprate.WithKeyFuncs(httprate.KeyByIP, httprate.KeyByEndpoint), + )) mux.Use(chimiddleware.RequestID) mux.Use(chimiddleware.RealIP) mux.Use(supporthttp.LoggingMiddleware) mux.Use(middleware.RecoverHandler) mux.Use(middleware.MetricsRequestHandler(o.MonitorService)) mux.Use(middleware.CSPMiddleware()) + mux.Use(chimiddleware.CleanPath) + mux.Use(chimiddleware.Compress(5)) // Create a route along /static that will serve contents from the ./public_files folder. staticFileServer(mux, publicfiles.PublicFiles) diff --git a/internal/serve/serve_test.go b/internal/serve/serve_test.go index 85aa756cf..5e84f19c4 100644 --- a/internal/serve/serve_test.go +++ b/internal/serve/serve_test.go @@ -407,6 +407,40 @@ func Test_handleHTTP_authenticatedEndpoints(t *testing.T) { } } +func Test_handleHTTP_rateLimit(t *testing.T) { + dbt := dbtest.Open(t) + defer dbt.Close() + serveOptions := getServeOptionsForTests(t, dbt.DSN) + defer serveOptions.dbConnectionPool.Close() + + handlerMux := handleHTTP(serveOptions) + + // 1. The first n requests to /health should return 200 + // 2. the n+1 request to /health should return 429 + // 3. an additional request to another endpoint should return something other than 429 + expectedEndpoints := make([]string, rateLimitPer20Seconds) + expectedResponseCodes := make([]int, rateLimitPer20Seconds) + for i := 0; i < rateLimitPer20Seconds; i++ { + expectedResponseCodes[i] = http.StatusOK + expectedEndpoints[i] = "/health" + } + expectedResponseCodes = append(expectedResponseCodes, http.StatusTooManyRequests, http.StatusNotFound) + expectedEndpoints = append(expectedEndpoints, "/health", "/not-found") + require.Len(t, expectedResponseCodes, rateLimitPer20Seconds+2) + require.Len(t, expectedEndpoints, rateLimitPer20Seconds+2) + + actualResponseCodes := make([]int, len(expectedResponseCodes)) + for i := 0; i < len(expectedResponseCodes); i++ { + req := httptest.NewRequest(http.MethodGet, expectedEndpoints[i], nil) + w := httptest.NewRecorder() + handlerMux.ServeHTTP(w, req) + resp := w.Result() + actualResponseCodes[i] = resp.StatusCode + } + + require.Equal(t, expectedResponseCodes, actualResponseCodes) +} + func Test_createAuthManager(t *testing.T) { dbt := dbtest.OpenWithoutMigrations(t) defer dbt.Close() From a48d788c3022fbf457085145430d964d72a929ae Mon Sep 17 00:00:00 2001 From: Marcelo Salloum dos Santos Date: Fri, 16 Feb 2024 10:31:27 -0800 Subject: [PATCH 06/12] [Chore] attempt to fix recurring false-negative in tests by walking away from a reflection comparison in `assets_handler_test.go` (#181) ### What Attempt to fix recurring false-negative in the test Test_AssetHandler_submitChangeTrustTransaction_makeSurePreconditionsAreSetAsExpected by walking away from a reflection comparison, which was done by using mock's `.Run` instead of `.MatchedBy` to assert the timebounds. ### Why Errors like [this](https://github.com/stellar/stellar-disbursement-platform-backend/actions/runs/7792837546/job/21251914245#step:5:209) are false negatives that could be caused by reflection with complex objects. By using Run rather than mock.MatchedBy, we avoid the reflection. --- .../serve/httphandler/assets_handler_test.go | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/internal/serve/httphandler/assets_handler_test.go b/internal/serve/httphandler/assets_handler_test.go index 1a177e063..f1eadfc2c 100644 --- a/internal/serve/httphandler/assets_handler_test.go +++ b/internal/serve/httphandler/assets_handler_test.go @@ -1360,17 +1360,17 @@ func Test_AssetHandler_submitChangeTrustTransaction_makeSurePreconditionsAreSetA distributionKP := keypair.MustRandom() // matchPreconditionsTimeboundsFn is a function meant to be used with mock.MatchedBy to check that the preconditions are set as expected. - matchPreconditionsTimeboundsFn := func(expectedPreconditions txnbuild.Preconditions) func(actualTx *txnbuild.Transaction) bool { - require := require.New(t) + assertExpectedPreconditionsWithTimeboundsTolerance := func(expectedTx *txnbuild.Transaction, actualTxIndex int) func(args mock.Arguments) { + return func(args mock.Arguments) { + actualTx, ok := args.Get(int(actualTxIndex)).(*txnbuild.Transaction) + require.True(t, ok) - return func(actualTx *txnbuild.Transaction) bool { - actualPreconditions := actualTx.ToXDR().Preconditions() + expectedPreconditions := expectedTx.ToXDR().Preconditions() expectedTime := time.Unix(int64(expectedPreconditions.TimeBounds.MaxTime), 0).UTC() + actualPreconditions := actualTx.ToXDR().Preconditions() actualTime := time.Unix(int64(actualPreconditions.TimeBounds.MaxTime), 0).UTC() - require.WithinDuration(expectedTime, actualTime, 2*time.Second) - require.Equal(expectedPreconditions.TimeBounds.MinTime, int64(actualPreconditions.TimeBounds.MinTime)) - - return true + require.WithinDuration(t, expectedTime, actualTime, 5*time.Second) + require.Equal(t, expectedPreconditions.TimeBounds.MinTime, actualPreconditions.TimeBounds.MinTime) } } @@ -1421,13 +1421,14 @@ func Test_AssetHandler_submitChangeTrustTransaction_makeSurePreconditionsAreSetA require.NoError(t, err) mocks.SignatureService. - On("SignStellarTransaction", ctx, mock.MatchedBy(matchPreconditionsTimeboundsFn(defaultPreconditions)), distributionKP.Address()). + On("SignStellarTransaction", ctx, mock.AnythingOfType("*txnbuild.Transaction"), distributionKP.Address()). + Run(assertExpectedPreconditionsWithTimeboundsTolerance(signedTx, 1)). Return(signedTx, nil). Once() - defer mocks.SignatureService.AssertExpectations(t) mocks.HorizonClientMock. - On("SubmitTransactionWithOptions", mock.MatchedBy(matchPreconditionsTimeboundsFn(defaultPreconditions)), horizonclient.SubmitTxOpts{SkipMemoRequiredCheck: true}). + On("SubmitTransactionWithOptions", mock.AnythingOfType("*txnbuild.Transaction"), horizonclient.SubmitTxOpts{SkipMemoRequiredCheck: true}). + Run(assertExpectedPreconditionsWithTimeboundsTolerance(signedTx, 0)). Return(horizon.Transaction{}, nil). Once() defer mocks.HorizonClientMock.AssertExpectations(t) @@ -1450,14 +1451,15 @@ func Test_AssetHandler_submitChangeTrustTransaction_makeSurePreconditionsAreSetA require.NoError(t, err) mocks.SignatureService. - On("SignStellarTransaction", ctx, mock.MatchedBy(matchPreconditionsTimeboundsFn(newPreconditions)), distributionKP.Address()). + On("SignStellarTransaction", ctx, mock.AnythingOfType("*txnbuild.Transaction"), distributionKP.Address()). + Run(assertExpectedPreconditionsWithTimeboundsTolerance(signedTx, 1)). Return(signedTx, nil). Once() - defer mocks.SignatureService.AssertExpectations(t) mocks.HorizonClientMock. - On("SubmitTransactionWithOptions", mock.MatchedBy(matchPreconditionsTimeboundsFn(newPreconditions)), horizonclient.SubmitTxOpts{SkipMemoRequiredCheck: true}). + On("SubmitTransactionWithOptions", mock.AnythingOfType("*txnbuild.Transaction"), horizonclient.SubmitTxOpts{SkipMemoRequiredCheck: true}). Return(horizon.Transaction{}, nil). + Run(assertExpectedPreconditionsWithTimeboundsTolerance(signedTx, 0)). Once() defer mocks.HorizonClientMock.AssertExpectations(t) From a1795825ef20fe20c9672a4160ee56385faffb04 Mon Sep 17 00:00:00 2001 From: Marcelo Salloum dos Santos Date: Wed, 21 Feb 2024 08:59:55 -0800 Subject: [PATCH 07/12] [Chore] Bump go version and make other project maintenance changes (#196) ### What - Bump go version from 1.19 (released 2022-08-02) to 1.22 (released 2024-02-06). - Updated the version of some github actions - Updated `slices` dependency to use the one that's now part of the Go SDK. - Removed two unused methods - Apply `deadcode` to the CI, to make sure there's no unused code in the project. ### Why We were falling behind on the version upgrade. The other bullets are also project maintenance. --- .../anchor_platform_integration_check.yml | 2 +- .github/workflows/ci.yml | 43 ++++++++++++------- .../workflows/docker_image_public_release.yml | 4 +- .github/workflows/e2e_integration_test.yml | 2 +- Dockerfile | 2 +- cmd/serve_test.go | 2 +- go.mod | 2 +- go.sum | 42 ++++++++++++++++++ .../anchorplatform/platform_api_service.go | 2 +- internal/data/assets.go | 2 +- internal/data/disbursement_instructions.go | 3 +- .../data/disbursement_instructions_test.go | 2 +- internal/data/receiver_verification.go | 1 - internal/message/main.go | 3 +- internal/serve/httperror/httperror.go | 7 --- internal/serve/serve_test.go | 7 +-- internal/serve/validators/query_validator.go | 2 +- .../send_receiver_wallets_invite_service.go | 2 +- .../setup_wallets_for_network_service_test.go | 10 ++--- internal/statistics/calculate_statistics.go | 1 - internal/transactionsubmission/horizon.go | 2 +- .../store/transaction_state_machine.go | 2 +- .../transaction_worker.go | 2 +- .../transactionsubmission/utils/errors.go | 2 +- .../utils/test_helpers.go | 38 ---------------- 25 files changed, 97 insertions(+), 90 deletions(-) delete mode 100644 internal/transactionsubmission/utils/test_helpers.go diff --git a/.github/workflows/anchor_platform_integration_check.yml b/.github/workflows/anchor_platform_integration_check.yml index 1d405b934..b75624305 100644 --- a/.github/workflows/anchor_platform_integration_check.yml +++ b/.github/workflows/anchor_platform_integration_check.yml @@ -22,7 +22,7 @@ jobs: SEP10_SIGNING_PRIVATE_KEY: ${{ vars.SEP10_SIGNING_PRIVATE_KEY }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Run Docker Compose for SDP and Anchor Platform working-directory: dev diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 475e3e434..893377c10 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,33 +16,46 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: - go-version: 1.19 + go-version: 1.22 - name: golangci-lint - uses: golangci/golangci-lint-action@08e2f20817b15149a52b5b3ebe7de50aff2ba8c5 # version v3.4.0 + uses: golangci/golangci-lint-action@3cfe3a4abbb849e10058ce4af15d205b6da42804 # version v4.0.0 with: - version: v1.52.2 # this is the golangci-lint version + version: v1.56.2 # this is the golangci-lint version args: --timeout 5m0s - name: Run ./gomod.sh run: ./gomod.sh - - name: Install github.com/nishanths/exhaustive - run: go install github.com/nishanths/exhaustive/cmd/exhaustive@latest + - name: Install github.com/nishanths/exhaustive and golang.org/x/tools/cmd/deadcode@latest + run: | + go install github.com/nishanths/exhaustive/cmd/exhaustive@latest + go install golang.org/x/tools/cmd/deadcode@latest - - name: Run exhaustive + - name: Run `exhaustive` run: exhaustive -default-signifies-exhaustive ./... + - name: Run `deadcode` + run: | + output=$(deadcode -test ./...) + if [[ -n "$output" ]]; then + echo "🚨 Deadcode found:" + echo "$output" + exit 1 + else + echo "✅ No deadcode found" + fi + check-helm-readme: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install NodeJs uses: actions/setup-node@v2 @@ -70,12 +83,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: - go-version: 1.19 + go-version: 1.22 - name: Build Project run: go build ./... @@ -107,12 +120,12 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: - go-version: 1.19 + go-version: 1.22 - name: Run tests run: go test -race -timeout 3m -coverpkg=./... -coverprofile=c.out ./... diff --git a/.github/workflows/docker_image_public_release.yml b/.github/workflows/docker_image_public_release.yml index 999568c25..495e35483 100644 --- a/.github/workflows/docker_image_public_release.yml +++ b/.github/workflows/docker_image_public_release.yml @@ -43,7 +43,7 @@ jobs: exit 1 fi - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Login to DockerHub uses: docker/login-action@v2.2.0 @@ -69,7 +69,7 @@ jobs: - anchor_platform_integration_check - e2e_integration_test steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Login to DockerHub uses: docker/login-action@v2.2.0 diff --git a/.github/workflows/e2e_integration_test.yml b/.github/workflows/e2e_integration_test.yml index 7f3a9e61d..f64b48099 100644 --- a/.github/workflows/e2e_integration_test.yml +++ b/.github/workflows/e2e_integration_test.yml @@ -26,7 +26,7 @@ jobs: SEP10_SIGNING_PRIVATE_KEY: ${{ vars.SEP10_SIGNING_PRIVATE_KEY }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Cleanup data working-directory: internal/integrationtests diff --git a/Dockerfile b/Dockerfile index 7f7132bfb..522d7bb64 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ # To push: # make docker-push -FROM golang:1.20-bullseye as build +FROM golang:1.22-bullseye as build ARG GIT_COMMIT WORKDIR /src/stellar-disbursement-platform diff --git a/cmd/serve_test.go b/cmd/serve_test.go index 905058283..54f2e668b 100644 --- a/cmd/serve_test.go +++ b/cmd/serve_test.go @@ -156,7 +156,7 @@ func Test_serve(t *testing.T) { mServer.On("StartMetricsServe", serveMetricOpts, mock.AnythingOfType("*serve.HTTPServer")).Once() mServer.On("StartServe", serveOpts, mock.AnythingOfType("*serve.HTTPServer")).Once() mServer. - On("GetSchedulerJobRegistrars", mock.AnythingOfType("*context.emptyCtx"), serveOpts, schedulerOptions, mock.Anything). + On("GetSchedulerJobRegistrars", mock.AnythingOfType("context.backgroundCtx"), serveOpts, schedulerOptions, mock.Anything). Return([]scheduler.SchedulerJobRegisterOption{}, nil). Once() mServer.wg.Add(1) diff --git a/go.mod b/go.mod index f2e9c693f..a99a55ad9 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/stellar/stellar-disbursement-platform-backend -go 1.19 +go 1.22 require ( github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 diff --git a/go.sum b/go.sum index 9dbc75d3d..40254d298 100644 --- a/go.sum +++ b/go.sum @@ -43,7 +43,9 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f h1:zvClvFQwU++UpIUBGC8YmDlfhUrweEy1R1Fj1gu5iIM= +github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= +github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go v1.45.26 h1:PJ2NJNY5N/yeobLYe1Y+xLdavBi67ZI8gvph6ftwVCg= @@ -80,10 +82,13 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/gavv/monotime v0.0.0-20161010190848-47d58efa6955 h1:gmtGRvSexPU4B1T/yYo0sLOKzER1YT+b4kPxPpm0Ty4= +github.com/gavv/monotime v0.0.0-20161010190848-47d58efa6955/go.mod h1:vmp8DIyckQMXOPl0AQVHt+7n5h7Gb7hS6CUydiV8QeA= github.com/getsentry/sentry-go v0.23.0 h1:dn+QRCeJv4pPt9OjVXiMcGIBIefaTJPw/h0bZWO05nE= github.com/getsentry/sentry-go v0.23.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec= @@ -102,8 +107,11 @@ github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpj github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU= +github.com/gobuffalo/logger v1.0.6/go.mod h1:J31TBEHR1QLV2683OXTAItYIg8pv2JMHnF/quuAbMjs= github.com/gobuffalo/packd v1.0.2 h1:Yg523YqnOxGIWCp69W12yYBKsoChwI7mtu6ceM9Bwfw= +github.com/gobuffalo/packd v1.0.2/go.mod h1:sUc61tDqGMXON80zpKGp92lDb86Km28jfvX7IAyxFT8= github.com/gobuffalo/packr/v2 v2.8.3 h1:xE1yzvnO56cUC0sTpKR3DIbxZgB54AftTFMhB2XEWlY= +github.com/gobuffalo/packr/v2 v2.8.3/go.mod h1:0SahksCVcx4IMnigTjiFuyldmTrdTctXsOdiU5KwbKc= github.com/gocarina/gocsv v0.0.0-20230616125104-99d496ca653d h1:KbPOUXFUDJxwZ04vbmDOc3yuruGvVO+LOa7cVER3yWw= github.com/gocarina/gocsv v0.0.0-20230616125104-99d496ca653d/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= @@ -152,7 +160,9 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v0.0.0-20160401233042-9235644dd9e5 h1:oERTZ1buOUYlpmKaqlO5fYmz8cZ1rYu5DieJzF4ZVmU= +github.com/google/go-querystring v0.0.0-20160401233042-9235644dd9e5/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -176,6 +186,7 @@ github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8 github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= github.com/guregu/null v4.0.0+incompatible h1:4zw0ckM7ECd6FNNddc3Fu4aty9nTlpkkzH7dPn4/4Gw= +github.com/guregu/null v4.0.0+incompatible/go.mod h1:ePGpQaN9cw0tj45IR5E5ehMvsFlLlQZAkkOXZurJ3NM= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -183,9 +194,11 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk= +github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jarcoal/httpmock v0.0.0-20161210151336-4442edb3db31 h1:Aw95BEvxJ3K6o9GGv5ppCd1P8hkeIeEJ30FO+OhOJpM= +github.com/jarcoal/httpmock v0.0.0-20161210151336-4442edb3db31/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -195,11 +208,14 @@ github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Cc github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw= +github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= +github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -220,24 +236,33 @@ github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GW github.com/manucorporat/sse v0.0.0-20160126180136-ee05b128a739 h1:ykXz+pRRTibcSjG1yRhpdSHInF8yZY/mfn+Rz2Nd1rE= github.com/manucorporat/sse v0.0.0-20160126180136-ee05b128a739/go.mod h1:zUx1mhth20V3VKgL5jbd1BSQcW4Fy6Qs4PZvQwRFwzM= github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI= +github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc= github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY= +github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI= github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI= +github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= +github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moul/http2curl v0.0.0-20161031194548-4e24498b31db h1:eZgFHVkk9uOTaOQLC6tgjkzdp7Ays8eEVecBcfHZlJQ= +github.com/moul/http2curl v0.0.0-20161031194548-4e24498b31db/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/nyaruka/phonenumbers v1.1.8 h1:mjFu85FeoH2Wy18aOMUvxqi1GgAqiQSJsa/cCC5yu2s= github.com/nyaruka/phonenumbers v1.1.8/go.mod h1:DC7jZd321FqUe+qWSNcHi10tyIyGNXGcNbfkPvdp1Vs= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= @@ -245,6 +270,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= +github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg= github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -256,6 +282,7 @@ github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rubenv/sql-migrate v1.5.2 h1:bMDqOnrJVV/6JQgQ/MxOpU+AdO8uzYYA/TxFUBzFtS0= @@ -268,6 +295,7 @@ github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWR github.com/segmentio/go-loggly v0.5.1-0.20171222203950-eb91657e62b2 h1:S4OC0+OBKz6mJnzuHioeEat74PuQ4Sgvbf8eus695sc= github.com/segmentio/go-loggly v0.5.1-0.20171222203950-eb91657e62b2/go.mod h1:8zLRYR5npGjaOXgPSKat5+oOh+UHd8OdbS18iqX9F6Y= github.com/sergi/go-diff v0.0.0-20161205080420-83532ca1c1ca h1:oR/RycYTFTVXzND5r4FdsvbnBn0HJXSVeNAnwaTXRwk= +github.com/sergi/go-diff v0.0.0-20161205080420-83532ca1c1ca/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= @@ -305,14 +333,23 @@ github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSW github.com/twilio/twilio-go v1.11.0 h1:ixO2DfAV4c0Yza0Tom5F5ZZB8WUbigiFc9wD84vbYnc= github.com/twilio/twilio-go v1.11.0/go.mod h1:tdnfQ5TjbewoAu4lf9bMsGvfuJ/QU9gYuv9yx3TSIXU= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.40.0 h1:CRq/00MfruPGFLTQKY8b+8SfdK60TxNztjRMnH0t1Yc= +github.com/valyala/fasthttp v1.40.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= github.com/xdrpp/goxdr v0.1.1 h1:E1B2c6E8eYhOVyd7yEpOyopzTPirUeF6mVOfXfGyJyc= +github.com/xdrpp/goxdr v0.1.1/go.mod h1:dXo1scL/l6s7iME1gxHWo2XCppbHEKZS7m/KyYWkNzA= github.com/xeipuuv/gojsonpointer v0.0.0-20151027082146-e0fe6f683076 h1:KM4T3G70MiR+JtqplcYkNVoNz7pDwYaBxWBXQK804So= +github.com/xeipuuv/gojsonpointer v0.0.0-20151027082146-e0fe6f683076/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20150808065054-e02fc20de94c h1:XZWnr3bsDQWAZg4Ne+cPoXRPILrNlPNQfxBuwLl43is= +github.com/xeipuuv/gojsonreference v0.0.0-20150808065054-e02fc20de94c/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v0.0.0-20161231055540-f06f290571ce h1:cVSRGH8cOveJNwFEEZLXtB+XMnRqKLjUP6V/ZFYQCXI= +github.com/xeipuuv/gojsonschema v0.0.0-20161231055540-f06f290571ce/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/yalp/jsonpath v0.0.0-20150812003900-31a79c7593bb h1:06WAhQa+mYv7BiOk13B/ywyTlkoE/S7uu6TBKU6FHnE= +github.com/yalp/jsonpath v0.0.0-20150812003900-31a79c7593bb/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= github.com/yudai/gojsondiff v0.0.0-20170107030110-7b1b7adf999d h1:yJIizrfO599ot2kQ6Af1enICnwBD3XoxgX3MrMwot2M= +github.com/yudai/gojsondiff v0.0.0-20170107030110-7b1b7adf999d/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= github.com/yudai/golcs v0.0.0-20150405163532-d1c525dea8ce h1:888GrqRxabUce7lj4OaoShPxodm3kXOMpSa85wdYzfY= +github.com/yudai/golcs v0.0.0-20150405163532-d1c525dea8ce/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -482,6 +519,7 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= +golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -645,16 +683,20 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/gavv/httpexpect.v1 v1.0.0-20170111145843-40724cf1e4a0 h1:r5ptJ1tBxVAeqw4CrYWhXIMr0SybY3CDHuIbCg5CFVw= +gopkg.in/gavv/httpexpect.v1 v1.0.0-20170111145843-40724cf1e4a0/go.mod h1:WtiW9ZA1LdaWqtQRo1VbIL/v4XZ8NDta+O/kSpGgVek= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tylerb/graceful.v1 v1.2.15 h1:1JmOyhKqAyX3BgTXMI84LwT6FOJ4tP2N9e2kwTCM0nQ= gopkg.in/tylerb/graceful.v1 v1.2.15/go.mod h1:yBhekWvR20ACXVObSSdD3u6S9DeSylanL2PAbAC/uJ8= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/anchorplatform/platform_api_service.go b/internal/anchorplatform/platform_api_service.go index d9536608e..eb5e508b4 100644 --- a/internal/anchorplatform/platform_api_service.go +++ b/internal/anchorplatform/platform_api_service.go @@ -6,10 +6,10 @@ import ( "fmt" "net/http" "net/url" + "slices" "strings" "github.com/gorilla/schema" - "golang.org/x/exp/slices" "github.com/stellar/stellar-disbursement-platform-backend/internal/serve/httpclient" "github.com/stellar/stellar-disbursement-platform-backend/internal/utils" diff --git a/internal/data/assets.go b/internal/data/assets.go index be13e2454..d8ea9d946 100644 --- a/internal/data/assets.go +++ b/internal/data/assets.go @@ -5,11 +5,11 @@ import ( "database/sql" "errors" "fmt" + "slices" "strings" "time" "github.com/lib/pq" - "golang.org/x/exp/slices" "github.com/stellar/go/protocols/horizon/base" "github.com/stellar/stellar-disbursement-platform-backend/internal/db" diff --git a/internal/data/disbursement_instructions.go b/internal/data/disbursement_instructions.go index 373794949..bbfd9d753 100644 --- a/internal/data/disbursement_instructions.go +++ b/internal/data/disbursement_instructions.go @@ -150,10 +150,9 @@ func (di DisbursementInstructionModel) ProcessAll(ctx context.Context, userID st } else { if verified := CompareVerificationValue(verification.HashedValue, instruction.disbursementInstruction.VerificationValue); !verified { if verification.ConfirmedAt != nil { - return fmt.Errorf("%w: receiver verification for %s doesn't match. Check line %d on CSV file - Internal ID %s.", ErrReceiverVerificationMismatch, receiver.PhoneNumber, instruction.line, instruction.disbursementInstruction.ID) + return fmt.Errorf("%w: receiver verification for %s doesn't match. Check line %d on CSV file - Internal ID %s", ErrReceiverVerificationMismatch, receiver.PhoneNumber, instruction.line, instruction.disbursementInstruction.ID) } err = di.receiverVerificationModel.UpdateVerificationValue(ctx, dbTx, verification.ReceiverID, verification.VerificationField, instruction.disbursementInstruction.VerificationValue) - if err != nil { return fmt.Errorf("error updating receiver verification for disbursement id %s: %w", disbursement.ID, err) } diff --git a/internal/data/disbursement_instructions_test.go b/internal/data/disbursement_instructions_test.go index c3235caae..dc7ebe43f 100644 --- a/internal/data/disbursement_instructions_test.go +++ b/internal/data/disbursement_instructions_test.go @@ -276,7 +276,7 @@ func Test_DisbursementInstructionModel_ProcessAll(t *testing.T) { instruction3.VerificationValue = "1990-01-07" err = di.ProcessAll(ctx, "user-id", instructions, disbursement, disbursementUpdate, MaxInstructionsPerDisbursement) require.Error(t, err) - assert.EqualError(t, err, "running atomic function in RunInTransactionWithResult: receiver verification mismatch: receiver verification for +380-12-345-673 doesn't match. Check line 3 on CSV file - Internal ID 123456783.") + assert.EqualError(t, err, "running atomic function in RunInTransactionWithResult: receiver verification mismatch: receiver verification for +380-12-345-673 doesn't match. Check line 3 on CSV file - Internal ID 123456783") }) } diff --git a/internal/data/receiver_verification.go b/internal/data/receiver_verification.go index f660cca32..4a8f8f3d8 100644 --- a/internal/data/receiver_verification.go +++ b/internal/data/receiver_verification.go @@ -169,7 +169,6 @@ func (m *ReceiverVerificationModel) UpdateVerificationValue(ctx context.Context, ` _, err = sqlExec.ExecContext(ctx, query, hashedValue, receiverID, verificationField) - if err != nil { return fmt.Errorf("error updating receiver verification: %w", err) } diff --git a/internal/message/main.go b/internal/message/main.go index d34fd68c1..9ed073d5e 100644 --- a/internal/message/main.go +++ b/internal/message/main.go @@ -2,9 +2,8 @@ package message import ( "fmt" + "slices" "strings" - - "golang.org/x/exp/slices" ) type MessengerType string diff --git a/internal/serve/httperror/httperror.go b/internal/serve/httperror/httperror.go index 64594d4cf..39f1d4096 100644 --- a/internal/serve/httperror/httperror.go +++ b/internal/serve/httperror/httperror.go @@ -91,13 +91,6 @@ func BadRequest(msg string, originalErr error, extras map[string]interface{}) *H return NewHTTPError(http.StatusBadRequest, msg, originalErr, extras) } -func NotImplemented(msg string, originalErr error, extras map[string]interface{}) *HTTPError { - if msg == "" { - msg = "This feature is not implemented yet." - } - return NewHTTPError(http.StatusNotImplemented, msg, originalErr, extras) -} - func Unauthorized(msg string, originalErr error, extras map[string]interface{}) *HTTPError { if msg == "" { msg = "Not authorized." diff --git a/internal/serve/serve_test.go b/internal/serve/serve_test.go index 5e84f19c4..c507da73e 100644 --- a/internal/serve/serve_test.go +++ b/internal/serve/serve_test.go @@ -14,6 +14,10 @@ import ( "github.com/stellar/go/network" supporthttp "github.com/stellar/go/support/http" "github.com/stellar/go/support/log" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/stellar/stellar-disbursement-platform-backend/internal/crashtracker" "github.com/stellar/stellar-disbursement-platform-backend/internal/data" "github.com/stellar/stellar-disbursement-platform-backend/internal/db" @@ -22,9 +26,6 @@ import ( "github.com/stellar/stellar-disbursement-platform-backend/internal/monitor" publicfiles "github.com/stellar/stellar-disbursement-platform-backend/internal/serve/publicfiles" "github.com/stellar/stellar-disbursement-platform-backend/stellar-auth/pkg/auth" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" ) type mockHTTPServer struct { diff --git a/internal/serve/validators/query_validator.go b/internal/serve/validators/query_validator.go index 89b229201..68e5cbb7b 100644 --- a/internal/serve/validators/query_validator.go +++ b/internal/serve/validators/query_validator.go @@ -2,12 +2,12 @@ package validators import ( "net/http" + "slices" "strconv" "strings" "time" "github.com/stellar/stellar-disbursement-platform-backend/internal/data" - "golang.org/x/exp/slices" ) type QueryValidator struct { diff --git a/internal/services/send_receiver_wallets_invite_service.go b/internal/services/send_receiver_wallets_invite_service.go index 611d2e3f3..d38a8a613 100644 --- a/internal/services/send_receiver_wallets_invite_service.go +++ b/internal/services/send_receiver_wallets_invite_service.go @@ -6,6 +6,7 @@ import ( "html/template" "net/url" "path" + "slices" "strings" "time" @@ -16,7 +17,6 @@ import ( "github.com/stellar/stellar-disbursement-platform-backend/internal/db" "github.com/stellar/stellar-disbursement-platform-backend/internal/message" "github.com/stellar/stellar-disbursement-platform-backend/internal/utils" - "golang.org/x/exp/slices" ) type SendReceiverWalletInviteService struct { diff --git a/internal/services/setup_wallets_for_network_service_test.go b/internal/services/setup_wallets_for_network_service_test.go index f476bfbd4..dc8e1eeee 100644 --- a/internal/services/setup_wallets_for_network_service_test.go +++ b/internal/services/setup_wallets_for_network_service_test.go @@ -100,7 +100,7 @@ func Test_SetupWalletsForProperNetwork(t *testing.T) { { Name: "Vibrant Assist", Homepage: "https://vibrantapp.com/vibrant-assist", - DeepLinkSchema: "https://aidpubnet.netlify.app", + DeepLinkSchema: "https://vibrantapp.com/sdp-dev", SEP10ClientDomain: "vibrantapp.com", }, { @@ -131,7 +131,7 @@ func Test_SetupWalletsForProperNetwork(t *testing.T) { assert.Equal(t, "Vibrant Assist", wallets[1].Name) assert.Equal(t, "https://vibrantapp.com/vibrant-assist", wallets[1].Homepage) assert.Equal(t, "vibrantapp.com", wallets[1].SEP10ClientDomain) - assert.Equal(t, "https://aidpubnet.netlify.app", wallets[1].DeepLinkSchema) + assert.Equal(t, "https://vibrantapp.com/sdp-dev", wallets[1].DeepLinkSchema) expectedLogs := []string{ "updating/inserting wallets for the 'pubnet' network", @@ -141,7 +141,7 @@ func Test_SetupWalletsForProperNetwork(t *testing.T) { "SEP-10 Client Domain: www.walletbyboss.com", "Name: Vibrant Assist", "Homepage: https://vibrantapp.com/vibrant-assist", - "Deep Link Schema: https://aidpubnet.netlify.app", + "Deep Link Schema: https://vibrantapp.com/sdp-dev", "SEP-10 Client Domain: vibrantapp.com", } @@ -163,7 +163,7 @@ func Test_SetupWalletsForProperNetwork(t *testing.T) { { Name: "Vibrant Assist", Homepage: "https://vibrantapp.com/vibrant-assist", - DeepLinkSchema: "https://aidpubnet.netlify.app", + DeepLinkSchema: "https://vibrantapp.com/sdp-dev", SEP10ClientDomain: "vibrantapp.com", Assets: []data.Asset{ { @@ -252,7 +252,7 @@ func Test_SetupWalletsForProperNetwork(t *testing.T) { "* XLM", "Name: Vibrant Assist", "Homepage: https://vibrantapp.com/vibrant-assist", - "Deep Link Schema: https://aidpubnet.netlify.app", + "Deep Link Schema: https://vibrantapp.com/sdp-dev", "SEP-10 Client Domain: vibrantapp.com", "Assets:", "* USDC - GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", diff --git a/internal/statistics/calculate_statistics.go b/internal/statistics/calculate_statistics.go index 2e84a6a84..062685096 100644 --- a/internal/statistics/calculate_statistics.go +++ b/internal/statistics/calculate_statistics.go @@ -225,7 +225,6 @@ func getReceiverWalletsStats(ctx context.Context, sqlExec db.SQLExecuter, disbur ) err = rows.Scan(&status, &count) - if err != nil { return nil, fmt.Errorf("attributing values to rows: %w", err) } diff --git a/internal/transactionsubmission/horizon.go b/internal/transactionsubmission/horizon.go index ada823ec1..9777627d2 100644 --- a/internal/transactionsubmission/horizon.go +++ b/internal/transactionsubmission/horizon.go @@ -4,12 +4,12 @@ import ( "context" "errors" "fmt" + "slices" "github.com/stellar/go/clients/horizonclient" "github.com/stellar/go/keypair" "github.com/stellar/go/support/log" "github.com/stellar/go/txnbuild" - "golang.org/x/exp/slices" "github.com/stellar/stellar-disbursement-platform-backend/internal/transactionsubmission/engine" "github.com/stellar/stellar-disbursement-platform-backend/internal/transactionsubmission/utils" diff --git a/internal/transactionsubmission/store/transaction_state_machine.go b/internal/transactionsubmission/store/transaction_state_machine.go index dd036c3e3..92734e546 100644 --- a/internal/transactionsubmission/store/transaction_state_machine.go +++ b/internal/transactionsubmission/store/transaction_state_machine.go @@ -2,9 +2,9 @@ package store import ( "fmt" + "slices" "github.com/stellar/stellar-disbursement-platform-backend/internal/data" - "golang.org/x/exp/slices" ) type TransactionStatus string diff --git a/internal/transactionsubmission/transaction_worker.go b/internal/transactionsubmission/transaction_worker.go index 5019b921d..ed7740edb 100644 --- a/internal/transactionsubmission/transaction_worker.go +++ b/internal/transactionsubmission/transaction_worker.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "slices" "strconv" "strings" @@ -12,7 +13,6 @@ import ( "github.com/stellar/go/strkey" "github.com/stellar/go/support/log" "github.com/stellar/go/txnbuild" - "golang.org/x/exp/slices" "github.com/stellar/stellar-disbursement-platform-backend/internal/crashtracker" "github.com/stellar/stellar-disbursement-platform-backend/internal/db" diff --git a/internal/transactionsubmission/utils/errors.go b/internal/transactionsubmission/utils/errors.go index 68a14fa21..bc8ef21fa 100644 --- a/internal/transactionsubmission/utils/errors.go +++ b/internal/transactionsubmission/utils/errors.go @@ -3,6 +3,7 @@ package utils import ( "fmt" "net/http" + "slices" "strings" "github.com/stellar/go/clients/horizonclient" @@ -10,7 +11,6 @@ import ( "github.com/stellar/go/support/log" "github.com/stellar/go/support/render/problem" sdpUtils "github.com/stellar/stellar-disbursement-platform-backend/internal/utils" - "golang.org/x/exp/slices" ) // TransactionStatusUpdateError is an error that occurs when failing to update a transaction's status. diff --git a/internal/transactionsubmission/utils/test_helpers.go b/internal/transactionsubmission/utils/test_helpers.go deleted file mode 100644 index b67d4d618..000000000 --- a/internal/transactionsubmission/utils/test_helpers.go +++ /dev/null @@ -1,38 +0,0 @@ -package utils - -import ( - "sync" - "testing" - "time" -) - -// WaitUntilWaitGroupIsDoneOrTimeout is a helper function that waits for a wait group to finish or times out after a -// given duration. This is used for test purposes. -func WaitUntilWaitGroupIsDoneOrTimeout(t *testing.T, wg *sync.WaitGroup, timeout time.Duration, shouldTimeout bool, assertFn func()) { - t.Helper() - - ch := make(chan struct{}) - go func() { - wg.Wait() - close(ch) - }() - - select { - case <-ch: - if shouldTimeout { - t.Fatal("wait group finished, but we expected it to timeout") - } else { - t.Log("wait group finished as expected") - } - case <-time.After(timeout): - if shouldTimeout { - t.Log("wait group correctly timed out") - } else { - t.Fatal("wait group did not finish within the expected time") - } - } - - if assertFn != nil { - assertFn() - } -} From ac3c909a2b148a709970f9132fad77aa0c4b50cf Mon Sep 17 00:00:00 2001 From: Caio Teixeira Date: Thu, 29 Feb 2024 10:25:07 -0300 Subject: [PATCH 08/12] [SDP-1106] data/httphandler: upsert receivers' verification info (#205) What Now we upsert the receivers' verification info. Note: Only NOT confirmed verification info will be updated. Why The caller will be able to update/insert these entries. --- internal/data/receiver_verification.go | 48 +++++++++-- internal/data/receiver_verification_test.go | 86 +++++++++++++++++++ .../httphandler/update_receiver_handler.go | 9 +- .../update_receiver_handler_test.go | 76 ++++++++++++++++ 4 files changed, 206 insertions(+), 13 deletions(-) diff --git a/internal/data/receiver_verification.go b/internal/data/receiver_verification.go index 4a8f8f3d8..474529cab 100644 --- a/internal/data/receiver_verification.go +++ b/internal/data/receiver_verification.go @@ -16,14 +16,14 @@ import ( ) type ReceiverVerification struct { - ReceiverID string `db:"receiver_id"` - VerificationField VerificationField `db:"verification_field"` - HashedValue string `db:"hashed_value"` - Attempts int `db:"attempts"` - CreatedAt time.Time `db:"created_at"` - UpdatedAt time.Time `db:"updated_at"` - ConfirmedAt *time.Time `db:"confirmed_at"` - FailedAt *time.Time `db:"failed_at"` + ReceiverID string `json:"receiver_id" db:"receiver_id"` + VerificationField VerificationField `json:"verification_field" db:"verification_field"` + HashedValue string `json:"hashed_value" db:"hashed_value"` + Attempts int `json:"attempts" db:"attempts"` + CreatedAt time.Time `json:"created_at" db:"created_at"` + UpdatedAt time.Time `json:"updated_at" db:"updated_at"` + ConfirmedAt *time.Time `json:"confirmed_at" db:"confirmed_at"` + FailedAt *time.Time `json:"failed_at" db:"failed_at"` } type ReceiverVerificationModel struct { @@ -176,7 +176,37 @@ func (m *ReceiverVerificationModel) UpdateVerificationValue(ctx context.Context, return nil } -// UpdateVerificationValue updates the hashed value of a receiver verification. +// UpsertVerificationValue creates or updates the receiver's verification. In case the verification exists and it's already confirmed by the receiver +// it's not updated. +func (m *ReceiverVerificationModel) UpsertVerificationValue(ctx context.Context, sqlExec db.SQLExecuter, receiverID string, verificationField VerificationField, verificationValue string) error { + log.Ctx(ctx).Infof("Calling UpsertVerificationValue for receiver %s and verification field %s", receiverID, verificationField) + hashedValue, err := HashVerificationValue(verificationValue) + if err != nil { + return fmt.Errorf("hashing verification value: %w", err) + } + + query := ` + INSERT INTO receiver_verifications + (receiver_id, verification_field, hashed_value) + VALUES + ($1, $2, $3) + ON CONFLICT (receiver_id, verification_field) + DO UPDATE SET + hashed_value = EXCLUDED.hashed_value, + updated_at = NOW() + WHERE + receiver_verifications.confirmed_at IS NULL + ` + + _, err = sqlExec.ExecContext(ctx, query, receiverID, verificationField, hashedValue) + if err != nil { + return fmt.Errorf("upserting receiver verification: %w", err) + } + + return nil +} + +// UpdateReceiverVerification updates the attempts, confirmed_at, and failed_at values of a receiver verification. func (m *ReceiverVerificationModel) UpdateReceiverVerification(ctx context.Context, receiverVerification ReceiverVerification, sqlExec db.SQLExecuter) error { query := ` UPDATE diff --git a/internal/data/receiver_verification_test.go b/internal/data/receiver_verification_test.go index c68b8a636..33341fc88 100644 --- a/internal/data/receiver_verification_test.go +++ b/internal/data/receiver_verification_test.go @@ -249,6 +249,92 @@ func Test_ReceiverVerificationModel_UpdateVerificationValue(t *testing.T) { assert.True(t, verified) } +func Test_ReceiverVerificationModel_UpsertVerificationValue(t *testing.T) { + dbt := dbtest.Open(t) + defer dbt.Close() + + dbConnectionPool, err := db.OpenDBConnectionPool(dbt.DSN) + require.NoError(t, err) + defer dbConnectionPool.Close() + + ctx := context.Background() + receiver := CreateReceiverFixture(t, ctx, dbConnectionPool, &Receiver{}) + receiverVerificationModel := ReceiverVerificationModel{} + getReceiverVerificationHashedValue := func(t *testing.T, ctx context.Context, dbConnectionPool db.DBConnectionPool, receiverID string, verificationField VerificationField) string { + const q = "SELECT hashed_value FROM receiver_verifications WHERE receiver_id = $1 AND verification_field = $2" + var hashedValue string + qErr := dbConnectionPool.GetContext(ctx, &hashedValue, q, receiverID, verificationField) + require.NoError(t, qErr) + return hashedValue + } + + t.Run("upserts the verification value successfully", func(t *testing.T) { + // Inserts the verification value + firstVerificationValue := "123456" + err = receiverVerificationModel.UpsertVerificationValue(ctx, dbConnectionPool, receiver.ID, VerificationFieldPin, firstVerificationValue) + require.NoError(t, err) + + currentHashedValue := getReceiverVerificationHashedValue(t, ctx, dbConnectionPool, receiver.ID, VerificationFieldPin) + assert.NotEmpty(t, currentHashedValue) + verified := CompareVerificationValue(currentHashedValue, firstVerificationValue) + assert.True(t, verified) + + // Updates the verification value + newVerificationValue := "654321" + err = receiverVerificationModel.UpsertVerificationValue(ctx, dbConnectionPool, receiver.ID, VerificationFieldPin, newVerificationValue) + require.NoError(t, err) + + afterUpdateHashedValue := getReceiverVerificationHashedValue(t, ctx, dbConnectionPool, receiver.ID, VerificationFieldPin) + assert.NotEmpty(t, afterUpdateHashedValue) + + // Checking if the hashed value is NOT the first one. + verified = CompareVerificationValue(afterUpdateHashedValue, firstVerificationValue) + assert.False(t, verified) + // Checking if the hashed value is equal the updated verification value + verified = CompareVerificationValue(afterUpdateHashedValue, newVerificationValue) + assert.True(t, verified) + }) + + t.Run("doesn't update the verification value when it was confirmed by the receiver", func(t *testing.T) { + // Inserts the verification value + firstVerificationValue := "0301016957187" + err := receiverVerificationModel.UpsertVerificationValue(ctx, dbConnectionPool, receiver.ID, VerificationFieldNationalID, firstVerificationValue) + require.NoError(t, err) + + currentHashedValue := getReceiverVerificationHashedValue(t, ctx, dbConnectionPool, receiver.ID, VerificationFieldNationalID) + assert.NotEmpty(t, currentHashedValue) + verified := CompareVerificationValue(currentHashedValue, firstVerificationValue) + assert.True(t, verified) + + // Receiver confirmed the verification value + now := time.Now() + err = receiverVerificationModel.UpdateReceiverVerification(ctx, ReceiverVerification{ + ReceiverID: receiver.ID, + VerificationField: VerificationFieldNationalID, + Attempts: 0, + ConfirmedAt: &now, + FailedAt: nil, + }, dbConnectionPool) + require.NoError(t, err) + + newVerificationValue := "0301017821085" + err = receiverVerificationModel.UpsertVerificationValue(ctx, dbConnectionPool, receiver.ID, VerificationFieldNationalID, newVerificationValue) + require.NoError(t, err) + + afterUpdateHashedValue := getReceiverVerificationHashedValue(t, ctx, dbConnectionPool, receiver.ID, VerificationFieldNationalID) + assert.NotEmpty(t, currentHashedValue) + + // Checking if the hashed value is NOT the new one. + verified = CompareVerificationValue(afterUpdateHashedValue, newVerificationValue) + assert.False(t, verified) + // Checking if the hashed value is equal the first verification value + verified = CompareVerificationValue(afterUpdateHashedValue, firstVerificationValue) + assert.True(t, verified) + + assert.Equal(t, currentHashedValue, afterUpdateHashedValue) + }) +} + func Test_ReceiverVerificationModel_UpdateReceiverVerification(t *testing.T) { dbt := dbtest.Open(t) defer dbt.Close() diff --git a/internal/serve/httphandler/update_receiver_handler.go b/internal/serve/httphandler/update_receiver_handler.go index eabbbca72..44359ae74 100644 --- a/internal/serve/httphandler/update_receiver_handler.go +++ b/internal/serve/httphandler/update_receiver_handler.go @@ -74,9 +74,9 @@ func (h UpdateReceiverHandler) UpdateReceiver(rw http.ResponseWriter, req *http. receiverVerifications := createVerificationInsert(&reqBody, receiverID) receiver, err := db.RunInTransactionWithResult(ctx, h.DBConnectionPool, nil, func(dbTx db.DBTransaction) (response *data.Receiver, innerErr error) { for _, rv := range receiverVerifications { - innerErr = h.Models.ReceiverVerification.UpdateVerificationValue( + innerErr = h.Models.ReceiverVerification.UpsertVerificationValue( req.Context(), - h.Models.DBConnectionPool, + dbTx, rv.ReceiverID, rv.VerificationField, rv.VerificationValue, @@ -97,7 +97,7 @@ func (h UpdateReceiverHandler) UpdateReceiver(rw http.ResponseWriter, req *http. } } - receiver, innerErr := h.Models.Receiver.Get(ctx, h.Models.DBConnectionPool, receiverID) + receiver, innerErr := h.Models.Receiver.Get(ctx, dbTx, receiverID) if innerErr != nil { return nil, fmt.Errorf("error querying receiver with ID %s: %w", receiverID, innerErr) } @@ -106,7 +106,8 @@ func (h UpdateReceiverHandler) UpdateReceiver(rw http.ResponseWriter, req *http. }) if err != nil { httperror.InternalError(ctx, "", err, nil).Render(rw) + return } - httpjson.RenderStatus(rw, http.StatusOK, receiver, httpjson.JSON) + httpjson.Render(rw, receiver, httpjson.JSON) } diff --git a/internal/serve/httphandler/update_receiver_handler_test.go b/internal/serve/httphandler/update_receiver_handler_test.go index 8fb14dd6c..b38c49f41 100644 --- a/internal/serve/httphandler/update_receiver_handler_test.go +++ b/internal/serve/httphandler/update_receiver_handler_test.go @@ -429,6 +429,82 @@ func Test_UpdateReceiverHandler(t *testing.T) { } }) + t.Run("updates and inserts receiver verifications values", func(t *testing.T) { + data.DeleteAllReceiverVerificationFixtures(t, ctx, dbConnectionPool) + + data.CreateReceiverVerificationFixture(t, ctx, dbConnectionPool, data.ReceiverVerificationInsert{ + ReceiverID: receiver.ID, + VerificationField: data.VerificationFieldPin, + VerificationValue: "890", + }) + + request := validators.UpdateReceiverRequest{ + DateOfBirth: "1999-01-01", + Pin: "123", + NationalID: "NEWID123", + } + + route := fmt.Sprintf("/receivers/%s", receiver.ID) + reqBody, err := json.Marshal(request) + require.NoError(t, err) + req, err := http.NewRequest(http.MethodPatch, route, strings.NewReader(string(reqBody))) + require.NoError(t, err) + + rr := httptest.NewRecorder() + r.ServeHTTP(rr, req) + + resp := rr.Result() + assert.Equal(t, http.StatusOK, resp.StatusCode) + + query := ` + SELECT + hashed_value + FROM + receiver_verifications + WHERE + receiver_id = $1 AND + verification_field = $2 + ` + + receiverVerifications := []struct { + verificationField data.VerificationField + newVerificationValue string + oldVerificationValue string + }{ + { + verificationField: data.VerificationFieldDateOfBirth, + newVerificationValue: "1999-01-01", + oldVerificationValue: "2000-01-01", + }, + { + verificationField: data.VerificationFieldPin, + newVerificationValue: "123", + oldVerificationValue: "", + }, + { + verificationField: data.VerificationFieldNationalID, + newVerificationValue: "NEWID123", + oldVerificationValue: "", + }, + } + for _, v := range receiverVerifications { + newReceiverVerification := data.ReceiverVerification{} + err = dbConnectionPool.GetContext(ctx, &newReceiverVerification, query, receiver.ID, v.verificationField) + require.NoError(t, err) + + assert.True(t, data.CompareVerificationValue(newReceiverVerification.HashedValue, v.newVerificationValue)) + + if v.oldVerificationValue != "" { + assert.False(t, data.CompareVerificationValue(newReceiverVerification.HashedValue, v.oldVerificationValue)) + } + + receiverDB, err := models.Receiver.Get(ctx, dbConnectionPool, receiver.ID) + require.NoError(t, err) + assert.Equal(t, "receiver@email.com", *receiverDB.Email) + assert.Equal(t, "externalID", receiverDB.ExternalID) + } + }) + t.Run("updates receiver's email", func(t *testing.T) { request := validators.UpdateReceiverRequest{ Email: "update_receiver@email.com", From ec6e2838e34bea702b8ca3bd86fe661a900babe5 Mon Sep 17 00:00:00 2001 From: Caio Teixeira Date: Mon, 4 Mar 2024 09:35:25 -0300 Subject: [PATCH 09/12] fix: ensure verification field order (#209) What The order should be by updated_at and then by verification_field in alphabetical order. --- internal/data/receiver_verification.go | 9 ++++---- internal/data/receiver_verification_test.go | 25 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/internal/data/receiver_verification.go b/internal/data/receiver_verification.go index 474529cab..914dc10cc 100644 --- a/internal/data/receiver_verification.go +++ b/internal/data/receiver_verification.go @@ -100,14 +100,15 @@ func (m *ReceiverVerificationModel) GetLatestByPhoneNumber(ctx context.Context, receiverVerification := ReceiverVerification{} query := ` SELECT - rv.* + rv.* FROM - receiver_verifications rv + receiver_verifications rv JOIN receivers r ON rv.receiver_id = r.id WHERE - r.phone_number = $1 + r.phone_number = $1 ORDER BY - rv.updated_at DESC + rv.updated_at DESC, + rv.verification_field ASC LIMIT 1 ` diff --git a/internal/data/receiver_verification_test.go b/internal/data/receiver_verification_test.go index 33341fc88..82104f5bf 100644 --- a/internal/data/receiver_verification_test.go +++ b/internal/data/receiver_verification_test.go @@ -402,6 +402,31 @@ func Test_ReceiverVerificationModel_CheckTotalAttempts(t *testing.T) { }) } +func Test_ReceiverVerificationModel_GetLatestByPhoneNumber(t *testing.T) { + dbt := dbtest.Open(t) + defer dbt.Close() + + dbConnectionPool, err := db.OpenDBConnectionPool(dbt.DSN) + require.NoError(t, err) + defer dbConnectionPool.Close() + + ctx := context.Background() + + receiver := CreateReceiverFixture(t, ctx, dbConnectionPool, &Receiver{}) + receiverVerificationModel := ReceiverVerificationModel{dbConnectionPool: dbConnectionPool} + + err = receiverVerificationModel.UpsertVerificationValue(ctx, dbConnectionPool, receiver.ID, VerificationFieldDateOfBirth, "1990-01-01") + require.NoError(t, err) + err = receiverVerificationModel.UpsertVerificationValue(ctx, dbConnectionPool, receiver.ID, VerificationFieldPin, "123456") + require.NoError(t, err) + + verification, err := receiverVerificationModel.GetLatestByPhoneNumber(ctx, receiver.PhoneNumber) + require.NoError(t, err) + + assert.Equal(t, VerificationFieldPin, verification.VerificationField) + assert.True(t, CompareVerificationValue(verification.HashedValue, "123456")) +} + func Test_ReceiverVerification_HashAndCompareVerificationValue(t *testing.T) { verificationValue := "1987-01-01" hashedVerificationInfo, err := HashVerificationValue(verificationValue) From 5ba26a09fc27bfe98f9c1209b8d69a990af43ae2 Mon Sep 17 00:00:00 2001 From: Marwen Abid Date: Wed, 6 Mar 2024 16:04:20 -0800 Subject: [PATCH 10/12] chore pin version of exhaustive --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b8dfd43b9..a8c3a1a30 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,10 +32,10 @@ jobs: - name: Run ./gomod.sh run: ./gomod.sh - - name: Install github.com/nishanths/exhaustive and golang.org/x/tools/cmd/deadcode@latest + - name: Install github.com/nishanths/exhaustive@v0.12.0 and golang.org/x/tools/cmd/deadcode@v0.18.0 run: | - go install github.com/nishanths/exhaustive/cmd/exhaustive@latest - go install golang.org/x/tools/cmd/deadcode@latest + go install github.com/nishanths/exhaustive/cmd/exhaustive@v0.12.0 + go install golang.org/x/tools/cmd/deadcode@v0.18.0 - name: Run `exhaustive` run: exhaustive -default-signifies-exhaustive ./... From a066c44d89c51a22b8b3bd567425e17da01dccff Mon Sep 17 00:00:00 2001 From: Marcelo Salloum Date: Mon, 15 Apr 2024 11:09:12 -0300 Subject: [PATCH 11/12] Update project versions from 1.1.5 to 1.1.6. --- helmchart/sdp/Chart.yaml | 2 +- main.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/helmchart/sdp/Chart.yaml b/helmchart/sdp/Chart.yaml index 53c2cd647..40951e631 100644 --- a/helmchart/sdp/Chart.yaml +++ b/helmchart/sdp/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v2 name: stellar-disbursement-platform description: A Helm chart for the Stellar Disbursement Platform Backend (A.K.A. `sdp`) version: 0.9.4 -appVersion: "1.1.5" +appVersion: "1.1.6" type: application maintainers: - name: Stellar Development Foundation diff --git a/main.go b/main.go index fc472c009..2a03bbed6 100644 --- a/main.go +++ b/main.go @@ -11,7 +11,7 @@ import ( // Version is the official version of this application. Whenever it's changed // here, it also needs to be updated at the `helmchart/Chart.yaml#appVersion“. -const Version = "1.1.5" +const Version = "1.1.6" // GitCommit is populated at build time by // go build -ldflags "-X main.GitCommit=$GIT_COMMIT" From 35e1123f092d28b4fd66b68b52ca320719e04e5f Mon Sep 17 00:00:00 2001 From: Marcelo Salloum Date: Mon, 15 Apr 2024 11:09:53 -0300 Subject: [PATCH 12/12] Update the changelog with 1.1.6 changes. --- CHANGELOG.md | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 39b6ceff5..f72524900 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,28 @@ All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +The format is based on [Keep a Changelog](https://keepachangelog.com/). ## Unreleased None +## [1.1.6](https://github.com/stellar/stellar-disbursement-platform-backend/compare/1.1.5...1.1.6) + +Attention, this version is compatible with the frontend version [1.1.2](https://github.com/stellar/stellar-disbursement-platform-frontend/releases/tag/1.1.2). + +### Changed + +- Update the `PATCH /receivers/{id}` request, so a receiver's verification info is not just inserted but upserted. The update part of the upsert only takes place if the verification info has not been confirmed yet. [#205](https://github.com/stellar/stellar-disbursement-platform-backend/pull/205) +- Update the order of the verification field that is shown to the receiver during the [SEP-24] flow. The order was `(updated_at DESC)` and was updated to the composed sorting `(updated_at DESC, rv.verification_field ASC)` to ensure consistency when multiple verification fields share the same `updated_at` value. +- Improve information in the error message returned when the disbursement instruction contains a verification info that is different from an already existing verification info that was already confirmed by the receiver. [#178](https://github.com/stellar/stellar-disbursement-platform-backend/pull/178) +- When adding an asset, make sure to trim the spaces fom the issuer field. [#185](https://github.com/stellar/stellar-disbursement-platform-backend/pull/185) + +### Security + +- Bump Go version from 1.19 to 1.22, and upgraded the version of some CI tools. [#196](https://github.com/stellar/stellar-disbursement-platform-backend/pull/196) +- Add rate-limiter in both in the application and the kubernetes deployment. [#195](https://github.com/stellar/stellar-disbursement-platform-backend/pull/195) + ## [1.1.5](https://github.com/stellar/stellar-disbursement-platform-backend/compare/1.1.4...1.1.5) ### Fixed @@ -32,7 +48,7 @@ None ### Fixed -- SEP24 registration flow not working properly when the phone number was not found in the DB [#187](https://github.com/stellar/stellar-disbursement-platform-backend/pull/187) +- [SEP-24] registration flow not working properly when the phone number was not found in the DB [#187](https://github.com/stellar/stellar-disbursement-platform-backend/pull/187) - Fix distribution account balance validation that fails when the intended asset is XLM [#186](https://github.com/stellar/stellar-disbursement-platform-backend/pull/186) ## [1.1.2](https://github.com/stellar/stellar-disbursement-platform-backend/compare/1.1.1...1.1.2) @@ -52,7 +68,7 @@ None ### Changed - Change `POST /disbursements` to accept different verification types [#103](https://github.com/stellar/stellar-disbursement-platform-backend/pull/103) -- Change `SEP-24` Flow to display different verifications based on disbursement verification type [#116](https://github.com/stellar/stellar-disbursement-platform-backend/pull/116) +- Change [SEP-24] Flow to display different verifications based on disbursement verification type [#116](https://github.com/stellar/stellar-disbursement-platform-backend/pull/116) - Add sorting to `GET /users` endpoint [#104](https://github.com/stellar/stellar-disbursement-platform-backend/pull/104) - Change read permission for receiver details to include business roles [#144](https://github.com/stellar/stellar-disbursement-platform-backend/pull/144) - Add support for unique payment ID to disbursement instructions file as an optional field in `GET /payments/{id}` [#131](https://github.com/stellar/stellar-disbursement-platform-backend/pull/131) @@ -144,7 +160,7 @@ None - Stellar.Expert URL in env-config.js for dev environment setup. [#34](https://github.com/stellar/stellar-disbursement-platform-backend/pull/34) - Patch the correct transaction data fields in AnchorPlatform. [#40](https://github.com/stellar/stellar-disbursement-platform-backend/pull/40) -- Sep10 domain configuration for Vibrant wallet on Testnet. [#42](https://github.com/stellar/stellar-disbursement-platform-backend/pull/42) +- [SEP-10] domain configuration for Vibrant wallet on Testnet. [#42](https://github.com/stellar/stellar-disbursement-platform-backend/pull/42) - The SMS invitation link for XLM asset. [#46](https://github.com/stellar/stellar-disbursement-platform-backend/pull/46) ### Security @@ -199,7 +215,7 @@ number, transfer amount, and essential customer validation data such as the date The platform subsequently sends an SMS to the recipient, which includes a deep link to the wallet. This link permits recipients with compatible wallets to register their wallet on the SDP. During this step, they are required to verify -their phone number and additional customer data through the SEP-24 interactive deposit flow, where this data is shared +their phone number and additional customer data through the [SEP-24] interactive deposit flow, where this data is shared directly with the backend through a webpage inside the wallet, but the wallet itself does not have access to this data. Upon successful verification, the SDP will transfer the funds directly to the recipient's wallet. When the recipient's @@ -207,3 +223,5 @@ wallet has been successfully associated with their phone number in the SDP, all automatically. [stellar/stellar-disbursement-platform-frontend]: https://github.com/stellar/stellar-disbursement-platform-frontend +[SEP-10]: https://stellar.org/protocol/sep-10 +[SEP-24]: https://stellar.org/protocol/sep-24