Skip to content

fix(#256-259): WebSocket forward-compat, 4401 refresh, recovery deep … - #358

Open
SouthToxic wants to merge 1 commit into
ethos-protocol:mainfrom
SouthToxic:fix/issues-256-257-258-259
Open

fix(#256-259): WebSocket forward-compat, 4401 refresh, recovery deep …#358
SouthToxic wants to merge 1 commit into
ethos-protocol:mainfrom
SouthToxic:fix/issues-256-257-258-259

Conversation

@SouthToxic

Copy link
Copy Markdown

…link, vault ownership

closes #256 — Add unrecognised type discriminator tests

  • Android: new test 'events ignores unknown type discriminator without crashing' in VaultEventSocketTest.kt sends a future type followed by a known one; asserts no crash and the unknown frame is silently dropped per api-contract.md.
  • iOS: test already existed (test_unknownMessageType_firesUnknownEvent); no change needed.

closes #257 — Handle WebSocket close code 4401 with silent token refresh retry

  • Android VaultEventSocket: after the incoming loop drains, await closeReason and throw Auth4401Exception for code 4401. Catch path attempts one silent refreshToken() call; on success stores the new token and reconnects immediately (no backoff); on failure emits auth_failure sentinel event and terminates the flow. Injectable 'refreshToken' lambda added for unit-test seam.
  • iOS VaultEventSocket: closeCode added to WebSocketTasking protocol so MockWebSocketTask can simulate a 4401 close. handleReceive() branches on task.closeCode == 4401 into new handleAuth4401(), which fires an injectable tokenRefresh closure; success stores token and reconnects, failure transitions state to .authFailure. ConnectionState.authFailure case added.
  • Android tests (3 new): refresh-succeeds reconnects, refresh-fails emits auth_failure, non-4401 close does not call refresh.
  • iOS tests (3 new): same three branches via MockWebSocketTask.simulateClose(code:).

closes #258 — Add /auth/recover/link deep link route

  • Android: RecoveryDeepLink(token) data class + parseRecoveryLink(Uri) in VaultDeepLinkParser; requires https scheme, exact host, path /auth/recover/link, non-empty token passing the [A-Za-z0-9_-]{1,128} allowlist.
  • iOS: DeepLink.recoveryLink(token) case in UniversalLinkRouter; /auth/recover/link route parsed in parse(url:); recoveryLink event added to DeepLinkLogger.
  • Android tests (7): well-formed URL, missing/empty token, wrong scheme/host/path, invalid token chars, over-length token, max-length token.
  • iOS tests (8): well-formed URL, missing/empty token, invalid chars, oversized token, wrong host, custom scheme, logging once.

closes #259 — Validate vault ID ownership before navigating deep links

  • Android: ownerVaultIds: Set? on VaultDeepLinkParser (null = skip check); parseUrl() and parse() reject vaults not in the set with a generic null return that does not reveal vault existence.
  • iOS: ownerVaultIDs: Set? on UniversalLinkRouter (nil = skip check); vaultAction, vaultInvitation, and beneficiaryAcceptance branches all guard through isOwnedVault() before routing.
  • Android tests (5): owned passes, unowned returns null, null set skips check, empty set rejects all, Uri variant.
  • iOS tests (6): owned passes, unowned returns nil, nil set skips check, invitation and acceptance unowned cases, empty set.

Summary

Changes

Testing

Parity checklist

This project maintains a feature-parity table in PARITY.md that
tracks which features are implemented on iOS vs Android. Please answer the
questions below before requesting review.

  • This PR does not add, change, or remove any user-facing feature on either
    platform — no PARITY.md update needed.

    — OR —

  • This PR adds/changes/removes a user-facing feature. I have updated PARITY.md:

    • Updated the status symbol(s) for the affected row(s).
    • Added or updated "Notes" if the implementation is partial or has caveats.
    • Removed or updated any rows in the "Known gaps" table that this PR closes.

Related issues

…recovery deep link, vault ownership

ethos-protocol#256 — Add unrecognised type discriminator tests
- Android: new test 'events ignores unknown type discriminator without crashing' in
  VaultEventSocketTest.kt sends a future type followed by a known one; asserts no
  crash and the unknown frame is silently dropped per api-contract.md.
- iOS: test already existed (test_unknownMessageType_firesUnknownEvent); no change needed.

ethos-protocol#257 — Handle WebSocket close code 4401 with silent token refresh retry
- Android VaultEventSocket: after the incoming loop drains, await closeReason and
  throw Auth4401Exception for code 4401. Catch path attempts one silent refreshToken()
  call; on success stores the new token and reconnects immediately (no backoff); on
  failure emits auth_failure sentinel event and terminates the flow.
  Injectable 'refreshToken' lambda added for unit-test seam.
- iOS VaultEventSocket: closeCode added to WebSocketTasking protocol so MockWebSocketTask
  can simulate a 4401 close. handleReceive() branches on task.closeCode == 4401 into new
  handleAuth4401(), which fires an injectable tokenRefresh closure; success stores token
  and reconnects, failure transitions state to .authFailure. ConnectionState.authFailure
  case added.
- Android tests (3 new): refresh-succeeds reconnects, refresh-fails emits auth_failure,
  non-4401 close does not call refresh.
- iOS tests (3 new): same three branches via MockWebSocketTask.simulateClose(code:).

ethos-protocol#258 — Add /auth/recover/link deep link route
- Android: RecoveryDeepLink(token) data class + parseRecoveryLink(Uri) in
  VaultDeepLinkParser; requires https scheme, exact host, path /auth/recover/link,
  non-empty token passing the [A-Za-z0-9_-]{1,128} allowlist.
- iOS: DeepLink.recoveryLink(token) case in UniversalLinkRouter; /auth/recover/link
  route parsed in parse(url:); recoveryLink event added to DeepLinkLogger.
- Android tests (7): well-formed URL, missing/empty token, wrong scheme/host/path,
  invalid token chars, over-length token, max-length token.
- iOS tests (8): well-formed URL, missing/empty token, invalid chars, oversized token,
  wrong host, custom scheme, logging once.

ethos-protocol#259 — Validate vault ID ownership before navigating deep links
- Android: ownerVaultIds: Set<String>? on VaultDeepLinkParser (null = skip check);
  parseUrl() and parse() reject vaults not in the set with a generic null return that
  does not reveal vault existence.
- iOS: ownerVaultIDs: Set<String>? on UniversalLinkRouter (nil = skip check);
  vaultAction, vaultInvitation, and beneficiaryAcceptance branches all guard through
  isOwnedVault() before routing.
- Android tests (5): owned passes, unowned returns null, null set skips check, empty
  set rejects all, Uri variant.
- iOS tests (6): owned passes, unowned returns nil, nil set skips check, invitation and
  acceptance unowned cases, empty set.
@drips-wave

drips-wave Bot commented Aug 31, 2026

Copy link
Copy Markdown

@SouthToxic 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

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