Skip to content

feat(telemedicine): TURN rotation, chat-cache isolation, attachment validation, runtime response parsing - #1020

Merged
llinsss merged 1 commit into
DogStark:mainfrom
willy-de7:feat/telemedicine-security-971-974
Aug 28, 2026
Merged

llinsss merged 1 commit into
DogStark:mainfrom
willy-de7:feat/telemedicine-security-971-974

Conversation

@willy-de7

Copy link
Copy Markdown
Contributor

Summary

Security hardening for the telemedicine relay, chat cache, attachment pipeline
and mobile API response parsing. Four narrowly-scoped, dependency-free modules
(Node crypto / Buffer only, node Jest environment) plus focused unit
suites and contributor docs.

Closes #971
Closes #972
Closes #973
Closes #974

#971 — TURN credential rotation and expiry

src/services/turnCredentialService.ts

  • Ephemeral coturn-style credentials: username = <expiryUnix>:<principal>,
    credential = base64(HMAC-SHA1(sharedSecret, username)). No long-lived secret
    reaches a device; a leaked credential dies at its embedded expiry (default TTL
    300s, clamped 30s–24h).
  • verifyTurnCredential uses timingSafeEqual and accepts the previous
    secret during a rotation grace window so rotating the shared secret never
    drops an in-flight call.
  • TurnCredentialManager caches one live credential, re-issues within a 60s
    refresh skew, coalesces concurrent fetches, and exposes
    recoverExpiredSession() for the "relay rejected the session" path.

#972 — Prevent telemedicine message history leakage on logout

src/services/telemedicineChatVault.ts

  • Per-account random 256-bit data key in the secure keystore; cache rows are
    AES-256-GCM ciphertext keyed by account id (chat bodies + attachment metadata).
  • logout() / switchAccount() destroy the key first, then purge the
    cache — an interrupted purge still fails closed because leftover ciphertext is
    unreadable.
  • readHistory() returns [] when no key is present, so a newly signed-in
    account can never read the previous account's cached history.
  • Injectable SecureKeystore / CacheStore seams; InMemoryStore provided for
    tests.

#973 — Attachment malware and content-type validation for chat

src/services/attachmentValidationService.ts

  • sniffContentType identifies files by magic bytes; looksExecutable blocks
    PE / ELF / Mach-O / Java class / shell scripts / <script / <?php.
  • validateAttachment enforces MAX_ATTACHMENT_BYTES (15 MiB) and an allowlist
    (png/jpeg/gif/webp/pdf/plain), rejects empty files, and quarantines
    declared-vs-detected type mismatches and disguised executables.
  • safeDownloadHeaders returns Content-Disposition: attachment,
    X-Content-Type-Options: nosniff,
    Content-Security-Policy: default-src 'none'; sandbox,
    Cache-Control: private, no-store.
  • Filenames sanitised (strip path / traversal, [\w.-] only, 128-char cap).

#974 — Runtime response validation for mobile API services

src/services/runtimeValidation.ts

  • Tiny schema combinator (v.object/array/string/number/boolean/literal/optional)
    with .parse(){ success, data } | { success:false, issues }; rejects
    null, wrong types, NaN/Infinity, and array/object confusion with
    path-tagged issues.
  • parseResponse(schema, data, context) throws a single
    ResponseValidationError carrying every issue instead of letting malformed
    nested JSON crash a screen.
  • Wired into telemedicineService.getTelemedicineAvailability; the pattern
    extends to the remaining src/services calls incrementally.

Tests

New unit suites (synthetic data only, no secrets/tokens/health data in
fixtures or logs):

  • src/services/__tests__/turnCredentialService.test.ts — issue, TTL clamping,
    HMAC verify/tamper/expiry, rotation grace window, manager caching + refresh +
    expired-session recovery + fetch coalescing.
  • src/services/__tests__/telemedicineChatVault.test.ts — encrypted round-trip,
    ciphertext-not-plaintext at rest, [] after logout, account-switch isolation,
    key-before-cache teardown on interrupted purge, idempotent logout.
  • src/services/__tests__/attachmentValidationService.test.ts — magic-byte
    sniffing, executable/script detection, filename sanitising, type-spoof and
    disguised-executable quarantine, size/empty limits, safe headers.
  • src/services/__tests__/runtimeValidation.test.ts — happy path, malformed
    nested data yields typed issues (no throw), optional handling, type guards,
    parseResponse aggregate error.

Note: node_modules is not installed in this working copy, so the suites were
not executed locally — CI will run them. Crypto primitives (HMAC-SHA1 verify,
AES-256-GCM round-trip) were smoke-tested directly against Node.

Platform

Pure TypeScript, no native modules — iOS and Android behave identically.
Injectable keystore / cache / clock seams keep every flow testable without a
device. No UI changes.

Docs

docs/TELEMEDICINE_SECURITY.md documents all four flows.

… and response parsing

- turnCredentialService: ephemeral coturn-style TURN credentials with embedded
  expiry, HMAC verification, rotation grace window, and a client manager that
  refreshes before expiry and recovers rejected sessions (closes DogStark#971)
- telemedicineChatVault: per-account AES-256-GCM chat/attachment cache; logout
  and account switch destroy the key before purging so history never leaks to
  the next account (closes DogStark#972)
- attachmentValidationService: magic-byte content sniffing, executable/script
  blocking, size + allowlist enforcement, quarantine of spoofed types, and safe
  sandboxed download headers (closes DogStark#973)
- runtimeValidation: dependency-free schema parser returning typed validation
  failures; wired into telemedicine availability so malformed nested JSON no
  longer crashes screens (closes DogStark#974)
- docs/TELEMEDICINE_SECURITY.md covering all four flows

Tests: focused unit suites added for each module (node env, synthetic data only).
@drips-wave

drips-wave Bot commented Aug 27, 2026

Copy link
Copy Markdown

@willy-de7 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

@llinsss
llinsss merged commit 5707f3c into DogStark:main Aug 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants