- backend: /api/magic/{register,devices,profile,release} + AdGuard provisioning + 24h cooldown
- prisma: magic_binding_fields migration (additive on UserDevice)
- mac-app: Phase 2 - Login + MacRegistration + Profile install
- marketing: landing section + /download/rebreakmagic + DMG
- lyra: forbidden phrases + RebreakMagic coach guidance
175 lines
7.1 KiB
Markdown
175 lines
7.1 KiB
Markdown
# ReBreak Magic Mac-App — Phase 2: Backend-Auth-Integration
|
|
|
|
## ✅ Implementierte Features
|
|
|
|
### 1. Auth-Stack (bereits implementiert)
|
|
- ✅ `AuthService.swift` — Supabase-Login + Keychain-Persistence
|
|
- ✅ `KeychainStore` — in AuthService integriert (Service: `org.rebreak.magic`)
|
|
- ✅ `MagicAPIClient.swift` — Backend-API-Client für `/api/magic/*`
|
|
- ✅ `MacDeviceDetector.swift` — IOPlatformUUID + hwModel via IOKit/sysctl
|
|
- ✅ `MacProfileInstaller.swift` — Profile-Download + Installation via `profiles` command
|
|
|
|
### 2. Login-UI (bereits implementiert)
|
|
- ✅ `LoginView.swift` — Email/Passwort-Login
|
|
- ✅ Error-Handling für InvalidCredentials
|
|
- ✅ Link zu "Noch kein Account? rebreak.org/signup"
|
|
- ✅ Integration in `ContentView.swift` via `model.showingLogin`
|
|
|
|
### 3. Mac-Registration-Flow (NEU implementiert)
|
|
- ✅ **Neuer WizardStep `.macRegistration`** (rawValue 0, vor .welcome)
|
|
- ✅ **`MacRegistrationView.swift`** — UI für Mac-Device-Registrierung:
|
|
- Zeigt Mac-Info (hostname, model, deviceId via IOPlatformUUID)
|
|
- Button "Mac registrieren" → ruft `model.registerMac()`
|
|
- Auto-Download + Installation des DNS-Filter-Profils
|
|
- Limit-Reached-Handling → öffnet `ManageBindingsView` (via `model.showingManageBindings`)
|
|
- Bei Erfolg: "Weiter → iPhone-Setup" button
|
|
- ✅ Integration in `ContentView.swift` switch-case
|
|
- ✅ `WizardModel.swift` erweitert:
|
|
- Initial-Step: `.macRegistration` statt `.welcome`
|
|
- `reset()` setzt auch `magicRegistration = nil` und `registrationError = nil`
|
|
|
|
### 4. Menu-Erweiterung
|
|
- ✅ Neues Command-Menu "Account" mit "Abmelden" (⌘⇧L)
|
|
- ✅ `handleLogout()` in WizardModel ruft `AuthService.signOut()` + reset
|
|
|
|
### 5. Workflow-Integration
|
|
**Neuer Flow:**
|
|
1. App startet → `authState` aus Keychain laden
|
|
2. Wenn kein Auth → `LoginView`
|
|
3. Nach Login → `.macRegistration` (Mac registrieren + Profil installieren)
|
|
4. Nach Mac-Setup → `.welcome` (iPhone-Detection wie bisher)
|
|
5. Rest unverändert: preflight → supervise → enroll → configure → done
|
|
|
|
## 📂 Neue Files
|
|
- ✅ `Sources/Views/MacRegistrationView.swift` (218 Zeilen)
|
|
|
|
## 📝 Geänderte Files
|
|
1. **`Sources/Models/WizardStep.swift`**
|
|
- Neuer Case `.macRegistration = 0`
|
|
- `.welcome` wurde von rawValue 0 → 1 (alle anderen +1)
|
|
- Titel: "Mac registrieren"
|
|
|
|
2. **`Sources/Models/WizardModel.swift`**
|
|
- Initial-Step: `var step: WizardStep = .macRegistration`
|
|
- `reset()` erweitert: setzt `magicRegistration = nil`, `registrationError = nil`
|
|
- Syntax-Fix: entfernte orphaned code-fragments
|
|
|
|
3. **`Sources/Views/ContentView.swift`**
|
|
- Switch-Case erweitert: `case .macRegistration: MacRegistrationView()`
|
|
|
|
4. **`Sources/Views/LoginView.swift`**
|
|
- macOS-Kompatibilität: `.textInputAutocapitalization(.never)` entfernt (iOS-only)
|
|
|
|
5. **`Sources/RebreakMagicApp.swift`**
|
|
- Neues Command-Menu "Account" mit "Abmelden"
|
|
|
|
## ⚙️ Config-Anforderungen
|
|
|
|
User muss `~/.config/rebreak-magic/config.json` erstellen (siehe `config.example.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"
|
|
}
|
|
```
|
|
|
|
**Benötigte Werte:**
|
|
- `supabaseUrl` + `supabaseAnonKey` — von Supabase-Dashboard
|
|
- `backendBaseUrl` — staging: `https://staging.rebreak.org`, prod: `https://api.rebreak.org`
|
|
- `mdmServer`, `mdmUser`, `mdmApiKey` — für iPhone-MDM-Commands (nur wenn iPhone-Setup durchgeführt wird)
|
|
|
|
## 🏗 Build-Status
|
|
|
|
✅ **BUILD SUCCEEDED**
|
|
|
|
```bash
|
|
cd apps/rebreak-magic-mac
|
|
xcodegen generate
|
|
xcodebuild -project RebreakMagic.xcodeproj -scheme RebreakMagic -configuration Debug build
|
|
```
|
|
|
|
**Warnings (harmlos):**
|
|
- `no 'async' operations occur within 'await' expression` bei `MainActor.run` (expected, korrekt)
|
|
|
|
## 📋 Login-Flow-Ablauf
|
|
|
|
1. **App-Start**
|
|
- `WizardModel.init()` lädt `authSession = AuthService.shared.currentSession()`
|
|
- Falls `authSession == nil` → `showingLogin = true`
|
|
|
|
2. **LoginView**
|
|
- User gibt Email + Passwort ein
|
|
- `AuthService.signIn()` → Supabase `/auth/v1/token`
|
|
- Bei Erfolg: Session in Keychain speichern
|
|
- `model.handleLogin(session)` setzt `showingLogin = false`
|
|
|
|
3. **MacRegistrationView** (neuer Step)
|
|
- Liest Mac-Info via `MacDeviceDetector.detect()`
|
|
- Button "Mac registrieren" → `model.registerMac()`
|
|
- API: `POST /api/magic/register` mit `{ deviceId, hostname, model, osVersion }`
|
|
- Response: `{ dnsToken, profileUrl, existing }`
|
|
- Auto-Download: `MagicAPIClient.downloadProfile(token)` → tmp-File
|
|
- Auto-Install: `MacProfileInstaller.downloadAndInstall()` → `profiles install -path <url>`
|
|
- Bei Limit-Reached (409): öffnet `ManageBindingsView` (Sheet)
|
|
- Bei Erfolg: "Weiter → iPhone-Setup" → `model.advance()` zu `.welcome`
|
|
|
|
4. **Rest des Wizards** (unverändert)
|
|
- `.welcome` — iPhone-Detection
|
|
- etc.
|
|
|
|
## 🔒 Security-Hinweise
|
|
|
|
- **Keychain-Service**: `org.rebreak.magic` (Account: User-Email)
|
|
- **JWT-Tokens**: Access + Refresh-Token in Keychain
|
|
- **Token-Refresh**: Auto-Refresh bei Expiry via `AuthService.refreshSessionIfNeeded()`
|
|
- **Config-File**: chmod 600 auf `~/.config/rebreak-magic/config.json` empfohlen
|
|
|
|
## 🚧 Bekannte Limitations / TODOs
|
|
|
|
1. **Profile-Installation benötigt User-Interaktion**
|
|
- `profiles install` auf macOS öffnet evtl. System-Settings-Dialog
|
|
- User muss Profil manuell bestätigen (macOS-Security-Policy)
|
|
- TODO: Anleitung in UI zeigen falls Installation fehlschlägt
|
|
|
|
2. **Keine Profile-Signierung**
|
|
- Unsigned Profiles triggern macOS-Warnung
|
|
- TODO: Apple-Developer-Cert für Profil-Signierung (Phase 3)
|
|
|
|
3. **Device-ID-Persistence**
|
|
- IOPlatformUUID ist Hardware-UUID, bleibt stabil
|
|
- Bei Mac-Hardware-Reset ändert sich UUID → neues Device im Backend
|
|
- Akzeptabel für jetzt
|
|
|
|
4. **Keine Tests**
|
|
- Unit-Tests für AuthService, MagicAPIClient kommen in Phase 3
|
|
|
|
5. **Offline-Handling**
|
|
- Bei Netzwerkfehler: Error-Message, aber kein Retry-Button
|
|
- User muss App neu starten oder "Erneut registrieren" clicken
|
|
|
|
## 📊 Code-Statistik
|
|
|
|
- **Neue Files**: 1 (`MacRegistrationView.swift`, 218 LOC)
|
|
- **Geänderte Files**: 5 (WizardStep, WizardModel, ContentView, LoginView, RebreakMagicApp)
|
|
- **Bestehende Services** (nicht geändert): AuthService, MagicAPIClient, MacDeviceDetector, MacProfileInstaller, ManageBindingsView
|
|
|
|
## 🎯 Nächste Schritte (optional für User)
|
|
|
|
1. **Config erstellen**: `cp config.example.json ~/.config/rebreak-magic/config.json` + Werte eintragen
|
|
2. **Supabase-Projekt**: URL + Anon-Key aus Supabase-Dashboard
|
|
3. **Test-Account**: User in Supabase anlegen (via Supabase-Dashboard oder Backend-Signup)
|
|
4. **App starten**: Xcode → Run, Login-Flow testen
|
|
5. **Mac-Registrierung testen**: Device-Limit-Check (max 3 Devices)
|
|
6. **Profil prüfen**: `profiles show -type configuration` → sollte `org.rebreak.protection.profile.*` enthalten
|
|
|
|
## ✨ Bonus-Feature (bereits implementiert)
|
|
|
|
- ✅ **ManageBindingsView** — zeigt eigene Magic-Bindings + Release-Button
|
|
- ✅ Erreichbar via Sheet wenn Limit-Reached
|
|
- ✅ 24h-Cooldown-Handling für Release-Requests
|