From f6fdeb1e83fb834d7dbb854a0b928dff5bfe11c9 Mon Sep 17 00:00:00 2001 From: trey Date: Sat, 11 Apr 2026 11:41:37 -0500 Subject: [PATCH] Add README --- README.md | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..6e636d3 --- /dev/null +++ b/README.md @@ -0,0 +1,85 @@ +# iOS App Store + +Self-hosted iOS OTA app distribution server. Build with your dev/distribution certs, host the IPAs, install on registered devices over the air — no Xcode tether, no TestFlight. + +## Features + +- Web UI for browsing and installing apps (mobile-friendly, dark theme) +- Drag-and-drop IPA upload with automatic metadata + icon extraction +- CLI/API uploads with token auth +- Automatic manifest plist generation for `itms-services://` installs +- Multiple builds per app, version history, release notes +- Password-protected web UI, token-protected API + +## Requirements + +- iOS device UDID registered in the provisioning profile embedded in the IPA +- IPA exported with `method: ad-hoc` (development-signed IPAs cannot be installed OTA) +- Server reachable over HTTPS with a trusted certificate + +## Stack + +Node.js + Express + SQLite + Docker. Sharp for icon resizing. No client framework — vanilla HTML/CSS/JS. + +## Endpoints + +| Method | Path | Auth | Description | +|--------|------|------|-------------| +| `GET` | `/` | session | App listing | +| `GET` | `/upload` | session | Upload page | +| `POST` | `/api/upload` | token or session | Upload IPA | +| `GET` | `/api/apps` | token or session | List apps + latest build | +| `GET` | `/api/apps/:id` | token or session | App detail with all builds | +| `DELETE` | `/api/apps/:id` | token or session | Delete app + all builds | +| `DELETE` | `/api/builds/:id` | token or session | Delete a single build | +| `GET` | `/api/manifest/:buildId` | public | Plist manifest for OTA install | +| `GET` | `/api/download/:buildId` | public | Download IPA file | +| `GET` | `/api/health` | public | Health check | + +The manifest and download endpoints are intentionally public — iOS fetches them unauthenticated during install. + +## CLI Upload + +```bash +curl -X POST https://appstore.example.com/api/upload \ + -H "X-Api-Token: $API_TOKEN" \ + -F "ipa=@path/to/YourApp.ipa" \ + -F "notes=Build notes" +``` + +Response includes the install URL (`itms-services://...`) ready to open in Safari on the device. + +## Configuration + +Copy `.env.example` to `.env` and set: + +| Variable | Description | +|----------|-------------| +| `ADMIN_PASSWORD` | Web UI login password | +| `API_TOKEN` | Token for CLI/automation uploads | +| `SESSION_SECRET` | Express session secret | +| `BASE_URL` | Public HTTPS URL of the server | +| `PORT` | Listen port (default `3000`) | + +## Deployment + +Runs as a single Docker container. The `/data` volume holds the SQLite DB, uploaded IPAs, and extracted icons. + +```bash +docker compose up -d --build +``` + +Put a reverse proxy with HTTPS in front of it. iOS requires a trusted SSL certificate for OTA installs to work. + +## Project Layout + +``` +src/ + server.js Express app, routes, middleware + db.js SQLite schema + ipa-parser.js Extracts Info.plist + icon from IPA + manifest.js Generates OTA manifest plist + auth.js Session + token auth middleware +public/ Static assets (CSS, JS) +views/ HTML pages +```