Skip to content

[Low] Add /rotate endpoint + 'Rotate notify URL' button for leaked-URL recovery #38

@json9512

Description

@json9512

Follow-up to #6 (deliberately deferred — see PR closing #6 for the analysis).

What

When a notify URL leaks (screenshot, casual share, agent dev-box compromise), the only recovery today is uninstalling and reinstalling the iOS app so APNs hands out a new device token and UpsertByDeviceToken issues a fresh subscriber row. That works but is heavy: ~2 minutes plus losing all local app state (host configs, shortcuts, theme).

Why

Quality-of-life recovery for a real-but-low-frequency scenario. Not a security blocker — the rate limit + body cap landed in #6 already cap the damage a leaked URL can cause (notification spam, no credential exposure).

Suggested fix

Server:

  • POST /rotate accepting {"deviceToken": "..."}. Find subscriber by device token; delete + insert with fresh ID; return {"id", "notifyURL"} with the new values. Return 404 if no existing subscriber (iOS falls back to /subscribe).
  • New Store.RotateByDeviceToken(ctx, deviceToken, newIDFn, now) (Subscriber, error) interface method + SQLite (DELETE + INSERT in a tx) + Firestore (Delete doc + Create new) implementations.
  • Cover by rate limit + body cap middleware already in place from [High] Relay /subscribe and /n/<id> have no auth, rate limit, or body size cap #6.

iOS:

  • PushService.rotateSubscription() posting to /rotate and replacing local PushSubscription.
  • Settings → Push notifications → "Rotate notify URL" button (visible when subscribed). Confirmation alert: "Old notify URL stops working immediately. Agent must be reconfigured."
  • After successful rotation, auto-copy the agent setup prompt to clipboard.

Tests

  • Go: rotate happy path, rotate of unknown device token returns 404, notify on old id returns 404 post-rotate.
  • iOS: manual E2E (no URLSession mocking infrastructure yet).

Acceptance

  • /rotate end-to-end test passes.
  • iOS button rotates without re-subscription.
  • Old URL stops working immediately after rotation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions