- backend/api/magic/register: explicit import of MAGIC_DEVICE_LIMIT and createAdGuardClient (Nitro auto-import was missing them → ReferenceError → HTTP 500 on /api/magic/register) - mac-app: default backendBaseUrl falls back to staging.rebreak.org (app.rebreak.org serves wrong TLS cert) - native MagicSheet: fallback download/dmg URLs point to staging - native settings: Magic sheet capped at detents=[0.85] so AppHeader stays visible - bundles all in-flight Magic feature work (pair create/redeem, device endpoints, schema, adguard utils, mac-app, locales)
294 lines
13 KiB
Markdown
294 lines
13 KiB
Markdown
# Rebreak Magic (Mac)
|
|
|
|
End-User-Wizard für Self-Binding eines Macs + iPhones an Rebreak. Macht in einem 6-Step-Flow:
|
|
|
|
1. **Mac Registration** — Mac im Backend registrieren + DNS-Filter-Profil installieren
|
|
2. **Welcome** — Detect iPhone via USB (lockdownd)
|
|
3. **Pre-Flight** — Find-My-iPhone + Stolen-Device-Protection prüfen/ausschalten
|
|
4. **Supervise** — `supervise-magic` Plist-Inject + Reboot (kein Erase)
|
|
5. **Enroll** — MDM-Enrollment-Profile auf iPhone installieren
|
|
6. **Configure** — NanoMDM pusht: Lock-Profile + Take-Management + Settings(mdmSupervised=true)
|
|
|
|
Resultat:
|
|
|
|
- **Mac**: DNS-Filter aktiv (Gambling-Domains blockiert via DoH-ClientID)
|
|
- **iPhone**: supervised by "Rebreak", App nicht löschbar, NEFilter aktiv (kein User-Toggle in Settings)
|
|
|
|
## Status
|
|
|
|
✅ **Phase 2 abgeschlossen** — Backend-Auth-Integration + Mac-Registration
|
|
|
|
### Was ist neu in Phase 2?
|
|
|
|
- **Login-Gate**: User muss sich mit Rebreak-Account anmelden bevor Wizard startet
|
|
- **Mac-Device-Registration**: Jeder Mac wird im Backend registriert (max. 3 Devices pro Account)
|
|
- **DNS-Filter für Mac**: Installation eines personalisierten DNS-Filter-Profils (DoH-ClientID)
|
|
- **Managed Bindings**: UI zum Verwalten gebundener Geräte + 24h-Release-Cooldown
|
|
|
|
Siehe [PHASE2_SUMMARY.md](./PHASE2_SUMMARY.md) für Details.
|
|
|
|
## Warum "Magic"?
|
|
|
|
Normalerweise muss ein iPhone **komplett zurückgesetzt** werden um es zu supervisen (alle Daten weg, Werks-Setup, Apple-Configurator-Kabel-Pairing mit komplexem Setup).
|
|
|
|
Rebreak Magic macht das **ohne Reset** — deine Fotos, Apps, Settings bleiben. Das ist in der Branche unüblich und spart den Betroffenen massiv Zeit und Frust beim Onboarding.
|
|
|
|
**Pre-Requirement**:
|
|
|
|
- **Rebreak-Account** (Login via Supabase-Auth)
|
|
- **Rebreak-App** muss VOR Wizard-Start aus TestFlight installiert sein (nur für iPhone-Binding)
|
|
- **Config-File** mit Supabase + Backend-URLs (siehe Config-Section)
|
|
|
|
## Status
|
|
|
|
🚧 Phase 1 — Skelett. Nur lokal nutzbar (User+Olfa+Dev-iPhones).
|
|
|
|
## Voraussetzungen
|
|
|
|
| Tool | Wie |
|
|
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------- |
|
|
| Xcode 16+ | App Store |
|
|
| xcodegen | `brew install xcodegen` |
|
|
| libimobiledevice | `brew install libimobiledevice` |
|
|
| supervise-magic binary | aus `../../ops/mdm/supervise-magic/` (`make build`) |
|
|
| cfgutil | Apple Configurator (App Store) → `/Applications/Apple Configurator.app/Contents/MacOS/cfgutil` für silent profile install |
|
|
| create-dmg | `brew install create-dmg` (für DMG-Build) |
|
|
|
|
Ja. Es nutzt Apple-offizielle MDM-APIs (gleiche wie Schul-iPads). Es installiert nichts Apple-Fremdes. Die Supervision kann jederzeit aufgehoben werden (Settings → Allgemein → VPN & Geräteverwaltung → Profile entfernen → Reboot).
|
|
|
|
### Was bedeutet das für mich?
|
|
|
|
- Die Rebreak-App ist nicht mehr per "App wackelt → X tippen" löschbar
|
|
- Der NEFilter (Gambling-Domain-Blocker) lässt sich nicht in den Settings ausschalten
|
|
- Du brauchst die Rebreak-Vertrauensperson um die Bindung zu lösen
|
|
|
|
### Kann ich das rückgängig machen?
|
|
|
|
Ja, aber mit Absicht — nicht im Affekt. Siehe Rebreak-App → Settings → Trustee-Override (7-Tage-Cooldown).
|
|
|
|
### Welche Daten sieht Rebreak?
|
|
|
|
Nur dass dein Device supervised IST + an unseren MDM-Server enrollt. Keine Inhalte, keine Browsing-History, keine Telemetrie über deine Nutzung.
|
|
|
|
## Status
|
|
|
|
🚧 Phase 1 — Skelett. Nur lokal nutzbar (User+Olfa+Dev-iPhones).
|
|
|
|
## Voraussetzungen
|
|
|
|
| Tool | Wie |
|
|
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------- |
|
|
| Xcode 26+ | App Store |
|
|
| xcodegen | `brew install xcodegen` |
|
|
| libimobiledevice | `brew install libimobiledevice` |
|
|
| supervise-magic binary | aus `../../ops/mdm/supervise-magic/` (`make build`) |
|
|
| cfgutil | Apple Configurator (App Store) → `/Applications/Apple Configurator.app/Contents/MacOS/cfgutil` für silent profile install |
|
|
|
|
## Build
|
|
|
|
### Development-magic-mac
|
|
|
|
# Einmalig: dependencies + supervise-magic-binary bauen
|
|
|
|
(cd ../../ops/mdm/supervise-magic && make tidy && make build)
|
|
|
|
# Xcode-Project generieren (oder neu generieren nach project.yml Änderungen)
|
|
|
|
xcodegen generate
|
|
|
|
# Bauen + öffnen
|
|
|
|
open RebreakMagic.xcodeproj
|
|
|
|
# → ⌘R in Xcode
|
|
|
|
````
|
|
|
|
Oder CLI-only:
|
|
|
|
```bash
|
|
xcodebuild -project RebreakMagic.xcodeproj -scheme RebreakMagic -configuration Debug build
|
|
open build/Build/Products/Debug/RebreakMagic.app
|
|
````
|
|
|
|
### Production-DMG (für Distribution)
|
|
|
|
```bash
|
|
./build-dmg.sh
|
|
```
|
|
|
|
Output: `build/RebreakMagic-0.1.0.dmg`
|
|
|
|
**Hinweis**: App ist unsigned (ad-hoc signature). User braucht Right-Click → Öffnen beim ersten Start (Gatekeeper-Warning). Für Production: Developer ID Application Cert nötig.
|
|
|
|
Falls das Icon nicht sofort erscheint nach Installation:
|
|
|
|
```bash
|
|
sudo rm -rf /Library/Caches/com.apple.iconservices.store && killall Dock
|
|
```
|
|
|
|
- Notarization via `xcrun notarytool`
|
|
- Staple Notarization-Ticket: `xcrun stapler staple`
|
|
- DMG dann ohne Gatekeeper-Warning installierbar
|
|
|
|
### App-Icon
|
|
|
|
Das Rebreak-Logo ist im `Sources/Resources/Assets.xcassets/AppIcon.appiconset/` integriert (alle macOS-Größen von 16x16 bis 1024x1024). Icons werden aus `apps/rebreak-native/assets/icon.png` generiert.
|
|
|
|
Falls Icons neu generiert werden müssen (z.B. nach Logo-Update):
|
|
|
|
````bash
|
|
# Master-Icon aus rebreak-native kopieren
|
|
cp ../rebreak-native/assets/icon.png /tmp/master-icon.png
|
|
|
|
# macOS-Icon-Größen generieren via sips
|
|
cd Sources/Resources/Assets.xcassets/AppIcon.appiconset/
|
|
sips -z 16 16 /tmp/master-icon.png --out icon_16x16.png
|
|
sips -z 32 32 /tmp/master-icon.png --out icon_16x16@2x.png
|
|
sips -z 32 32 /tmp/master-icon.png --out icon_32x32.png
|
|
sips -z 64 64 /tmp/master-icon.png --out icon_32x32@2x.png
|
|
sips -z 128 128 /tmp/master-icon.png --out icon_128x128.png
|
|
sips -z 256 256 /tmp/master-icon.png --out icon_128x128@2x.png
|
|
sips -z 256 256 /tmp/master-icon.png --out icon_256x256.png
|
|
**WICHTIG**: Seit Phase 2 braucht die App ein Config-File mit Supabase + Backend-URLs.
|
|
|
|
### Schritt 1: Config-File erstellen
|
|
|
|
```bash
|
|
mkdir -p ~/.config/rebreak-magic
|
|
cp config.example.json ~/.config/rebreak-magic/config.json
|
|
chmod 600 ~/.config/rebreak-magic/config.json
|
|
````
|
|
|
|
### Schritt 2: Config-Werte eintragen
|
|
|
|
Editiere `~/.config/rebreak-magic/config.json`:
|
|
|
|
```json
|
|
{
|
|
"supabaseUrl": "https://your-project.supabase.co",
|
|
"supabaseAnonKey": "your-supabase-anon-key",
|
|
"backendBaseUrl": "https://staging.rebreak.org",
|
|
"mdmServer": "https://mdm.rebreak.org",
|
|
"mdmUser": "admin",
|
|
"mdmApiKey": "your-nanomdm-api-key"
|
|
}
|
|
```
|
|
|
|
**Wo finde ich die Werte?**
|
|
|
|
| Key | Quelle |
|
|
| ----------------- | ----------------------------------------------------------------------- |
|
|
| `supabaseUrl` | Supabase-Dashboard → Project Settings → API → Project URL |
|
|
| `supabaseAnonKey` | Supabase-Dashboard → Project Settings → API → `anon` public key |
|
|
| `backendBaseUrl` | Staging: `https://staging.rebreak.org`, Prod: `https://api.rebreak.org` |
|
|
| `mdmServer` | `https://mdm.rebreak.org` (rebreak-mdm-VM) |
|
|
| `mdmUser` | `admin` (NanoMDM-Basic-Auth-User) |
|
|
| `mdmApiKey` | `/root/.nanomdm_admin_pass` auf rebreak-mdm (32-char-hex) |
|
|
|
|
**Hinweis**: `mdmServer`, `mdmUser`, `mdmApiKey` werden nur für iPhone-Setup (Steps 5-6) benötigt. Falls du nur den Mac-DNS-Filter testen willst, kannst du Dummy-Werte eintragen.
|
|
|
|
### Alte Config (pre-Phase-2)
|
|
|
|
Falls du ein altes `~/.config/rebreak-binder/config.json` hast (nur MDM-Keys), lösche es und erstelle `~/.config/rebreak-magic/config.json` neu. Der alte Pfad wird nicht mehr verwendet
|
|
"mdmApiKey": "<32-char-hex from /root/.nanomdm_admin_pass on rebreak-mdm>"
|
|
}
|
|
EOF
|
|
chmod 600 ~/.config/rebreak-binder/config.json
|
|
|
|
````
|
|
|
|
Production-Version legt das in Keychain ab — heute reicht plain JSON.
|
|
|
|
## Troubleshooting
|
|
|
|
### iPhone wird nicht erkannt
|
|
|
|
```bash
|
|
# Prüfe libimobiledevice
|
|
idevice_id -l
|
|
# Falls leer: USB-Kabel-/Port-Problem oder "Diesem Computer vertrauen?" Dialog nicht bestätigt
|
|
|
|
# PRelated Docs
|
|
|
|
- [ops/mdm/ARCHITECTURE.md](../../ops/mdm/ARCHITECTURE.md) — MDM-Infrastruktur-Overview
|
|
- [ops/mdm/PHASES.md](../../ops/mdm/PHASES.md) — Roadmap (Self-Binding → ABM-DEP → Mac-Support)
|
|
- [ops/mdm/RUNBOOK.md](../../ops/mdm/RUNBOOK.md) — NanoMDM-Server-Operations
|
|
- [ops/mdm/supervise-magic/README.md](../../ops/mdm/supervise-magic/README.md) — supervise-magic-Technical-Deep-Dive
|
|
|
|
## License
|
|
|
|
Proprietary. © 2026 Raynis GmbH.
|
|
|
|
../../ops/mdm/supervise-magic/bin/supervise-magic --device <udid>
|
|
# Check stdout/stderr
|
|
````
|
|
|
|
### MDM-Enrollment schlägt fehl
|
|
|
|
- Prüfe NanoMDM-Server: `ssh rebreak-mdm 'pm2 status'` → `nanomdm-server` muss `online` sein
|
|
- Prüfe nginx: `ssh rebreak-mdm 'curl -I https://mdm.rebreak.org'` → 200 OK
|
|
- Prüfe APNs-Cert-Ablauf: siehe `ops/mdm/RUNBOOK.md` → APNs-Cert-Renewal-Section
|
|
|
|
### Icon wird als Placeholder angezeigt
|
|
|
|
macOS Icon-Cache clearen:
|
|
|
|
```bash
|
|
sudo rm -rf /Library/Caches/com.apple.iconservices.store
|
|
killall Dock Finder
|
|
```
|
|
|
|
Dann App neu starten.
|
|
|
|
## TODOs (post-Phase-2)
|
|
|
|
### Phase 3 (geplant)
|
|
|
|
- [ ] **Code-Signing + Notarization** (Developer-ID-Cert)
|
|
- [ ] **Unit-Tests** für AuthService, MagicAPIClient, MacDeviceDetector
|
|
- [ ] **Profile-Signierung** (Apple-Developer-Cert für DNS-Filter-Profil)
|
|
- [ ] **Offline-Retry-Logic** (Network-Error-Handling mit Retry-Button)
|
|
- [ ] **Mac-Supervision via UAMDM** (aktuell: nur DNS-Filter, keine Supervision)
|
|
|
|
### Backlog
|
|
|
|
- [ ] **Lock-Profile-Refactor**: `allowAppRemoval=false` GLOBAL raus aus `rebreak-content-filter-sideload.mobileconfig`. Per-App-Lock kommt über Managed-App-State (MDM `InstallApplication` mit `ChangeManagementState: Managed` → iOS deaktiviert App-Wackel-„X" automatisch für managed apps). Andere Apps bleiben löschbar (bessere UX).
|
|
- [ ] App-Versions-Mgmt: `InstallApplication`-Manifest-URL-Pointer auf latest IPA (siehe `ops/mdm/PHASES.md` Phase F.5)
|
|
- [ Auth-Stack\*\* (Phase 2):
|
|
- Supabase-JWT-Login (`AuthService.swift`)
|
|
- Keychain-Persistence (Service: `org.rebreak.magic`)
|
|
- Auto-Refresh bei Token-Expiry
|
|
- **Backend-API-Client** (`MagicAPIClient.swift`):
|
|
- `/api/magic/register` — Mac-Device-Registration
|
|
- `/api/magic/devices` — List own bindings
|
|
- `/api/magic/devices/{id}/request-release` — 24h-Cooldown
|
|
- `/api/magic/profile.mobileconfig` — Personalisiertes DNS-Filter-Profil (DoH-ClientID)
|
|
- **Services** sind dünne Wrapper um:
|
|
- `ideviceinfo` (libimobiledevice) — Device-Detection
|
|
- `supervise-magic` Go-CLI — Supervise + Status-Check
|
|
- `cfgutil` (optional, Apple Configurator 2) — Silent Profile-Install
|
|
- NanoMDM HTTP-API (`mdm.rebreak.org`) — InstallProfile + Settings-Commands
|
|
- `profiles` command (macOS) — Mac-DNS-Filter-Installation
|
|
- [x] Mac-Device-Registration API
|
|
- [x] DNS-Filter-Profil-Installation
|
|
- [x] Manage-Bindings-UI (Device-Limit, Release-Cooldown)
|
|
- [x] Login-Gate vor Wizard
|
|
|
|
## Architektur
|
|
|
|
- **SwiftUI macOS-App** mit `@Observable` State-Machine (`WizardModel`)
|
|
- **Services** sind dünne Wrapper um:
|
|
- `ideviceinfo` (libimobiledevice) — Device-Detection
|
|
- `supervise-magic` Go-CLI — Supervise + Status-Check
|
|
- `cfgutil` (optional, Apple Configurator 2) — Silent Profile-Install
|
|
- NanoMDM HTTP-API (`mdm.rebreak.org`) — InstallProfile + Settings-Commands
|
|
- **Kein Backend-Account-Login** für MVP — API-Key in lokalem Config
|
|
|
|
## Sicherheit
|
|
|
|
- API-Key sollte langfristig in Keychain (heute: plain JSON, chmod 600)
|
|
- App ist **unsigned** für lokales Testen — Gatekeeper-Warning beim ersten Öffnen (Right-Click → Öffnen)
|
|
- Production: Developer ID Application Cert + Notarization nötig (siehe Build → DMG)
|
|
- Process-Spawn von go-binaries braucht **disabled App-Sandbox** (gesetzt in `project.yml`)
|