fix(verify): close service-level typed-nil store + adapter-author guidance#289
Merged
Merged
Conversation
…dance Followups to #281 (verify replay protection) raised on the post-merge review. None blocking, all small. 1. Service-level typed-nil VerifConfirmationStoreFunc guard. The handler-level guard added in round 2 normalizes a typed-nil func to nil, but the AddVerifProvider check at auth.go was still a plain `s.opts.VerifConfirmationStore != nil` test. A typed-nil VerifConfirmationStoreFunc is a non-nil interface wrapping a nil func, so it survived that check, the in-memory default was skipped, and at redemption the handler's typed-nil guard normalized it to nil — net result: a user who wrote `Opts{VerifConfirmationStore: VerifConfirmationStoreFunc(nil)}` got neither their func nor the default, and replay protection was silently disabled for that exact configuration. Same shape as the *avatar.Proxy typed-nil case fixed in #286 with a different consequence (silent loss of protection vs panic). Apply the same shape of guard one layer up. New regression test TestService_AddVerifProvider_TypedNilStoreFuncFallsBackToDefault in both v1 and v2. 2. gofmt -w on auth.go / v2/auth.go. The verifConfirmStoreO -> verifConfirmStoreOnce rename in #281 made the field longer than the surrounding column alignment. Cosmetic; CI doesn't enforce gofmt but a noisy IDE-on-save diff for the next contributor. 3. scrubTokenFromRequest unit test (TestScrubTokenFromRequest) in both v1 and v2 — covers the defensive early-return that coveralls flagged as uncovered after #281 (token-missing returns r unchanged, nil r returns nil, token-present returns redacted clone with other query params preserved). 4. Adapter-author guidance on VerifConfirmationStore.MarkUsed godoc: tells external Redis/DB adapter authors not to embed the supplied key in returned errors, since the handler logs err on the fail-closed branch and the key is the SHA-256 of a still-live JWT.
Coverage Report for CI Build 25611934022Coverage increased (+0.09%) to 85.291%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
umputun
approved these changes
May 10, 2026
Member
umputun
left a comment
There was a problem hiding this comment.
all 4 followups look good. Tests cover the typed-nil regression and scrubTokenFromRequest, v1/v2 mirror is right. LGTM.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Followups to #281 raised on the post-merge review. None blocking, all small.
VerifConfirmationStoreFuncguard -- silently disabled replay protection forOpts{VerifConfirmationStore: VerifConfirmationStoreFunc(nil)}auth.go,v2/auth.go(+ tests)gofmt -wafter theverifConfirmStoreO->verifConfirmStoreOncerenameauth.go,v2/auth.goscrubTokenFromRequest-- the defensive early-return was uncovered after #281provider/verify_test.go,v2/provider/verify_test.goMarkUsed-- don't embed key in returned errorsprovider/verify.go,v2/provider/verify.goItem 1 in detail
The handler-level guard added in #281 round 2 (
provider/verify.goLoginHandler) correctly normalises a typed-nilVerifConfirmationStoreFuncto no-store, but the Service-level check inAddVerifProviderwas still:A typed-nil
VerifConfirmationStoreFuncis a non-nil interface wrapping a nil func, so it survives the!= nilcheck,NewInMemoryVerifStore()is skipped, and at redemption time the handler-level guard then normalises the typed-nil to nil. Net effect: a user writingOpts{VerifConfirmationStore: VerifConfirmationStoreFunc(nil)}gets neither their func nor the default in-memory store, and replay protection is silently disabled.Same shape as the
*avatar.Proxytyped-nil case fixed in #286, with a different consequence (silent loss of protection rather than panic). The fix is the same shape applied one layer up:Regression test
TestService_AddVerifProvider_TypedNilStoreFuncFallsBackToDefaultin both v1 and v2: writesvar nilFn provider.VerifConfirmationStoreFunc; ConfirmationStore: nilFn, assertsverifConfirmStoreis non-nil and is not the typed-nil func itself (i.e. the default fired).Test
go test -race ./...green in both modules;golangci-lint run --enable-only=misspell ./...clean.