diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a54d9bfeee..5ca0eef417 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -49,13 +49,10 @@ jobs: - name: Run static check run: | set -x - go install honnef.co/go/tools/cmd/staticcheck@latest - go install github.com/nishanths/exhaustive/cmd/exhaustive@latest make static - name: Check gosec run: | set -x - go install github.com/securego/gosec/v2/cmd/gosec@latest make sec - name: Init Database run: psql -f hack/init_postgres.sql postgresql://postgres:root@localhost:5432/postgres diff --git a/Makefile b/Makefile index cf768b39b6..14d41aa1c5 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ .PHONY: all build deps image migrate test vet sec format unused -.PHONY: check-exhaustive check-gosec check-oapi-codegen check-staticcheck +.PHONY: check-gosec check-oapi-codegen check-staticcheck CHECK_FILES?=./... ifdef RELEASE_VERSION @@ -66,18 +66,13 @@ unused: | check-staticcheck # Look for unused code @echo "Code used only in _test.go (do move it in those files):" staticcheck -checks U1000 -tests=false $(CHECK_FILES) -static: | check-staticcheck check-exhaustive +static: | check-staticcheck staticcheck ./... - exhaustive ./... check-staticcheck: @command -v staticcheck >/dev/null 2>&1 \ || go install honnef.co/go/tools/cmd/staticcheck@latest -check-exhaustive: - @command -v exhaustive >/dev/null 2>&1 \ - || go install github.com/nishanths/exhaustive/cmd/exhaustive@latest - generate: | check-oapi-codegen go generate ./... diff --git a/go.mod b/go.mod index 88ed5cf408..966c5074d0 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.1 github.com/stretchr/testify v1.10.0 - golang.org/x/crypto v0.36.0 + golang.org/x/crypto v0.40.0 golang.org/x/oauth2 v0.27.0 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df ) @@ -71,8 +71,8 @@ require ( github.com/x448/float16 v0.8.4 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - golang.org/x/mod v0.22.0 // indirect - golang.org/x/tools v0.29.0 // indirect + golang.org/x/mod v0.26.0 // indirect + golang.org/x/tools v0.35.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect ) @@ -169,10 +169,10 @@ require ( github.com/stretchr/objx v0.5.2 // indirect go.opentelemetry.io/proto/otlp v1.2.0 // indirect golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb - golang.org/x/net v0.38.0 // indirect - golang.org/x/sync v0.12.0 - golang.org/x/sys v0.31.0 - golang.org/x/text v0.23.0 + golang.org/x/net v0.42.0 // indirect + golang.org/x/sync v0.16.0 + golang.org/x/sys v0.34.0 + golang.org/x/text v0.27.0 golang.org/x/time v0.9.0 google.golang.org/grpc v1.63.2 // indirect google.golang.org/protobuf v1.34.2 // indirect @@ -181,4 +181,4 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) -go 1.23.7 +go 1.25.5 diff --git a/go.sum b/go.sum index 8f420c6729..0e7a44a10e 100644 --- a/go.sum +++ b/go.sum @@ -558,8 +558,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb h1:mIKbk8weKhSeLH2GmUTrvx8CjkyJmnU1wFmg59CUjFA= golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -568,8 +568,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= -golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= golang.org/x/net v0.0.0-20161007143504-f4b625ec9b21/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -587,8 +587,8 @@ golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfS golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -597,8 +597,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= -golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -632,8 +632,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -650,8 +650,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/time v0.0.0-20160926182426-711ca1cb8763/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= @@ -668,8 +668,8 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE= -golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588= +golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/internal/api/admin.go b/internal/api/admin.go index 0d53406def..ad50b81e53 100644 --- a/internal/api/admin.go +++ b/internal/api/admin.go @@ -390,7 +390,7 @@ func (a *API) adminUserCreate(w http.ResponseWriter, r *http.Request) error { if err != nil { if errors.Is(err, bcrypt.ErrPasswordTooLong) { - return apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, err.Error()) + return apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, "%s", err.Error()) } return apierrors.NewInternalServerError("Error creating user").WithInternalError(err) } diff --git a/internal/api/apierrors/apierrors_test.go b/internal/api/apierrors/apierrors_test.go index 515a79a9ef..aa47066d3a 100644 --- a/internal/api/apierrors/apierrors_test.go +++ b/internal/api/apierrors/apierrors_test.go @@ -144,7 +144,7 @@ func TestHTTPErrors(t *testing.T) { ErrorCodeBadJSON, "Unable to parse JSON: %v", errors.New("bad syntax"), - ).WithInternalError(sentinel).WithInternalMessage(sentinel.Error()) + ).WithInternalError(sentinel).WithInternalMessage("%s", sentinel.Error()) require.Equal(t, err.Error(), sentinel.Error()) require.Equal(t, err.Cause(), sentinel) @@ -171,7 +171,7 @@ func TestOAuthErrors(t *testing.T) { err := NewOAuthError( "oauth error", "oauth desc", - ).WithInternalError(sentinel).WithInternalMessage(sentinel.Error()) + ).WithInternalError(sentinel).WithInternalMessage("%s", sentinel.Error()) require.Error(t, err) require.Equal(t, err.Error(), sentinel.Error()) diff --git a/internal/api/auth.go b/internal/api/auth.go index 448212beb6..abcb529a21 100644 --- a/internal/api/auth.go +++ b/internal/api/auth.go @@ -58,7 +58,10 @@ func (a *API) requireAdmin(ctx context.Context) (context.Context, error) { return withAdminUser(ctx, &models.User{Role: claims.Role, Email: storage.NullString(claims.Role)}), nil } - return nil, apierrors.NewForbiddenError(apierrors.ErrorCodeNotAdmin, "User not allowed").WithInternalMessage(fmt.Sprintf("this token needs to have one of the following roles: %v", strings.Join(adminRoles, ", "))) + return nil, apierrors.NewForbiddenError(apierrors.ErrorCodeNotAdmin, "User not allowed"). + WithInternalMessage( + "this token needs to have one of the following roles: %v", + strings.Join(adminRoles, ", ")) } func (a *API) extractBearerToken(r *http.Request) (string, error) { @@ -143,7 +146,7 @@ func (a *API) maybeLoadUserOrSession(ctx context.Context) (context.Context, erro session, err = models.FindSessionByID(db, sessionId, false) if err != nil { if models.IsNotFoundError(err) { - return ctx, apierrors.NewForbiddenError(apierrors.ErrorCodeSessionNotFound, "Session from session_id claim in JWT does not exist").WithInternalError(err).WithInternalMessage(fmt.Sprintf("session id (%s) doesn't exist", sessionId)) + return ctx, apierrors.NewForbiddenError(apierrors.ErrorCodeSessionNotFound, "Session from session_id claim in JWT does not exist").WithInternalError(err).WithInternalMessage("session id (%s) doesn't exist", sessionId) } return ctx, err } diff --git a/internal/api/errors.go b/internal/api/errors.go index 7479f9f032..a9b467f36a 100644 --- a/internal/api/errors.go +++ b/internal/api/errors.go @@ -15,10 +15,13 @@ import ( ) // Common error messages during signup flow +const ( + DuplicateEmailMsg = "A user with this email address has already been registered" + DuplicatePhoneMsg = "A user with this phone number has already been registered" +) + var ( - DuplicateEmailMsg = "A user with this email address has already been registered" - DuplicatePhoneMsg = "A user with this phone number has already been registered" - UserExistsError error = errors.New("user already exists") + UserExistsError error = errors.New("user already exists") ) const InvalidChannelError = "Invalid channel, supported values are 'sms' or 'whatsapp'. 'whatsapp' is only supported if Twilio or Twilio Verify is used as the provider." diff --git a/internal/api/external.go b/internal/api/external.go index dc2fd6e008..8392797d59 100644 --- a/internal/api/external.go +++ b/internal/api/external.go @@ -441,10 +441,19 @@ func (a *API) createAccountFromExternalIdentity(tx *storage.Connection, r *http. if !config.Mailer.AllowUnverifiedEmailSignIns { if emailConfirmationSent { - return 0, nil, storage.NewCommitWithError(apierrors.NewUnprocessableEntityError(apierrors.ErrorCodeProviderEmailNeedsVerification, fmt.Sprintf("Unverified email with %v. A confirmation email has been sent to your %v email", providerType, providerType))) + err := apierrors.NewUnprocessableEntityError( + apierrors.ErrorCodeProviderEmailNeedsVerification, + "Unverified email with %v. A confirmation email has been sent to your %v email", + providerType, providerType, + ) + return 0, nil, storage.NewCommitWithError(err) } - return 0, nil, storage.NewCommitWithError(apierrors.NewUnprocessableEntityError(apierrors.ErrorCodeProviderEmailNeedsVerification, fmt.Sprintf("Unverified email with %v. Verify the email with %v in order to sign in", providerType, providerType))) + err := apierrors.NewUnprocessableEntityError( + apierrors.ErrorCodeProviderEmailNeedsVerification, + "Unverified email with %v. Verify the email with %v in order to sign in", + providerType, providerType) + return 0, nil, storage.NewCommitWithError(err) } } } else { diff --git a/internal/api/logout.go b/internal/api/logout.go index fa3742ccc3..310b7c0d60 100644 --- a/internal/api/logout.go +++ b/internal/api/logout.go @@ -1,7 +1,6 @@ package api import ( - "fmt" "net/http" "github.com/sirupsen/logrus" @@ -37,7 +36,7 @@ func (a *API) Logout(w http.ResponseWriter, r *http.Request) error { scope = LogoutOthers default: - return apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, fmt.Sprintf("Unsupported logout scope %q", r.URL.Query().Get("scope"))) + return apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, "Unsupported logout scope %q", r.URL.Query().Get("scope")) } } @@ -52,7 +51,6 @@ func (a *API) Logout(w http.ResponseWriter, r *http.Request) error { if s == nil { logrus.Infof("user has an empty session_id claim: %s", u.ID) } else { - //exhaustive:ignore Default case is handled below. switch scope { case LogoutLocal: return models.LogoutSession(tx, s.ID) diff --git a/internal/api/mail.go b/internal/api/mail.go index d25462a519..7106a5a3a2 100644 --- a/internal/api/mail.go +++ b/internal/api/mail.go @@ -335,7 +335,7 @@ func (a *API) sendConfirmation(r *http.Request, tx *storage.Connection, u *model }); err != nil { u.ConfirmationToken = oldToken if errors.Is(err, EmailRateLimitExceeded) { - return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, EmailRateLimitExceeded.Error()) + return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, "%s", EmailRateLimitExceeded.Error()) } else if herr, ok := err.(*HTTPError); ok { return herr } @@ -370,7 +370,7 @@ func (a *API) sendInvite(r *http.Request, tx *storage.Connection, u *models.User if err != nil { u.ConfirmationToken = oldToken if errors.Is(err, EmailRateLimitExceeded) { - return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, EmailRateLimitExceeded.Error()) + return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, "%s", EmailRateLimitExceeded.Error()) } else if herr, ok := err.(*HTTPError); ok { return herr } @@ -413,7 +413,7 @@ func (a *API) sendPasswordRecovery(r *http.Request, tx *storage.Connection, u *m if err != nil { u.RecoveryToken = oldToken if errors.Is(err, EmailRateLimitExceeded) { - return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, EmailRateLimitExceeded.Error()) + return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, "%s", EmailRateLimitExceeded.Error()) } else if herr, ok := err.(*HTTPError); ok { return herr } @@ -455,7 +455,7 @@ func (a *API) sendReauthenticationOtp(r *http.Request, tx *storage.Connection, u if err != nil { u.ReauthenticationToken = oldToken if errors.Is(err, EmailRateLimitExceeded) { - return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, EmailRateLimitExceeded.Error()) + return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, "%s", EmailRateLimitExceeded.Error()) } else if herr, ok := err.(*HTTPError); ok { return herr } @@ -498,7 +498,7 @@ func (a *API) sendMagicLink(r *http.Request, tx *storage.Connection, u *models.U }); err != nil { u.RecoveryToken = oldToken if errors.Is(err, EmailRateLimitExceeded) { - return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, EmailRateLimitExceeded.Error()) + return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, "%s", EmailRateLimitExceeded.Error()) } else if herr, ok := err.(*HTTPError); ok { return herr } @@ -550,7 +550,7 @@ func (a *API) sendEmailChange(r *http.Request, tx *storage.Connection, u *models }) if err != nil { if errors.Is(err, EmailRateLimitExceeded) { - return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, EmailRateLimitExceeded.Error()) + return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, "%s", EmailRateLimitExceeded.Error()) } else if herr, ok := err.(*HTTPError); ok { return herr } @@ -590,7 +590,7 @@ func (a *API) sendPasswordChangedNotification(r *http.Request, tx *storage.Conne }) if err != nil { if errors.Is(err, EmailRateLimitExceeded) { - return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, EmailRateLimitExceeded.Error()) + return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, "%s", EmailRateLimitExceeded.Error()) } else if herr, ok := err.(*HTTPError); ok { return herr } @@ -607,7 +607,7 @@ func (a *API) sendEmailChangedNotification(r *http.Request, tx *storage.Connecti }) if err != nil { if errors.Is(err, EmailRateLimitExceeded) { - return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, EmailRateLimitExceeded.Error()) + return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, "%s", EmailRateLimitExceeded.Error()) } else if herr, ok := err.(*HTTPError); ok { return herr } @@ -624,7 +624,7 @@ func (a *API) sendPhoneChangedNotification(r *http.Request, tx *storage.Connecti }) if err != nil { if errors.Is(err, EmailRateLimitExceeded) { - return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, EmailRateLimitExceeded.Error()) + return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, "%s", EmailRateLimitExceeded.Error()) } else if herr, ok := err.(*HTTPError); ok { return herr } @@ -641,7 +641,7 @@ func (a *API) sendIdentityLinkedNotification(r *http.Request, tx *storage.Connec }) if err != nil { if errors.Is(err, EmailRateLimitExceeded) { - return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, EmailRateLimitExceeded.Error()) + return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, "%s", EmailRateLimitExceeded.Error()) } else if herr, ok := err.(*HTTPError); ok { return herr } @@ -658,7 +658,7 @@ func (a *API) sendIdentityUnlinkedNotification(r *http.Request, tx *storage.Conn }) if err != nil { if errors.Is(err, EmailRateLimitExceeded) { - return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, EmailRateLimitExceeded.Error()) + return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, "%s", EmailRateLimitExceeded.Error()) } else if herr, ok := err.(*HTTPError); ok { return herr } @@ -675,7 +675,7 @@ func (a *API) sendMFAFactorEnrolledNotification(r *http.Request, tx *storage.Con }) if err != nil { if errors.Is(err, EmailRateLimitExceeded) { - return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, EmailRateLimitExceeded.Error()) + return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, "%s", EmailRateLimitExceeded.Error()) } else if herr, ok := err.(*HTTPError); ok { return herr } @@ -692,7 +692,7 @@ func (a *API) sendMFAFactorUnenrolledNotification(r *http.Request, tx *storage.C }) if err != nil { if errors.Is(err, EmailRateLimitExceeded) { - return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, EmailRateLimitExceeded.Error()) + return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, "%s", EmailRateLimitExceeded.Error()) } else if herr, ok := err.(*HTTPError); ok { return herr } @@ -710,7 +710,7 @@ func (a *API) validateEmail(email string) (string, error) { return "", apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, "An email address is too long") } if err := checkmail.ValidateFormat(email); err != nil { - return "", apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, "Unable to validate email address: "+err.Error()) + return "", apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, "Unable to validate email address: %s", err.Error()) } return strings.ToLower(email), nil @@ -718,7 +718,7 @@ func (a *API) validateEmail(email string) (string, error) { func validateSentWithinFrequencyLimit(sentAt *time.Time, frequency time.Duration) error { if sentAt != nil && sentAt.Add(frequency).After(time.Now()) { - return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, generateFrequencyLimitErrorMessage(sentAt, frequency)) + return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, "%s", generateFrequencyLimitErrorMessage(sentAt, frequency)) } return nil } diff --git a/internal/api/mfa.go b/internal/api/mfa.go index 81523363f4..26654c0160 100644 --- a/internal/api/mfa.go +++ b/internal/api/mfa.go @@ -140,7 +140,7 @@ func validateFactors(db *storage.Connection, user *models.User, newFactorName st if factor.FriendlyName == newFactorName { return apierrors.NewUnprocessableEntityError( apierrors.ErrorCodeMFAFactorNameConflict, - fmt.Sprintf("A factor with the friendly name %q for this user already exists", newFactorName), + "A factor with the friendly name %q for this user already exists", newFactorName, ) } if factor.IsVerified() { @@ -389,7 +389,7 @@ func (a *API) challengePhoneFactor(w http.ResponseWriter, r *http.Request) error if factor.IsPhoneFactor() && factor.LastChallengedAt != nil { if !factor.LastChallengedAt.Add(config.MFA.Phone.MaxFrequency).Before(time.Now()) { - return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverSMSSendRateLimit, generateFrequencyLimitErrorMessage(factor.LastChallengedAt, config.MFA.Phone.MaxFrequency)) + return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverSMSSendRateLimit, "%s", generateFrequencyLimitErrorMessage(factor.LastChallengedAt, config.MFA.Phone.MaxFrequency)) } } @@ -670,7 +670,7 @@ func (a *API) verifyTOTPFactor(w http.ResponseWriter, r *http.Request, params *V output.Message = v0hooks.DefaultMFAHookRejectionMessage } - return apierrors.NewForbiddenError(apierrors.ErrorCodeMFAVerificationRejected, output.Message) + return apierrors.NewForbiddenError(apierrors.ErrorCodeMFAVerificationRejected, "%s", output.Message) } } if !valid { @@ -821,7 +821,7 @@ func (a *API) verifyPhoneFactor(w http.ResponseWriter, r *http.Request, params * output.Message = v0hooks.DefaultMFAHookRejectionMessage } - return apierrors.NewForbiddenError(apierrors.ErrorCodeMFAVerificationRejected, output.Message) + return apierrors.NewForbiddenError(apierrors.ErrorCodeMFAVerificationRejected, "%s", output.Message) } } if !valid { diff --git a/internal/api/middleware.go b/internal/api/middleware.go index 96b323c53c..92003e6d7b 100644 --- a/internal/api/middleware.go +++ b/internal/api/middleware.go @@ -138,7 +138,7 @@ func (a *API) requireOAuthClientAuth(w http.ResponseWriter, r *http.Request) (co clientID, clientSecret, err := oauthserver.ExtractClientCredentials(r) if err != nil { - return nil, apierrors.NewBadRequestError(apierrors.ErrorCodeInvalidCredentials, "Invalid client credentials: "+err.Error()) + return nil, apierrors.NewBadRequestError(apierrors.ErrorCodeInvalidCredentials, "Invalid client credentials: %s", err.Error()) } // If no client credentials provided, continue without client authentication @@ -164,7 +164,7 @@ func (a *API) requireOAuthClientAuth(w http.ResponseWriter, r *http.Request) (co // Validate authentication using centralized logic if err := oauthserver.ValidateClientAuthentication(client, clientSecret); err != nil { - return nil, apierrors.NewBadRequestError(apierrors.ErrorCodeInvalidCredentials, err.Error()) + return nil, apierrors.NewBadRequestError(apierrors.ErrorCodeInvalidCredentials, "%s", err.Error()) } // Add authenticated client to context diff --git a/internal/api/oauthserver/handlers.go b/internal/api/oauthserver/handlers.go index 770f3f50c3..c61de40852 100644 --- a/internal/api/oauthserver/handlers.go +++ b/internal/api/oauthserver/handlers.go @@ -127,7 +127,7 @@ func (s *Server) AdminOAuthServerClientRegister(w http.ResponseWriter, r *http.R client, plaintextSecret, err := s.registerOAuthServerClient(ctx, ¶ms) if err != nil { - return apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, err.Error()) + return apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, "%s", err.Error()) } response := oauthServerClientToResponse(client) @@ -156,7 +156,7 @@ func (s *Server) OAuthServerClientDynamicRegister(w http.ResponseWriter, r *http client, plaintextSecret, err := s.registerOAuthServerClient(ctx, ¶ms) if err != nil { - return apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, err.Error()) + return apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, "%s", err.Error()) } response := oauthServerClientToResponse(client) diff --git a/internal/api/oauthserver/service.go b/internal/api/oauthserver/service.go index 3af95d0644..7ee02dafa1 100644 --- a/internal/api/oauthserver/service.go +++ b/internal/api/oauthserver/service.go @@ -164,7 +164,7 @@ func (p *OAuthServerClientRegisterParams) validate() error { // Validate consistency between client_type and token_endpoint_auth_method if err := ValidateClientTypeConsistency(p.ClientType, p.TokenEndpointAuthMethod); err != nil { - return apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, err.Error()) + return apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, "%s", err.Error()) } return nil diff --git a/internal/api/password.go b/internal/api/password.go index 47cc6755df..5ce20149b2 100644 --- a/internal/api/password.go +++ b/internal/api/password.go @@ -29,7 +29,11 @@ func (a *API) checkPasswordStrength(ctx context.Context, password string) error config := a.config if len(password) > MaxPasswordLength { - return apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, fmt.Sprintf("Password cannot be longer than %v characters", MaxPasswordLength)) + return apierrors.NewBadRequestError( + apierrors.ErrorCodeValidationFailed, + "Password cannot be longer than %v characters", + MaxPasswordLength, + ) } var messages, reasons []string diff --git a/internal/api/phone.go b/internal/api/phone.go index ab21bf6cd7..fbd940bcbf 100644 --- a/internal/api/phone.go +++ b/internal/api/phone.go @@ -71,7 +71,7 @@ func (a *API) sendPhoneConfirmation(r *http.Request, tx *storage.Connection, use // intentionally keeping this before the test OTP, so that the behavior // of regular and test OTPs is similar if sentAt != nil && !sentAt.Add(config.Sms.MaxFrequency).Before(time.Now()) { - return "", apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverSMSSendRateLimit, generateFrequencyLimitErrorMessage(sentAt, config.Sms.MaxFrequency)) + return "", apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverSMSSendRateLimit, "%s", generateFrequencyLimitErrorMessage(sentAt, config.Sms.MaxFrequency)) } now := time.Now() diff --git a/internal/api/provider/provider.go b/internal/api/provider/provider.go index 9ced63937b..f7acb91e6c 100644 --- a/internal/api/provider/provider.go +++ b/internal/api/provider/provider.go @@ -134,7 +134,7 @@ func makeRequest(ctx context.Context, tok *oauth2.Token, g *oauth2.Config, url s res.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) if res.StatusCode < http.StatusOK || res.StatusCode >= http.StatusMultipleChoices { - return httpError(res.StatusCode, string(bodyBytes)) + return httpError(res.StatusCode, "%s", string(bodyBytes)) } if err := json.NewDecoder(res.Body).Decode(dst); err != nil { diff --git a/internal/api/signup.go b/internal/api/signup.go index 89c79f889a..3a9773ce0a 100644 --- a/internal/api/signup.go +++ b/internal/api/signup.go @@ -168,7 +168,7 @@ func (a *API) Signup(w http.ResponseWriter, r *http.Request) error { msg = "Sign up with this provider not possible" } - return apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, msg) + return apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, "%s", msg) } if err != nil && !models.IsNotFoundError(err) { diff --git a/internal/api/token.go b/internal/api/token.go index 43863784cf..4345d0def7 100644 --- a/internal/api/token.go +++ b/internal/api/token.go @@ -170,7 +170,7 @@ func (a *API) ResourceOwnerPasswordGrant(ctx context.Context, w http.ResponseWri return err } } - return apierrors.NewBadRequestError(apierrors.ErrorCodeInvalidCredentials, output.Message) + return apierrors.NewBadRequestError(apierrors.ErrorCodeInvalidCredentials, "%s", output.Message) } } if !isValidPassword { @@ -246,7 +246,7 @@ func (a *API) PKCE(ctx context.Context, w http.ResponseWriter, r *http.Request) return err } if err := flowState.VerifyPKCE(params.CodeVerifier); err != nil { - return apierrors.NewBadRequestError(apierrors.ErrorCodeBadCodeVerifier, err.Error()) + return apierrors.NewBadRequestError(apierrors.ErrorCodeBadCodeVerifier, "%s", err.Error()) } var token *AccessTokenResponse diff --git a/internal/api/token_oidc.go b/internal/api/token_oidc.go index e62940abc9..c6e37ff78f 100644 --- a/internal/api/token_oidc.go +++ b/internal/api/token_oidc.go @@ -122,7 +122,7 @@ func (p *IdTokenGrantParams) getProvider(ctx context.Context, config *conf.Globa } if !allowed { - return nil, false, "", nil, false, apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, fmt.Sprintf("Custom OIDC provider %q not allowed", p.Provider)) + return nil, false, "", nil, false, apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, "Custom OIDC provider %q not allowed", p.Provider) } cfg = &conf.OAuthProviderConfiguration{ @@ -132,7 +132,7 @@ func (p *IdTokenGrantParams) getProvider(ctx context.Context, config *conf.Globa } if !cfg.Enabled { - return nil, false, "", nil, false, apierrors.NewBadRequestError(apierrors.ErrorCodeProviderDisabled, fmt.Sprintf("Provider (issuer %q) is not enabled", issuer)) + return nil, false, "", nil, false, apierrors.NewBadRequestError(apierrors.ErrorCodeProviderDisabled, "Provider (issuer %q) is not enabled", issuer) } oidcCtx := ctx diff --git a/internal/api/web3.go b/internal/api/web3.go index 3928b1a25f..8971846e80 100644 --- a/internal/api/web3.go +++ b/internal/api/web3.go @@ -73,7 +73,7 @@ func (a *API) web3GrantSolana(ctx context.Context, w http.ResponseWriter, r *htt parsedMessage, err := siws.ParseMessage(params.Message) if err != nil { - return apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, err.Error()) + return apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, "%s", err.Error()) } if !parsedMessage.VerifySignature(signatureBytes) { @@ -219,7 +219,7 @@ func (a *API) web3GrantEthereum(ctx context.Context, w http.ResponseWriter, r *h parsedMessage, err := siwe.ParseMessage(params.Message) if err != nil { - return apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, err.Error()) + return apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, "%s", err.Error()) } if !parsedMessage.VerifySignature(params.Signature) { diff --git a/internal/conf/saml.go b/internal/conf/saml.go index a38929ebe5..9f0ec1ce15 100644 --- a/internal/conf/saml.go +++ b/internal/conf/saml.go @@ -75,16 +75,26 @@ func (c *SAMLConfiguration) Validate() error { // PopulateFields fills the configuration details based off the provided // parameters. func (c *SAMLConfiguration) PopulateFields(externalURL string) error { + certTemplate, err := c.populateFields(externalURL) + if err != nil { + return err + } + return c.createCertificate(certTemplate) +} + +// PopulateFields fills the configuration details based off the provided +// parameters. +func (c *SAMLConfiguration) populateFields(externalURL string) (*x509.Certificate, error) { // errors are intentionally ignored since they should have been handled // within #Validate() bytes, err := base64.StdEncoding.DecodeString(c.PrivateKey) if err != nil { - return fmt.Errorf("saml: PopulateFields: invalid base64: %w", err) + return nil, fmt.Errorf("saml: PopulateFields: invalid base64: %w", err) } privateKey, err := x509.ParsePKCS1PrivateKey(bytes) if err != nil { - return fmt.Errorf("saml: PopulateFields: invalid private key: %w", err) + return nil, fmt.Errorf("saml: PopulateFields: invalid private key: %w", err) } c.RSAPrivateKey = privateKey @@ -92,7 +102,7 @@ func (c *SAMLConfiguration) PopulateFields(externalURL string) error { parsedURL, err := url.ParseRequestURI(externalURL) if err != nil { - return fmt.Errorf("saml: unable to parse external URL for SAML, check API_EXTERNAL_URL: %w", err) + return nil, fmt.Errorf("saml: unable to parse external URL for SAML, check API_EXTERNAL_URL: %w", err) } host := "" @@ -125,7 +135,7 @@ func (c *SAMLConfiguration) PopulateFields(externalURL string) error { if c.AllowEncryptedAssertions { certTemplate.KeyUsage = certTemplate.KeyUsage | x509.KeyUsageDataEncipherment } - return c.createCertificate(certTemplate) + return certTemplate, nil } func (c *SAMLConfiguration) createCertificate(certTemplate *x509.Certificate) error { diff --git a/internal/conf/saml_test.go b/internal/conf/saml_test.go index aa9c1262c1..24657a9345 100644 --- a/internal/conf/saml_test.go +++ b/internal/conf/saml_test.go @@ -4,6 +4,7 @@ import ( "crypto/x509" "encoding/base64" "fmt" + "math/big" "testing" "github.com/stretchr/testify/require" @@ -97,11 +98,13 @@ func TestSAMLConfiguration(t *testing.T) { t.Run("PopulateFieldInvalidCreateCertificate", func(t *testing.T) { c := &SAMLConfiguration{ Enabled: true, - PrivateKey: base64.StdEncoding.EncodeToString([]byte("INVALID")), + PrivateKey: validPrivateKey, } + certTemplate, err := c.populateFields("https://projectref.supabase.co") + require.NoError(t, err) - tmpl := &x509.Certificate{} - err := c.createCertificate(tmpl) + certTemplate.SerialNumber = big.NewInt(-1) + err = c.createCertificate(certTemplate) require.Error(t, err) }) diff --git a/internal/e2e/e2ehooks/e2ehooks.go b/internal/e2e/e2ehooks/e2ehooks.go index 637f4f090d..2b56ca4f70 100644 --- a/internal/e2e/e2ehooks/e2ehooks.go +++ b/internal/e2e/e2ehooks/e2ehooks.go @@ -76,7 +76,6 @@ func NewHook(name v0hooks.Name) *Hook { name: name, } - //exhaustive:ignore switch name { case v0hooks.CustomizeAccessToken: // This hooks returns the exact claims given. @@ -188,7 +187,6 @@ func NewHookRecorder() *HookRecorder { } o.mux.HandleFunc("POST /hooks/{hook}", func(w http.ResponseWriter, r *http.Request) { - //exhaustive:ignore switch v0hooks.Name(r.PathValue("hook")) { case v0hooks.BeforeUserCreated: o.BeforeUserCreated.ServeHTTP(w, r) diff --git a/internal/hooks/hookshttp/hookshttp.go b/internal/hooks/hookshttp/hookshttp.go index 36df0977fe..1f7d8016b5 100644 --- a/internal/hooks/hookshttp/hookshttp.go +++ b/internal/hooks/hookshttp/hookshttp.go @@ -157,11 +157,10 @@ func (o *Dispatcher) runHTTPHook( rsp, err := client.Do(req) if err != nil && errors.Is(err, context.DeadlineExceeded) { - msg := fmt.Sprintf( + return nil, apierrors.NewUnprocessableEntityError( + apierrors.ErrorCodeHookTimeout, "Failed to reach hook within maximum time of %f seconds", o.hookTimeout.Seconds()) - return nil, apierrors.NewUnprocessableEntityError( - apierrors.ErrorCodeHookTimeout, msg) } else if err != nil { if terr, ok := err.(net.Error); ok && terr.Timeout() || i < o.hookRetries-1 { @@ -169,11 +168,10 @@ func (o *Dispatcher) runHTTPHook( "Request timed out for attempt %d with err %s", i, err) select { case <-ctx.Done(): - msg := fmt.Sprintf( + return nil, apierrors.NewUnprocessableEntityError( + apierrors.ErrorCodeHookTimeout, "Failed to reach hook within maximum time of %f seconds", o.hookTimeout.Seconds()) - return nil, apierrors.NewUnprocessableEntityError( - apierrors.ErrorCodeHookTimeout, msg) case <-time.After(o.hookBackoff): } continue @@ -198,14 +196,18 @@ func (o *Dispatcher) runHTTPHook( mediaType, _, err := mime.ParseMediaType(contentType) if err != nil { - msg := fmt.Sprintf("Invalid Content-Type header: %s", err.Error()) return nil, apierrors.NewBadRequestError( - apierrors.ErrorCodeHookPayloadInvalidContentType, msg) + apierrors.ErrorCodeHookPayloadInvalidContentType, + "Invalid Content-Type header: %s", + err.Error(), + ) } if mediaType != "application/json" { return nil, apierrors.NewBadRequestError( apierrors.ErrorCodeHookPayloadInvalidContentType, - "Invalid JSON response. Received content-type: "+contentType) + "Invalid JSON response. Received content-type: %s", + contentType, + ) } limitedReader := io.LimitedReader{R: rsp.Body, N: o.limitResponse} @@ -216,11 +218,11 @@ func (o *Dispatcher) runHTTPHook( if limitedReader.N <= 0 { // check if the response body still has excess bytes to be read if n, _ := rsp.Body.Read(make([]byte, 1)); n > 0 { - msg := fmt.Sprintf( - "Payload size exceeded size limit of %d bytes", - o.limitResponse) return nil, apierrors.NewUnprocessableEntityError( - apierrors.ErrorCodeHookPayloadOverSizeLimit, msg) + apierrors.ErrorCodeHookPayloadOverSizeLimit, + "Payload size exceeded size limit of %d bytes", + o.limitResponse, + ) } } return body, nil diff --git a/internal/tokens/service.go b/internal/tokens/service.go index a01c9dc279..3e3d7cd08d 100644 --- a/internal/tokens/service.go +++ b/internal/tokens/service.go @@ -206,7 +206,7 @@ func (s *Service) RefreshTokenGrant(ctx context.Context, db *storage.Connection, if models.IsNotFoundError(err) { return nil, apierrors.NewBadRequestError(apierrors.ErrorCodeRefreshTokenNotFound, "Invalid Refresh Token: Refresh Token Not Found") } - return nil, apierrors.NewInternalServerError(err.Error()) + return nil, apierrors.NewInternalServerError("%s", err.Error()) } responseHeaders.Set("sb-auth-user-id", user.ID.String()) @@ -283,7 +283,7 @@ func (s *Service) RefreshTokenGrant(ctx context.Context, db *storage.Connection, retry = true return terr } - return apierrors.NewInternalServerError(terr.Error()) + return apierrors.NewInternalServerError("%s", terr.Error()) } // Validate OAuth client consistency between session and current request @@ -317,7 +317,7 @@ func (s *Service) RefreshTokenGrant(ctx context.Context, db *storage.Connection, retry = true return terr } else if terr != nil { - return apierrors.NewInternalServerError(terr.Error()) + return apierrors.NewInternalServerError("%s", terr.Error()) } sessionTag := session.DetermineTag(config.Sessions.Tags) @@ -367,7 +367,7 @@ func (s *Service) RefreshTokenGrant(ctx context.Context, db *storage.Connection, if token.Revoked { activeRefreshToken, terr := session.FindCurrentlyActiveRefreshToken(tx) if terr != nil && !models.IsNotFoundError(terr) { - return apierrors.NewInternalServerError(terr.Error()) + return apierrors.NewInternalServerError("%s", terr.Error()) } if activeRefreshToken != nil && activeRefreshToken.Parent.String() == token.Token { @@ -391,7 +391,7 @@ func (s *Service) RefreshTokenGrant(ctx context.Context, db *storage.Connection, if config.Security.RefreshTokenRotationEnabled { // Revoke all tokens in token family if err := models.RevokeTokenFamily(tx, token); err != nil { - return apierrors.NewInternalServerError(err.Error()) + return apierrors.NewInternalServerError("%s", err.Error()) } }