Skip to content

feat(backend): compile queue, SEP-10 auth, validation middleware, rate limiter - #1464

Open
trustjosh4-dev wants to merge 1 commit into
StellarDevHub:mainfrom
trustjosh4-dev:feat/compile-queue-sep10-validation-ratelimiter
Open

trustjosh4-dev wants to merge 1 commit into
StellarDevHub:mainfrom
trustjosh4-dev:feat/compile-queue-sep10-validation-ratelimiter

Conversation

@trustjosh4-dev

Copy link
Copy Markdown

Summary

Implements four production-ready backend features across the compilation pipeline, authentication, input validation, and rate limiting subsystems.


Changes

#1381 — Redis BullMQ Compile Queue & Distributed Worker

Files: backend/src/queues/compileQueue.ts, backend/src/workers/compileWorker.ts

  • Queue (compileQueue.ts): BullMQ Queue<CompileJobData> with three priority tiers — HIGH=1 (premium/API-key), NORMAL=5 (authenticated), LOW=10 (anonymous). enqueueCompileJob() validates source code (non-empty, ≤500 KB, valid language), deduplicates by userId + source hash via jobId, and returns job metadata for WebSocket polling. Redis connection parsed from REDIS_URL (follows project pattern). Configurable retry: 3 attempts with exponential back-off (3 s → 6 s → 12 s).
  • Worker (compileWorker.ts): Distributed BullMQ Worker consuming from the same queue. Concurrency throttled by COMPILE_WORKER_CONCURRENCY env var (default 2 — Rust builds are CPU/RAM intensive). Per-job timeout enforced via COMPILE_TIMEOUT_MS (default 5 min). Progress streaming: each build phase (preparing → compiling → linking → packaging → completed/failed) emits a compile_progress event via broadcastEvent() to the student's private Socket.IO room. Graceful shutdown via closeCompileWorker().

#1383 — SEP-10 Stellar Web Authentication (Production Provider)

File: backend/src/auth/sep10.service.ts

  • Nonce binding: Each buildSep10Challenge() call generates a 32-byte cryptographically random nonce stored in Redis alongside the transaction hash (sep10:ch:<txHash> → {accountId, nonce}). After successful verification the nonce is embedded in JWT claims (sep10Nonce).
  • Per-account rate limiting: Sliding-window check (10 challenges / 60 s per wallet address) using Redis sorted sets. Returns RATE_LIMITED error code; fails open if Redis is unavailable.
  • Atomic replay prevention: verifySep10Challenge() checks sep10:used:<txHash> before marking it used — concurrent replays both observe the existing key and fail. TTL = challenge lifetime + 60 s verification window.
  • Fail-closed on Horizon errors: Non-404 Horizon responses throw immediately; only unfunded (404) accounts fall back to threshold=1 per SEP-10 spec.
  • Hardened JWT claims: Token payload extended with walletAddress and sep10Nonce for downstream authorization.

✅ Acceptance criteria: Replaying an existing signed challenge fails; valid signatures receive authenticated session JWTs.


#1385 — Universal Zod Validation Middleware

File: backend/src/middleware/validation.ts

  • stripPrototypePollutingKeys(): Recursively removes __proto__, constructor, prototype, and other dangerous keys before any handler or schema sees the payload. Runs inside both validateInput (global) and validate() (per-route).
  • extractSchemaKeys(): Traverses Zod optional/nullable/default wrappers to extract top-level ZodObject shape keys at route-registration time — zero cost per request.
  • stripUnwhitelistedKeys(): Drops any body key not declared in the schema, eliminating mass-assignment vectors (e.g. isAdmin: true injected into a register body).
  • validate() factory: Pre-computes allowed keys; per-request pipeline is stripPrototypePollutingKeys → stripUnwhitelistedKeys → schema.parse. Error responses use the project's versioned ApiError envelope and never echo submitted values.
  • validateInput global guard: Prototype pollution stripping runs before HTML sanitization in the global middleware layer.

#1384 — Redis-backed Distributed Rate Limiter

File: backend/src/middleware/rateLimiter.ts

  • Spoofing-resistant IP extraction (extractClientIp()): Reads TRUSTED_PROXY_DEPTH (default 0) and walks the X-Forwarded-For header right-to-left by that many hops. When the header has fewer entries than the configured depth, falls back to the socket address and logs a warning.
  • API key tier quotas (ApiKeyTierConfig): Loaded from RATE_LIMIT_API_KEY_TIERS_JSON env var (JSON array of {prefix, burstMax, sustainedMax}). resolveApiKeyTier() matches the request's X-API-Key or Authorization: ApiKey <key> header against configured prefixes.
  • Unified rate-limit key selection: API key holders → apikey:<key[:24]>; authenticated users → user ID; anonymous → spoofing-resistant IP. Guarantees each principal has a single quota bucket regardless of originating IP.
  • Existing sliding-window Redis sorted-set logic and enforceTier() / RFC 6585 headers preserved unchanged.

Environment Variables Added

Variable Default Description
COMPILE_WORKER_CONCURRENCY 2 Max concurrent Rust builds per worker process
COMPILE_TIMEOUT_MS 300000 Per-job compilation timeout in ms (5 min)
TRUSTED_PROXY_DEPTH 0 Trusted reverse-proxy hops for IP extraction
RATE_LIMIT_API_KEY_TIERS_JSON [] JSON array of API key tier configs

Closes #1381
Closes #1383
Closes #1385
Closes #1384

…e limiter

Implements four interconnected backend features:

## StellarDevHub#1381 — Redis BullMQ Compile Queue & Distributed Worker
- backend/src/queues/compileQueue.ts: Queue with 3 priority tiers
  (HIGH=1, NORMAL=5, LOW=10), enqueueCompileJob() helper with
  source-code validation, 500 KB size limit, and dedup by jobId
- backend/src/workers/compileWorker.ts: Distributed BullMQ Worker
  with COMPILE_WORKER_CONCURRENCY throttle (default 2), global
  token-bucket limiter, per-job WebSocket progress streaming via
  broadcastEvent(), graceful shutdown handler

## StellarDevHub#1383 — SEP-10 Stellar Web Authentication (Production Provider)
- backend/src/auth/sep10.service.ts: Enhanced with:
  - Cryptographic nonce (32-byte) generated per challenge and stored
    in Redis alongside the transaction hash for binding
  - Per-account sliding-window rate limit (max 10 challenges/60s)
  - Atomic Redis SET NX replay prevention (challenge hash marked used
    before signature verification so concurrent replays both fail)
  - JWT claims include walletAddress + sep10Nonce for downstream
    authorization and audit trail
  - Fail-closed on Horizon non-404 errors
- Acceptance criteria met: replaying a signed challenge returns error;
  valid signatures receive authenticated session JWTs

## StellarDevHub#1385 — Universal Zod Validation Middleware
- backend/src/middleware/validation.ts: Enhanced with:
  - stripPrototypePollutingKeys(): recursively removes __proto__,
    constructor, prototype before any handler sees the payload
  - extractSchemaKeys(): extracts declared ZodObject keys at route
    registration time (zero overhead per request)
  - stripUnwhitelistedKeys(): drops any body keys not declared in the
    Zod schema (mass-assignment protection)
  - validate() factory pre-computes allowed keys and applies both
    prototype pollution guard and key whitelist on every request

## StellarDevHub#1384 — Redis-backed Distributed Rate Limiter
- backend/src/middleware/rateLimiter.ts: Enhanced with:
  - extractClientIp(): TRUSTED_PROXY_DEPTH-aware X-Forwarded-For
    parsing -- walks right-to-left to avoid header spoofing
  - ApiKeyTierConfig loaded from RATE_LIMIT_API_KEY_TIERS_JSON env
    var; keys matching a configured prefix receive higher burst and
    sustained quotas
  - resolveApiKeyTier(): returns the matching tier or null for default
  - Single unified rate-limit key per request (API key > user > IP)
    so authenticated users with API keys have one quota bucket

Closes StellarDevHub#1381
Closes StellarDevHub#1383
Closes StellarDevHub#1385
Closes StellarDevHub#1384
@vercel

vercel Bot commented Sep 29, 2026

Copy link
Copy Markdown

@trustjosh4-dev is attempting to deploy a commit to the Ayomide Adeniran's projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented Sep 29, 2026

Copy link
Copy Markdown

@trustjosh4-dev Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant