# KeyAuthy for macOS (Apple Silicon)

A thin native shell around the live KeyAuthy web app: its own dock icon, window,
menu bar and persistent login session. Because it loads the deployed site, the
app content is always up to date, and the native shell itself auto-updates via
electron-updater.

## Build the unsigned app

```bash
cd desktop
./build-mac.sh
```

Produces `KeyAuthy-macOS-arm64-<version>.zip` containing `KeyAuthy.app`
(arm64 / Apple Silicon).

Since it is unsigned, the first launch needs: **right-click the app → Open →
Open**. After that it opens normally.

## Sign + notarize on your Mac

Run on an Apple Silicon Mac with Xcode command line tools and a Developer ID
certificate (see the header of the script for the one-time setup):

```bash
cd desktop
./sign-and-notarize.sh /Applications/KeyAuthy.app
```

This signs with the hardened runtime, notarizes with Apple, staples the ticket
and outputs a notarized `KeyAuthy-arm64.dmg` that opens with no warning.

## Automatic updates

The shell updates itself with [electron-updater](https://www.electron.build/auto-update)
— the Electron equivalent of Sparkle. It checks `https://keyauthy.com/desktop/latest-mac.yml`
8 seconds after launch, every 6 hours, and on demand via **KeyAuthy → Check for
Updates…**. New versions download in the background and install on restart.

There is an in-app **Updates** screen (KeyAuthy → Updates…, or ⌥⌘U) showing the
current version, live download progress, a manual check button, an
automatic-updates switch and the check frequency (hourly / daily / weekly /
manual). Preferences persist in `update-prefs.json` in the app's data folder.

### Shipping a release — one command

Run on your Mac:

```bash
./release.sh 1.1.0                 # bump, build, sign, notarize, staple, zip, write feed
```

Optional environment:

- `ZIP_URL=https://cdn.example.com/KeyAuthy-macOS-arm64-1.1.0.zip` — absolute
  download URL baked into the feed.
- `UPLOAD_CMD='aws s3 cp "$ZIP" s3://downloads/keyauthy/ --acl public-read'` —
  uploads the archive as part of the same run.
- `SKIP_SIGN=1` — unsigned build (auto-install will not work).

Then publish the site: `public/desktop/latest-mac.yml` ships with it and
installed copies pick up the release.

`build-mac.sh`, `sign-and-notarize.sh` and `publish-update.sh` still work
individually if you prefer running the steps by hand.

Then publish the site — `public/desktop/latest-mac.yml` is deployed with it and
installed copies pick the release up automatically.

The ~100 MB zip must be hosted outside the repo (GitHub release, S3, R2 …) and
its absolute URL passed to `publish-update.sh`. Omit the argument only if you
host the zip at `https://keyauthy.com/desktop/`.

**Code signing is required for silent updates.** Squirrel.Mac refuses to swap an
unsigned app in place; in that case the app reports the failure and offers the
download page instead.

## Notes

- Target URL defaults to `https://keyauthy.com`; override with the
  `KEYAUTHY_URL` env var when launching for testing.
- Google sign-in opens in a separate window that shares the app session, using a
  standard Chrome user agent so Google does not reject it as an embedded browser.
- Passkey unlock opens in the system browser, then returns the verified vault key
  through an encrypted, one-time loopback channel to the running desktop app.
- Microphone and camera prompts are granted only to the KeyAuthy origin.
- Renderer runs sandboxed with `contextIsolation` on and Node integration off.
- `node_modules/` and build output are git-ignored — the Electron runtime is
  ~200 MB and is downloaded at build time.
