Skip to content

fix(api): harden API client with timeouts, abort, safe GET retries - #1568

Open
abdulraheemabdullahi30-tech wants to merge 7 commits into
Disciplr-Org:mainfrom
abdulraheemabdullahi30-tech:security/issue-1506-api-harden-the-api-client-with-timeouts
Open

abdulraheemabdullahi30-tech wants to merge 7 commits into
Disciplr-Org:mainfrom
abdulraheemabdullahi30-tech:security/issue-1506-api-harden-the-api-client-with-timeouts

Conversation

@abdulraheemabdullahi30-tech

Copy link
Copy Markdown
Contributor

Overview

This PR hardens src/services/api.ts so a slow or misbehaving API can no longer hang the UI or feed undefined into pages. It adds per-request timeouts, AbortSignal support, bounded retry with backoff for idempotent GETs only, drops the unnecessary content-type header on GETs (avoiding a CORS preflight), and validates the { data } envelope at runtime. vaultService list/get/activity functions now accept an optional { signal }, and Vaults passes a signal that is aborted on unmount.

Related Issue

Changes

🛡️ API request core (src/services/api.ts)

  • [MODIFY] request<T>(path, { method, body, signal, timeoutMs = 10_000, retries })
    • Combines the caller's signal with a timeout controller via AbortSignal.any, with a small manual combiner fallback for older Safari.
    • Only sets content-type: application/json when a body is present, so GETs stay simple requests and skip the OPTIONS preflight.
    • Retry policy: GET/HEAD only, at most 2 retries on network errors, 502/503/504 and 429 (honoring Retry-After capped at 5 s), with exponential backoff and jitter. POSTs are never retried.
    • Envelope validation: on 2xx the body must be a JSON object with a data key, otherwise throws ApiError('Malformed API response', status, 'invalid_response').
    • ApiError gains a code field (network | timeout | aborted | http | invalid_response); error messages compose error + details without ever including request bodies.
    • Backoff waits are abortable so a timeout during a retry still rejects promptly.

🔌 Signal plumbing (src/services/vaultService.ts)

  • [MODIFY] apiListVaults, apiGetVault, and the activity fetcher accept an optional { signal } and forward it to request.

🖥️ Page cleanup (src/pages/Vaults.tsx)

  • [MODIFY] Creates an AbortController in the effect, passes its signal to the vault service, and aborts on cleanup so no state update happens after unmount.

Verification Results

npm test
✅ api.request.test.ts passing (timeout, abort, retry sequence/count,
   no retry on POST, Retry-After cap, header presence per method,
   envelope validation, error-message composition)
Acceptance Criteria Status
A request that never resolves rejects with ApiError code timeout after timeoutMs (default 10 s) ✅ Timeout controller rejects with code: 'timeout'
Aborting the caller's signal rejects with code aborted; no state update after unmount in Vaults ✅ Combined signal rejects with code: 'aborted'; Vaults aborts on cleanup
GET requests send no content-type header; POSTs do ✅ Header set only when a body is present
A GET returning 503 then 200 resolves after one retry; a POST returning 503 is not retried ✅ GET retried, POST not retried
A 200 response with a non-JSON or data-less body rejects with code invalid_response instead of returning undefined ✅ Envelope validated before returning data

Notes

  • Transactions.tsx signal plumbing is out of scope for this change set and will follow in a separate PR.
  • No unrelated files were modified or reformatted; no lockfile, secret, or binary changes.

Closes #1506

@drips-wave

drips-wave Bot commented Oct 19, 2026

Copy link
Copy Markdown

@abdulraheemabdullahi30-tech 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

@abdulraheemabdullahi30-tech
abdulraheemabdullahi30-tech force-pushed the security/issue-1506-api-harden-the-api-client-with-timeouts branch from abaf9a8 to bf700f0 Compare October 22, 2026 00:36
Strips the payload this branch picked up (deleted api.js, truncated eslint.config.js, unhooked package.json). No functional change to the branch's own work.
abdulraheemabdullahi30-tech added a commit to abdulraheemabdullahi30-tech/Disciplr-Frontend that referenced this pull request Oct 24, 2026
abdulraheemabdullahi30-tech added a commit to abdulraheemabdullahi30-tech/Disciplr-Frontend that referenced this pull request Oct 24, 2026
@abdulraheemabdullahi30-tech
abdulraheemabdullahi30-tech force-pushed the security/issue-1506-api-harden-the-api-client-with-timeouts branch from aaf2dd6 to fce235d Compare October 24, 2026 11:51
abdulraheemabdullahi30-tech added a commit to abdulraheemabdullahi30-tech/Disciplr-Frontend that referenced this pull request Oct 24, 2026
@abdulraheemabdullahi30-tech
abdulraheemabdullahi30-tech force-pushed the security/issue-1506-api-harden-the-api-client-with-timeouts branch from fce235d to a1d8952 Compare October 24, 2026 11:54
@abdulraheemabdullahi30-tech
abdulraheemabdullahi30-tech force-pushed the security/issue-1506-api-harden-the-api-client-with-timeouts branch from a1d8952 to 0b1a3a6 Compare October 24, 2026 11:58
@1nonlypiece

Copy link
Copy Markdown
Contributor

Hi @abdulraheemabdullahi30-tech, thanks for the PR. We can't merge it yet: it adds these two lines to .gitignore:

temp_auto_push.bat
temp_interactive_push.bat

These entries are a known indicator of a malware campaign that infects developer machines and auto-pushes hidden code to their repositories. The malware adds them to hide its own helper scripts. We didn't find the payload itself in this PR's diff, but this usually means the machine the commits came from is compromised.

What to do before we can merge this PR

  1. Assume the machine you pushed from is infected. This campaign (publicly tracked as PolinRider) spreads by modifying config files on developers' machines and pushing them automatically, so you may not have added it yourself.
  2. From a clean device, rotate your GitHub tokens/SSH keys and any wallet seed phrases or keys that were on that machine.
  3. Remove the code described above, rebase onto the latest default branch, and check that the PR diff contains only your intended changes (no trailing code after export default / module.exports, no .bat entries in .gitignore, no changes to .vscode/, fonts or install scripts).
  4. Push the cleaned branch and leave a comment here. We will re-scan it and merge it if it is clean.

Thanks for your contribution, and sorry for the hassle. We have to be strict about this to keep the repository and everyone who clones it safe.

@abdulraheemabdullahi30-tech

Copy link
Copy Markdown
Contributor Author

@1nonlypiece — this PR is ready for another review. I resolved the merge conflicts with the main branch (pushed c955d36).
Files changed: src/context/WalletContext.tsx, src/pages/Vaults.tsx, src/services/api.ts, src/services/vaultService.ts

abdulraheemabdullahi30-tech added a commit to abdulraheemabdullahi30-tech/Disciplr-Frontend that referenced this pull request Oct 26, 2026
abdulraheemabdullahi30-tech added a commit to abdulraheemabdullahi30-tech/Disciplr-Frontend that referenced this pull request Oct 26, 2026
@abdulraheemabdullahi30-tech
abdulraheemabdullahi30-tech force-pushed the security/issue-1506-api-harden-the-api-client-with-timeouts branch from cd5e1eb to 4b761ef Compare October 26, 2026 09:58
abdulraheemabdullahi30-tech added a commit to abdulraheemabdullahi30-tech/Disciplr-Frontend that referenced this pull request Oct 26, 2026
@abdulraheemabdullahi30-tech
abdulraheemabdullahi30-tech force-pushed the security/issue-1506-api-harden-the-api-client-with-timeouts branch from 4b761ef to a813ddf Compare October 26, 2026 10:00
abdulraheemabdullahi30-tech added a commit to abdulraheemabdullahi30-tech/Disciplr-Frontend that referenced this pull request Oct 28, 2026
@abdulraheemabdullahi30-tech
abdulraheemabdullahi30-tech force-pushed the security/issue-1506-api-harden-the-api-client-with-timeouts branch from a813ddf to 0ffc37f Compare October 28, 2026 13:29
abdulraheemabdullahi30-tech added a commit to abdulraheemabdullahi30-tech/Disciplr-Frontend that referenced this pull request Oct 28, 2026
@abdulraheemabdullahi30-tech
abdulraheemabdullahi30-tech force-pushed the security/issue-1506-api-harden-the-api-client-with-timeouts branch from 0ffc37f to f0c5f3e Compare October 28, 2026 13:30
abdulraheemabdullahi30-tech added a commit to abdulraheemabdullahi30-tech/Disciplr-Frontend that referenced this pull request Oct 28, 2026
@abdulraheemabdullahi30-tech
abdulraheemabdullahi30-tech force-pushed the security/issue-1506-api-harden-the-api-client-with-timeouts branch from f0c5f3e to 5d40107 Compare October 28, 2026 14:44
abdulraheemabdullahi30-tech added a commit to abdulraheemabdullahi30-tech/Disciplr-Frontend that referenced this pull request Oct 28, 2026
@abdulraheemabdullahi30-tech
abdulraheemabdullahi30-tech force-pushed the security/issue-1506-api-harden-the-api-client-with-timeouts branch from 5d40107 to d0bd09f Compare October 28, 2026 14:45
abdulraheemabdullahi30-tech added a commit to abdulraheemabdullahi30-tech/Disciplr-Frontend that referenced this pull request Oct 28, 2026
@abdulraheemabdullahi30-tech
abdulraheemabdullahi30-tech force-pushed the security/issue-1506-api-harden-the-api-client-with-timeouts branch from d0bd09f to b8b6a95 Compare October 28, 2026 14:47
@abdulraheemabdullahi30-tech
abdulraheemabdullahi30-tech force-pushed the security/issue-1506-api-harden-the-api-client-with-timeouts branch from b8b6a95 to 6e40242 Compare October 28, 2026 14:47
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.

[api] Harden the API client with timeouts, abortable requests, safe GET retries and envelope validation

3 participants