diff --git a/apps/rebreak-magic-mac/Sources/Services/MacProfileInstaller.swift b/apps/rebreak-magic-mac/Sources/Services/MacProfileInstaller.swift index 9e7e61c..f07c10c 100644 --- a/apps/rebreak-magic-mac/Sources/Services/MacProfileInstaller.swift +++ b/apps/rebreak-magic-mac/Sources/Services/MacProfileInstaller.swift @@ -1,4 +1,5 @@ import Foundation +import AppKit /// Service für Mac-DNS-Profile-Download + Installation. enum MacProfileInstaller { @@ -20,8 +21,12 @@ enum MacProfileInstaller { } } - /// Lädt Mac-DNS-Profile von Backend und installiert via `profiles install`. - /// Profile-File wird nach Installation gelöscht (enthält sensiblen Token). + /// Lädt Mac-DNS-Profile von Backend und öffnet es in System Settings → Profiles. + /// Ab macOS 15+ ist `profiles install` für Configuration Profiles entfernt + /// ("profiles tool no longer supports installs. Use System Settings + /// Profiles to add configuration profiles."). Einzig zulässiger Weg ohne + /// MDM-Enrollment: NSWorkspace öffnet die .mobileconfig → Profiles-Pane + /// erscheint → User muss manuell „Installieren" klicken + Admin-PW geben. static func downloadAndInstall(registration: MagicRegistration) async throws { // 1. Download profile let profileURL: URL @@ -31,19 +36,20 @@ enum MacProfileInstaller { throw InstallerError.downloadFailed(error.localizedDescription) } - // 2. Install via `profiles` command (macOS-only) - let result = try await ProcessRunner.run( - "/usr/bin/profiles", - arguments: ["install", "-path", profileURL.path] - ) - - // 3. Clean up downloaded file - try? FileManager.default.removeItem(at: profileURL) - - if result.exitCode != 0 { - let errorMsg = result.stderr.isEmpty ? result.stdout : result.stderr - throw InstallerError.installFailed(errorMsg) + // 2. Open in System Settings → Profiles (user must confirm in UI) + let opened = await MainActor.run { + NSWorkspace.shared.open(profileURL) } + + if !opened { + try? FileManager.default.removeItem(at: profileURL) + throw InstallerError.installFailed( + "System Settings konnte das Profil nicht öffnen. Datei liegt unter: \(profileURL.path)" + ) + } + + // NICHT löschen — System Settings braucht die Datei evtl. noch. + // OS räumt /tmp selbst auf. } /// Prüft ob ReBreak-DNS-Profile bereits installiert ist. diff --git a/apps/rebreak-magic-mac/Sources/Views/MacRegistrationView.swift b/apps/rebreak-magic-mac/Sources/Views/MacRegistrationView.swift index bc81657..d876601 100644 --- a/apps/rebreak-magic-mac/Sources/Views/MacRegistrationView.swift +++ b/apps/rebreak-magic-mac/Sources/Views/MacRegistrationView.swift @@ -196,13 +196,10 @@ struct MacRegistrationView: View { try await model.registerMac() await MainActor.run { - successMessage = "Mac erfolgreich registriert ✓" isRegistering = false } - - // Auto-trigger profile install - try await Task.sleep(nanoseconds: 500_000_000) // 0.5s delay - await handleProfileInstall() + // KEIN Auto-Profile-Install mehr — DNS-Schutz ist optional. + // User entscheidet selbst via Button. } catch { await MainActor.run { @@ -226,14 +223,15 @@ struct MacRegistrationView: View { do { try await MacProfileInstaller.downloadAndInstall(registration: registration) - // Re-check profile status - await checkProfileStatus() - await MainActor.run { isInstallingProfile = false - successMessage = "DNS-Filter-Profil installiert ✓" + successMessage = "System Settings → Profile geöffnet. Bitte dort „Installieren" klicken und Admin-Passwort eingeben." } + // Re-check profile status nach kurzer Wartezeit (User muss in UI bestätigen) + try? await Task.sleep(nanoseconds: 3_000_000_000) + await checkProfileStatus() + } catch { await MainActor.run { isInstallingProfile = false