Skip to content

docs(auth, avatar): fix misleading and stale docstrings around the security fix#291

Merged
umputun merged 1 commit into
masterfrom
fix/csp-consumer-note
May 21, 2026
Merged

docs(auth, avatar): fix misleading and stale docstrings around the security fix#291
umputun merged 1 commit into
masterfrom
fix/csp-consumer-note

Conversation

@paskal
Copy link
Copy Markdown
Collaborator

@paskal paskal commented May 21, 2026

Docstring sweep over the surface touched by (or adjacent to) PR #290's
security work, prompted by Copilot's post-merge review of
withSecurityHeaders and a Codex adversarial pass over the rest of the
same surface. All changes are docstring/comment-only — no code, no
behavior change, no test churn.

Six fixes, mirrored across v1 and v2:

  • withSecurityHeaders CONSUMER NOTE (auth.go, v2/auth.go) — the
    previous text told consumers HTML custom handlers could fix CSP blocking
    by "moving scripts/styles to external files served from 'self'", but
    the wrapper applies default-src 'none' and sandbox, so even
    self-hosted resources are blocked. The example list also named "the
    dev_provider's login page", which is served by DevAuthServer on its
    own HTTP listener and is not wrapped by Service.Handlers().
    Replaced with "custom server login pages" and a concrete relaxed-CSP
    example.

  • Proxy.Put — was "stores retrieved avatar to avatar.Store. Gets
    image from user info. Returns proxied url", which omitted the identicon
    fallback that fires on empty u.Picture, fetch failure, or non-image
    upstream bytes. Doc now describes that the function silently substitutes
    an identicon in those cases — the caller is not told the upstream was
    rejected.

  • Proxy.Handler godoc — was "returns token routes for given
    provider", a leftover from a much older shape of the code. Replaced
    with what Handler actually does: serves stored avatar bytes by id,
    sniffs against an allowlist, sets defense headers.

  • Handler inline serve-time comment — said "validate the bytes really
    are an image", but Handler reads up to sniffLen bytes and runs them
    through http.DetectContentType + the allowlist. That is content-type
    sniffing, not proof of full decodability. Reworded to match.

  • Proxy.resize godoc — said "validates that the input is a real
    image", but the no-resize path returns the original bytes after only
    image.DecodeConfig and the dimension cap; no full decode runs. Split
    into format/dimension metadata checks (DecodeConfig only) vs full
    decode (resize path only).

  • maxAvatarFetchSize constant — mentioned only the remote-URL fetch
    path; after fix(avatar): prevent stored XSS via content-type spoofing #290 the cap also bounds PutContent's caller-supplied
    reader and is the implicit size invariant resize trusts. Doc now
    names both callers.

@paskal paskal requested a review from umputun as a code owner May 21, 2026 01:18
@coveralls
Copy link
Copy Markdown

coveralls commented May 21, 2026

Coverage Report for CI Build 26202851038

Coverage increased (+0.03%) to 85.425%

Details

  • Coverage increased (+0.03%) from the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 3561
Covered Lines: 3042
Line Coverage: 85.43%
Coverage Strength: 8.3 hits per line

💛 - Coveralls

@paskal paskal force-pushed the fix/csp-consumer-note branch from ca93d66 to 0da9c4f Compare May 21, 2026 01:25
@paskal paskal changed the title docs(auth): fix misleading withSecurityHeaders CONSUMER NOTE docs(auth, avatar): fix misleading and stale docstrings around the security fix May 21, 2026
paskal added a commit that referenced this pull request May 21, 2026
Pre-existing comment drift in files unrelated to the recent security fix —
unrelated docstrings that misled, said the wrong thing, or were copy-paste
leftovers. Mirrored across v1 and v2.

The security-fix docstring fixes (avatar/avatar.go security comments and
auth.go withSecurityHeaders) live in PR #291 and are intentionally NOT
included here so the two PRs stay independent.

Findings:

  * avatar/gridfs.go — ID doc claimed MD5 sourced from gridfs; metadata.hash
    is the sha1 written at Put time.
  * avatar/bolt.go, avatar/gridfs.go — Put docs and BoltDB type doc claimed
    these layers "resize" the image; they only copy bytes. Resize happens
    in Proxy.resize upstream.
  * avatar/store.go — Migrate doc didn't mention that per-avatar Get/Put/Close
    errors are logged and skipped, and that the returned count is "ids
    attempted", not "ids stored".
  * provider/oauth1.go — initOauth1Handler doc and DEBUG log both said
    "oauth2".
  * provider/service.go — Service.Handler doc said "returns auth routes";
    it dispatches login/callback/logout.
  * provider/telegram.go — processUpdates claimed to return an offset (no
    return value); checkToken doc described an "address or empty string"
    return shape but the signature is (*token.User, error).
  * provider/verify.go — Sender interface doc locked the contract to "send
    emails", contradicting the broader "email, IM, or anything else" on
    VerifyHandler. AuthHandler comment was copy-pasted from direct.
  * provider/dev_provider.go — NewDev doc said "for admin user"; just makes
    the dev oauth2 provider.
  * middleware/user_updater.go — UserUpdFunc adapter doc said result "is a
    Handler"; implements UserUpdater.
  * logger/interface.go — Func adapter doc said "Logf calls f(id)"; actually
    calls f(format, args...).
  * token/jwt.go — SendJWTHeader option doc said "instead of cookie"; Set
    sends header AND cookie. Set doc referenced a "permanent flag" that
    doesn't exist in the signature (controlled by claims.SessionOnly/Handshake).
    Get doc oversimplified the XSRF gate. Update/Validate adapter docs said
    "calls f(id)"; actually f(claims) and f(token, claims).
  * token/user.go — HashID inline "or empty" was wrong; an empty val never
    matches reValidSha.
  * auth.go — BasicAuthChecker doc grammar broken and understated behavior
    (AdminPasswd is bypassed entirely, not "ignored"); "peak dev provider"
    typo; AvatarProxy doc was a sentence fragment.

All changes mirrored across v1 and v2. Build green, lint clean, go fix clean.
@paskal paskal force-pushed the fix/csp-consumer-note branch from 0da9c4f to 75471bc Compare May 21, 2026 02:38
…curity fix

Sweep over the docstrings touched (or adjacent to) PR #290's security work,
prompted by Copilot's post-merge review of withSecurityHeaders and an
adversarial pass from Codex on the rest of the same surface. All changes are
docstring/comment-only; no code, no behavior, no test churn.

  * withSecurityHeaders CONSUMER NOTE (auth.go, v2/auth.go) — the previous
    text told consumers HTML custom handlers could fix CSP blocking by
    "moving scripts/styles to external files served from 'self'", but the
    wrapper applies default-src 'none' and sandbox, so even self-hosted
    resources are blocked. New text spells out what the wrapper actually
    does and gives a concrete relaxed-CSP example. The example list also
    drops "dev_provider's login page" — that page is served by
    DevAuthServer on its own HTTP listener, not by handlers Service.Handlers
    wraps. Replaced with "custom server login pages".

  * Proxy.Put godoc — was "stores retrieved avatar to avatar.Store. Gets
    image from user info. Returns proxied url", which omitted the identicon
    fallback that fires on empty u.Picture, fetch failure, or non-image
    upstream bytes. Doc now describes that the function silently substitutes
    an identicon in those cases and returns its proxied URL — the caller
    is not told the upstream was rejected.

  * Proxy.Handler godoc — was "returns token routes for given provider",
    a leftover from a much older shape of the code. Replaced with a
    description of what Handler actually does today: serves stored avatar
    bytes by id, sniffs against an allowlist, sets defense headers.

  * Handler's inline serve-time validation comment — said "validate the
    bytes really are an image", but Handler reads up to sniffLen bytes
    and runs them through http.DetectContentType + an allowlist. That is
    content-type sniffing, not proof of full decodability. Reworded to
    match.

  * Proxy.resize godoc — said "validates that the input is a real image",
    but the no-resize path returns the original bytes after only
    image.DecodeConfig and the dimension cap; no full decode runs. Split
    into format/dimension checks (DecodeConfig only) vs full decode (resize
    path only).

  * maxAvatarFetchSize constant — mentioned only the remote-URL fetch
    path; after #290 the cap also bounds PutContent's caller-supplied
    reader and is the implicit size invariant resize trusts. Doc updated
    to name both callers.

All changes mirrored across v1 and v2.
@paskal paskal force-pushed the fix/csp-consumer-note branch from 75471bc to 4a9b150 Compare May 21, 2026 03:01
paskal added a commit that referenced this pull request May 21, 2026
Pre-existing comment drift in files unrelated to the recent security fix —
unrelated docstrings that misled, said the wrong thing, or were copy-paste
leftovers. Mirrored across v1 and v2.

The security-fix docstring fixes (avatar/avatar.go security comments and
auth.go withSecurityHeaders) live in PR #291 and are intentionally NOT
included here so the two PRs stay independent.

Findings:

  * avatar/gridfs.go — ID doc claimed MD5 sourced from gridfs; metadata.hash
    is the sha1 written at Put time.
  * avatar/bolt.go, avatar/gridfs.go — Put docs and BoltDB type doc claimed
    these layers "resize" the image; they only copy bytes. Resize happens
    in Proxy.resize upstream.
  * avatar/store.go — Migrate doc didn't mention that per-avatar Get/Put/Close
    errors are logged and skipped, and that the returned count is "ids
    attempted", not "ids stored".
  * provider/oauth1.go — initOauth1Handler doc and DEBUG log both said
    "oauth2".
  * provider/service.go — Service.Handler doc said "returns auth routes";
    it dispatches login/callback/logout.
  * provider/telegram.go — processUpdates claimed to return an offset (no
    return value); checkToken doc described an "address or empty string"
    return shape but the signature is (*token.User, error).
  * provider/verify.go — Sender interface doc locked the contract to "send
    emails", contradicting the broader "email, IM, or anything else" on
    VerifyHandler. AuthHandler comment was copy-pasted from direct.
  * provider/dev_provider.go — NewDev doc said "for admin user"; just makes
    the dev oauth2 provider.
  * middleware/user_updater.go — UserUpdFunc adapter doc said result "is a
    Handler"; implements UserUpdater.
  * logger/interface.go — Func adapter doc said "Logf calls f(id)"; actually
    calls f(format, args...).
  * token/jwt.go — SendJWTHeader option doc said "instead of cookie"; Set
    sends header AND cookie. Set doc referenced a "permanent flag" that
    doesn't exist in the signature (controlled by claims.SessionOnly/Handshake).
    Get doc oversimplified the XSRF gate. Update/Validate adapter docs said
    "calls f(id)"; actually f(claims) and f(token, claims).
  * token/user.go — HashID inline "or empty" was wrong; an empty val never
    matches reValidSha.
  * auth.go — BasicAuthChecker doc grammar broken and understated behavior
    (AdminPasswd is bypassed entirely, not "ignored"); "peak dev provider"
    typo; AvatarProxy doc was a sentence fragment.

All changes mirrored across v1 and v2. Build green, lint clean, go fix clean.
@umputun umputun merged commit ba35ab3 into master May 21, 2026
9 checks passed
@umputun umputun deleted the fix/csp-consumer-note branch May 21, 2026 03:12
umputun pushed a commit that referenced this pull request May 21, 2026
Pre-existing comment drift in files unrelated to the recent security fix —
unrelated docstrings that misled, said the wrong thing, or were copy-paste
leftovers. Mirrored across v1 and v2.

The security-fix docstring fixes (avatar/avatar.go security comments and
auth.go withSecurityHeaders) live in PR #291 and are intentionally NOT
included here so the two PRs stay independent.

Findings:

  * avatar/gridfs.go — ID doc claimed MD5 sourced from gridfs; metadata.hash
    is the sha1 written at Put time.
  * avatar/bolt.go, avatar/gridfs.go — Put docs and BoltDB type doc claimed
    these layers "resize" the image; they only copy bytes. Resize happens
    in Proxy.resize upstream.
  * avatar/store.go — Migrate doc didn't mention that per-avatar Get/Put/Close
    errors are logged and skipped, and that the returned count is "ids
    attempted", not "ids stored".
  * provider/oauth1.go — initOauth1Handler doc and DEBUG log both said
    "oauth2".
  * provider/service.go — Service.Handler doc said "returns auth routes";
    it dispatches login/callback/logout.
  * provider/telegram.go — processUpdates claimed to return an offset (no
    return value); checkToken doc described an "address or empty string"
    return shape but the signature is (*token.User, error).
  * provider/verify.go — Sender interface doc locked the contract to "send
    emails", contradicting the broader "email, IM, or anything else" on
    VerifyHandler. AuthHandler comment was copy-pasted from direct.
  * provider/dev_provider.go — NewDev doc said "for admin user"; just makes
    the dev oauth2 provider.
  * middleware/user_updater.go — UserUpdFunc adapter doc said result "is a
    Handler"; implements UserUpdater.
  * logger/interface.go — Func adapter doc said "Logf calls f(id)"; actually
    calls f(format, args...).
  * token/jwt.go — SendJWTHeader option doc said "instead of cookie"; Set
    sends header AND cookie. Set doc referenced a "permanent flag" that
    doesn't exist in the signature (controlled by claims.SessionOnly/Handshake).
    Get doc oversimplified the XSRF gate. Update/Validate adapter docs said
    "calls f(id)"; actually f(claims) and f(token, claims).
  * token/user.go — HashID inline "or empty" was wrong; an empty val never
    matches reValidSha.
  * auth.go — BasicAuthChecker doc grammar broken and understated behavior
    (AdminPasswd is bypassed entirely, not "ignored"); "peak dev provider"
    typo; AvatarProxy doc was a sentence fragment.

All changes mirrored across v1 and v2. Build green, lint clean, go fix clean.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants