Skip to content

fix/feat: webhook reliability, Jellyfin Content-Type fix, Seerr rebrand#79

Merged
retardgerman merged 10 commits intomainfrom
dev
Mar 16, 2026
Merged

fix/feat: webhook reliability, Jellyfin Content-Type fix, Seerr rebrand#79
retardgerman merged 10 commits intomainfrom
dev

Conversation

@retardgerman
Copy link
Contributor

@retardgerman retardgerman commented Mar 15, 2026

Summary

Webhook reliability fixes

  • Debounce error cleanup: A failed Discord send no longer silently blocks notifications for a series — previously it could take up to 24 hours before new webhooks for the same series were processed again
  • Temp marker timeout: Reduced orphaned marker cleanup from 24h to 5min so subsequent webhooks are not blocked
  • Empty channel guard: If no Discord channel is configured for a library, the webhook logs a clear config error instead of crashing with a cryptic Discord API exception
  • Better error logs: Webhook errors and warnings now include item type and name for easier debugging

Persist pending DM requests across restarts

  • Add savePendingRequests() / loadPendingRequests() helpers writing pending-requests.json next to config.json
  • Pending requests are saved on every write and loaded on bot startup — users who requested media via /request now still receive their DM notification even if the bot was restarted

Jellyfin webhook Content-Type fix

  • express.json() was silently rejecting Jellyfin webhook bodies because Jellyfin sends Content-Type: text/plain — changed to express.json({ type: "*/*" }) to accept any content type
  • Added empty-body guard with a descriptive warning log
  • Webhook secret field in the dashboard is now populated on page load so the value is visible and copyable

Seerr rebrand (Jellyseerr → Seerr)

  • Renamed api/jellyseerr.jsapi/seerr.js
  • Renamed all JELLYSEERR_* config keys to SEERR_* (URL, API_KEY, AUTO_APPROVE)
  • Renamed jellyseerr* user mapping keys to seerr* (UserId, Username, DisplayName)
  • Updated all variable names, function names, i18n keys, DOM IDs, CSS classes, and docs
  • Updated repo link to https://github.com/seerr-team/seerr in README and docs
  • Added startup auto-migration so existing config.json and USER_MAPPINGS with old keys are silently upgraded on first boot
  • Third-party API paths (/api/v1/*) left unchanged — server-side paths are unaffected

Login brute-force protections (ref #80)

  • Account lockout: 10-minute lockout after 5 consecutive failed attempts per username (HTTP 429 with seconds remaining)
  • Progressive delays: Each failed attempt adds a 300ms response delay (capped at 4s) to slow automated tools
  • Timing safety: bcrypt always runs even for unknown usernames to prevent user enumeration via timing differences
  • Existing IP-based rate limit (20 req / 15 min) remains as a first layer

…uests (H5)

Webhook reliability fixes:
- Clean up sentNotifications temp marker (-1) on debounce error so a
  failed Discord send doesn't silently block the series for 24 hours
- Reduce temp marker cleanup timeout from 24h to 5min so orphaned
  markers are cleared quickly without blocking subsequent webhooks
- Guard against empty channelId before hitting Discord API — logs a
  clear config error instead of a cryptic API failure
- Include ItemType and Name in webhook error/warning logs for easier
  debugging without having to parse the raw payload

H5 — Persist pendingRequests to disk:
- Add savePendingRequests() / loadPendingRequests() helpers writing
  pending-requests.json next to config.json (mode 0600)
- Call savePendingRequests() after every write (3 interaction sites)
- Call onPendingRequestsChanged() callback in handleJellyfinWebhook
  after deleting a fulfilled request so the file stays in sync
- Call loadPendingRequests() on bot startup so DM notifications for
  in-flight requests survive service restarts
- Rename api/jellyseerr.js to api/seerr.js
- Rename all JELLYSEERR_* config keys to SEERR_* (URL, API_KEY, AUTO_APPROVE)
- Rename jellyseerr* user mapping keys to seerr* (UserId, Username, DisplayName)
- Update all variable names, function names, i18n keys, DOM IDs, CSS, docs
- Add startup auto-migration for old JELLYSEERR_* keys and USER_MAPPINGS
- Update repo link to https://github.com/seerr-team/seerr in README and docs
- Third-party API paths (/api/v1/*) left unchanged — server-side paths unaffected
@retardgerman retardgerman changed the title fix: webhook notifications dropped silently after errors, DM requests lost on restart fix/feat: webhook reliability, Jellyfin Content-Type fix, Seerr rebrand Mar 16, 2026
…ilures

- Lock account for 10 minutes after 5 consecutive failed login attempts
- Add progressive response delay (300ms * attempt count, capped at 4s) to slow brute-force
- Log failed attempts and lockouts with username and source IP
- Clear failure counter on successful login
- Always run bcrypt compare even for unknown usernames to prevent user enumeration via timing
- Existing IP-based rate limit (20 req/15min) remains in place as a first layer
- Escape discordUserId with escapeHtml() in displayMappings() onclick attribute
- Restrict discordUserId validation to Discord snowflake format (17-19 digits)
- Restrict seerrUserId to numeric strings only

Fixes stored XSS where an attacker with dashboard access could inject
arbitrary JS into the user-mapping Remove button, executing in any
admin's browser context on page load.
…h, duplicate fetch

- auth.js: cancel previous cleanup timer before scheduling new one in recordFailure
  so a single username under attack doesn't accumulate unbounded setTimeout handles
- auth.js: return new entry from recordFailure to eliminate second Map.get call
  in the login handler immediately after the write
- app.js: /api/webhook-secret now returns in-memory WEBHOOK_SECRET instead of
  calling readConfig() on every request
- web/script.js: copy-secret button reads from the already-populated input field
  instead of making a second fetch to /api/webhook-secret
Add [1.4.3] entry covering: Seerr rebrand (JELLYSEERR_* → SEERR_*
with auto-migration), login brute-force protections (ref #80), XSS fix
on discordUserId onclick, Jellyfin Content-Type fix, webhook debounce
error cleanup, empty channel guard, pending requests persistence, and
associated refactors.
@retardgerman retardgerman merged commit 7c704b7 into main Mar 16, 2026
1 check passed
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.

1 participant