Skip to content

[cli][menu-bar] Add iOS re-signing with a free Apple ID - #372

Draft
gabrieldonadel wants to merge 2 commits into
mainfrom
resign-support
Draft

gabrieldonadel wants to merge 2 commits into
mainfrom
resign-support

Conversation

@gabrieldonadel

@gabrieldonadel gabrieldonadel commented Sep 4, 2026 •

Copy link
Copy Markdown
Member

Why

EAS internal-distribution and development builds are code-signed for a fixed set of provisioned devices. If your iPhone is not on that build's provisioning profile, installing it fails verification and there is no way to run it locally without re-provisioning on EAS or rebuilding through Xcode. That round trip is slow and, for a build someone else produced, often not possible at all.

This lets you re-sign such a build with a free Apple ID so it installs and runs on your personal device, in one click, straight from Orbit. Free is the point: no paid Apple Developer Program membership is required.

This is the base of a two-PR stack. It adds the manual re-sign flow only; automatic 7-day renewal and App ID quota management are in the stacked follow-up PR.

How

When an install fails with a code-signature verification error, Orbit offers to re-sign and install instead of dead-ending. The heavy lifting (Apple ID auth via GSA/SRP + anisette, minting a certificate and provisioning profile on your free personal team, and codesigning) lives in the ipa-resign package; Orbit drives it through the bundled CLI and owns the UX around it.

Design decisions worth reviewing:

  • Reactive, not a general action. Re-signing is only offered when an install actually fails verification, so it stays contextual and never invites misuse on builds that don't need it.
  • Password is never stored. It is handed once to the local CLI process through a transient env var; the durable Apple session lives in ipa-resign's own store under ~/.orbit, not in Orbit. The Settings copy states this plainly.
  • Session expiry is a logout, not an error. When Apple rejects a stored session, Orbit forgets the signed-in Apple ID so every "signed in as" surface updates, and re-prompts with the email pre-filled. This avoids a stale "signed in" state that silently fails.
  • Free-account constraints are surfaced, not hidden. 2FA supports SMS fallback for accounts without a trusted device; the first successful install shows the iOS "Untrusted Developer" trust steps once per device; raw Apple/portal errors are mapped to actionable copy (locked account, agreement not accepted, rate limiting, quota).
  • Cross-platform helper wiring. macOS ships the native anisette + zsign helpers with the packaged CLI; Windows/Linux use ipa-resign's WASM anisette emulator, so no per-platform native anisette build is needed.

Test Plan

Automated (run in apps/cli and apps/menu-bar): typecheck, lint, and unit tests pass; the packaged CLI builds for both arm64 and x64 and returns clean JSON from list-app-ids / apple-id-auth probes; a dummy-credential sign-in exercises the full SRP/GSA path to Apple and comes back with a real "incorrect account information" response (proving auth + crypto work end to end in the pkg binary).

Manual (needs a physical iPhone and an internal-distribution build not provisioned for it):

  1. Attempt to install the build on the connected iPhone from Orbit; the install fails verification and Orbit offers "Resign and install".
  2. Sign in with a free Apple ID, complete 2FA (try the SMS fallback if you have no trusted device on hand).
  3. The build re-signs, installs, and launches; on first launch, trust the developer via Settings → General → VPN & Device Management.
  4. Confirm Settings shows the signed-in Apple ID and that "Sign Out" clears it.
  5. To exercise the expiry path, delete ~/.orbit/apple-resign/secrets.json and re-sign: Orbit should treat it as a logout and re-prompt with the email pre-filled rather than erroring.

Re-sign an installed build that fails code-signing so it runs on a personal
device, using a free Apple ID. When an install fails with
APPLE_APP_VERIFICATION_FAILED, Orbit offers to re-sign and install.

- CLI: `resign-ipa` and `apple-id-auth` (sign-in / verify-2fa with SMS
  fallback / sign-out) commands, driven by ipa-resign.
- Menu-bar: the resign offer + determinate progress in the popover, an Apple
  ID sign-in window (6-digit 2FA input, resend, SMS fallback), error-copy
  mapping, first-install "Untrusted Developer" trust instructions, and an
  Apple ID section in Settings (signed-in state + sign out).
- Session expiry is treated as an automatic logout: the stored Apple ID is
  forgotten and every "signed in as" surface updates, with one-tap re-auth.
- Electron/macOS wiring for the ipa-resign native anisette + zsign helpers,
  transient-env-var plumbing to pass the password to the CLI, and the
  APPLE_APP_VERIFICATION_FAILED mapping that triggers the offer.

ipa-resign@0.0.9.
…less return

- forge.config: create ./bin and ./anisette in the generateAssets hook so
  packaging (and Electron E2E, which runs 'yarn package' without
  'build:helpers') does not fail with ENOENT on the missing extraResource
  dirs. build:helpers still populates them for real builds.
- build-helpers: remove a no-useless-return that failed eslint --max-warnings 0.

This branch has not been deployed

No deployments
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.

1 participant