Skip to content

feat: resolve issues #491 #492 #493 #494 - #583

Merged
legend-esc merged 2 commits into
legend-esc:mainfrom
edwarddavid929-png:feature/issues-491-492-493-494
Jul 25, 2026
Merged

feat: resolve issues #491 #492 #493 #494#583
legend-esc merged 2 commits into
legend-esc:mainfrom
edwarddavid929-png:feature/issues-491-492-493-494

Conversation

@edwarddavid929-png

Copy link
Copy Markdown
Contributor

Summary

Resolves #491, #492, #493, #494


#491 — JWT logout via Redis blocklist

  • auth.service.ts: verifyAndIssueToken now includes a jti (UUID v4) claim in all issued tokens. Added logout(token) to store the jti in Redis with remaining TTL, and isTokenRevoked(jti) for guard checks.
  • jwt-auth.guard.ts: Rewritten with LRU in-memory cache (1000-entry cap, <1ms on hit) + Redis fallback blocklist check. Tokens without jti are rejected as unrevocable.
  • stellar-auth.strategy.ts: Forwards jti through req.user.
  • auth.controller.ts: Added POST /auth/logout (JWT-protected, returns 200).
  • auth.module.ts: JwtAuthGuard provided with AuthService dependency properly wired.

#492 — Per-account rate limiting on POST /auth/verify

  • throttler.guard.ts: Rewritten with dual-mode. Standard @Throttle = IP-only (in-memory, backward-compatible). New @AccountThrottle = per-account + per-IP, Redis-backed (INCR/EXPIRE with in-memory fallback). Returns Retry-After header on 429.
  • auth.controller.ts: Added POST /auth/verify with @AccountThrottle({ accountLimit: 10, ipLimit: 50, ttl: 300_000 }).
  • throttler.guard.spec.ts: Updated for async canActivate + full account-throttle test suite.

#493 — CertificateService error recovery + wired IPFS

  • certificate.service.ts: Worker construction wrapped in try/catch for DataCloneError. Worker messages checked for { error } object. Pinata circuit breaker — IPFS failure returns { pdfBuffer, ipfsHash: null } instead of throwing.
  • pdf.worker.js: Generation wrapped in try/catch; errors posted via parentPort.postMessage({ error }) instead of throwing to uncaught handler.
  • retirement.service.ts: CertificateService injected @Optional(). retire() now calls generateAndPin() and returns real certificateIpfsHash; Pinata failure is logged and does not abort the retirement.
  • certificate.service.spec.ts: Added Pinata failure tests (ECONNREFUSED, 503, success, DataCloneError).

#494 — POST /credits/bulk parallelisation + validation

  • credits.service.ts: getBulkCredits rewritten with Promise.allSettled for parallel fetches. Invalid hex IDs skipped (partial result, not 400). Each fetched credit individually cached.
  • credits.controller.ts: POST /bulk now uses BulkCreditsDto with ValidationPipe.
  • dto/bulk-credits.dto.ts: New DTO with @ArrayMaxSize(100), @ArrayMinSize(1).

Tests

Chore

  • .gitignore: test_snapshots/, __snapshots__/, *.snap, coverage/, karma output, jest cache excluded.

…end-esc#494

legend-esc#492 - Per-account Redis-backed rate limiting on POST /auth/verify
- Rewrite ThrottlerGuard: dual-mode IP + per-account, Redis INCR/EXPIRE
  with in-memory fallback; Retry-After header on 429
- Add AccountThrottle decorator and POST /auth/verify route
- Update throttler.guard.spec.ts for async canActivate + account mode

legend-esc#491 - JWT logout via Redis blocklist
- Sign tokens with jti (UUID v4) claim in verifyAndIssueToken
- Add AuthService.logout() stores jti in Redis with remaining TTL
- Add AuthService.isTokenRevoked() for guard check
- Rewrite JwtAuthGuard: LRU in-memory cache for hot revoked JTIs,
  Redis fallback; rejects tokens without jti (legacy tokens)
- Update StellarAuthStrategy to forward jti to req.user
- Add POST /auth/logout route (JWT-protected, returns 200)

legend-esc#493 - CertificateService error recovery + wire IPFS
- Wrap Worker construction in try/catch for DataCloneError
- Handle worker message with { error } field from pdf.worker.js
- pdf.worker.js: wrap generation in try/catch, post errors via
  parentPort.postMessage({ error }) instead of throwing
- Wire CertificateService.generateAndPin() into retire()
- Pinata circuit breaker: IPFS failure returns null hash, retirement
  still succeeds with a logged warning
- Add Pinata failure path tests to certificate.service.spec.ts

legend-esc#494 - POST /credits/bulk parallelisation + validation
- Rewrite getBulkCredits with Promise.allSettled (parallel fetches)
- Filter invalid hex IDs before fetching (skip, not 400)
- Add BulkCreditsDto with ArrayMaxSize(100) validation
- Wire ValidationPipe on POST /credits/bulk controller route

Tests:
- security.e2e-spec.ts: per-account rate limit scenarios
- jwt-auth.e2e-spec.ts: logout flow, jti claim, legacy token rejection

Chore:
- Update .gitignore: test_snapshots/, __snapshots__/, *.snap, coverage/,
  karma output, jest cache, build artifacts
@legend-esc
legend-esc merged commit 2f6d58c into legend-esc:main Jul 25, 2026
1 of 4 checks 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.

Implement POST /api/v1/auth/logout — JWT invalidation via Redis blocklist

2 participants