Repository navigation
Conversation
…t-side signing docs Issue arflexx#247: - validateEnv.ts: add JWT_SECRET_MIN_LEN=32 check so a weak secret is rejected at startup with an actionable error message, not silently accepted and then blown up inside jsonwebtoken at runtime - auth.ts: replace all four process.env['JWT_SECRET']! non-null assertions with a getJwtSecret() helper that throws a descriptive error if the secret is somehow absent at call time (second line of defence) - __tests__/validateEnv.test.ts: 7 cases covering absent secret, too-short secret, exactly-32-char secret, assertEnvValid throw behaviour, and ENCRYPTION_KEY format validation Issue arflexx#245 (docs): - docs/security.md: add 'Stellar Key Handling and Client-Side Signing Model' section explaining the /buy/prepare -> /wallet/unlock -> /buy flow and explicitly stating that buyerSecretKey is not accepted anywhere - contracts/THREAT_MODEL.md: add threat arflexx#7 documenting the original secret-in-request-body vulnerability and the implemented mitigation
…ementation - 010_withdrawals.sql: new withdrawals table with pending/processing/ completed/failed state machine, idempotency reference column, and an updated_at trigger - process-withdrawal.ts: background processor that creates a Paystack transfer recipient, initiates the transfer, moves the record to 'processing', and records a debit in the transactions ledger. Exports applyTransferSuccess / applyTransferFailed for webhook use - paystackWebhookHandlers.ts: import and re-export the two transfer settlement helpers; add applyTransferEvent dispatcher - process-paystack-webhook.ts: route transfer.success / transfer.failed / transfer.reversed events to applyTransferEvent - jobs/queue.ts: add 'process-withdrawal' to JOB_QUEUES const - jobs/index.ts: register processWithdrawalProcessor; re-export ProcessWithdrawalData type - routes/wallet.ts: POST /withdraw refactored from a synchronous inline Paystack call returning 200 to a 202 Accepted response that validates fiat_balance, creates the withdrawal record, deducts the balance, and enqueues the background job atomically inside a DB transaction
…terface - storage/StorageProvider.ts: interface with upload(key, stream, opts) and delete(key) — the only contract application code touches - storage/S3StorageProvider.ts: production implementation using @aws-sdk/client-s3 + @aws-sdk/lib-storage; supports any S3-compatible store via S3_ENDPOINT override (MinIO, R2, etc.); private ACL + AES256 server-side encryption by default - storage/LocalStorageProvider.ts: dev fallback (STORAGE_PROVIDER=local) that preserves the old uploads/kyc/ write behaviour without any AWS dep - storage/index.ts: singleton factory — selects backend from STORAGE_PROVIDER env var, lazy-imports the concrete class - routes/kyc.ts: rewritten to pipe busboy file stream directly into StorageProvider.upload() (no createWriteStream / temp disk writes); kyc_document_path now stores the object-store key, not a filesystem path; partial upload cleanup on file-too-large and field validation errors - config/validateEnv.ts: add S3_BUCKET + S3_REGION to required-when-s3 check; add STORAGE_PROVIDER / S3_ENDPOINT to OPTIONAL_ENV_VARS
|
@pugsley76 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! 🚀 |
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.
fix(#245,#246,#247,#248): security hardening, withdraw queue, KYC S3 storage
#247 — JWT_SECRET fail-fast validation
descriptive error and generation hint
a getJwtSecret() helper that throws clearly if the secret is absent
exactly-32-char, and assertEnvValid throw behaviour
#245 — Client-side signing model documented
the /buy/prepare → /wallet/unlock → /buy flow; buyerSecretKey is gone
secret-in-request-body vulnerability and its mitigation
#246 — Withdrawal stub replaced with proper async implementation
failed state machine, idempotency reference, updated_at trigger
initiates transfer, moves record to processing, records ledger debit;
exports applyTransferSuccess / applyTransferFailed for webhook settlement
transfer.success / transfer.failed / transfer.reversed
fiat_balance, creates withdrawal record, deducts balance, enqueues job —
all inside a single DB transaction
#248 — KYC file storage abstracted behind StorageProvider interface
for MinIO / R2
kyc_document_path stores object-store key not filesystem path; cleanup
on size limit and field validation errors
closes [backend] - KYC documents stored on local filesystem — breaks horizontal scaling and lost on container restart #248
closes [backend] - JWT_SECRET falls back to undefined with non-null assertion instead of failing fast at startup #247
closes [backend] - POST /api/v1/trades/:id/buy accepts buyerSecretKey in request body — secret key transmitted over the wire #245
closes [backend] - POST /api/v1/wallet/withdraw is a stub that always returns success without executing any transfer #246