154 lines
5.1 KiB
Swift
154 lines
5.1 KiB
Swift
import Foundation
|
|
import Observation
|
|
|
|
enum DebugSupervisionMode: String, CaseIterable, Identifiable {
|
|
case none
|
|
case forceSupervised
|
|
case forceUnsupervised
|
|
|
|
var id: String { rawValue }
|
|
|
|
var title: String {
|
|
switch self {
|
|
case .none: return "Aus"
|
|
case .forceSupervised: return "Force Supervised"
|
|
case .forceUnsupervised: return "Force Unsupervised"
|
|
}
|
|
}
|
|
}
|
|
|
|
@MainActor
|
|
@Observable
|
|
final class WizardModel {
|
|
var step: WizardStep = .welcome
|
|
var device: DeviceState?
|
|
|
|
var supervisionLog: [String] = []
|
|
var supervisionRunning: Bool = false
|
|
var supervisionError: String?
|
|
|
|
var enrollmentLog: [String] = []
|
|
var enrollmentRunning: Bool = false
|
|
var enrollmentError: String?
|
|
|
|
var configureLog: [String] = []
|
|
var configureRunning: Bool = false
|
|
var configureError: String?
|
|
|
|
var showAdvancedLogs: Bool = false
|
|
|
|
var cooldownEndsAt: Date?
|
|
|
|
// Debug-Reset State
|
|
var supervisionMode: DebugSupervisionMode = .none
|
|
var resetRunning: Bool = false
|
|
var resetStatus: String?
|
|
var resetAll: Bool = true
|
|
var resetEnrollmentProfile: Bool = true
|
|
var resetLockProfile: Bool = true
|
|
var resetApp: Bool = true
|
|
|
|
func advance() {
|
|
if let next = WizardStep(rawValue: step.rawValue + 1) {
|
|
step = next
|
|
}
|
|
}
|
|
|
|
func goTo(_ s: WizardStep) {
|
|
step = s
|
|
}
|
|
|
|
func reset() {
|
|
step = .welcome
|
|
device = nil
|
|
supervisionLog = []
|
|
enrollmentLog = []
|
|
configureLog = []
|
|
supervisionError = nil
|
|
enrollmentError = nil
|
|
configureError = nil
|
|
showAdvancedLogs = false
|
|
cooldownEndsAt = nil
|
|
resetStatus = nil
|
|
}
|
|
|
|
func startDebugReset() {
|
|
guard device != nil else {
|
|
resetStatus = "Kein iPhone erkannt."
|
|
return
|
|
}
|
|
resetRunning = true
|
|
resetStatus = "Führe Debug-Reset aus …"
|
|
|
|
Task {
|
|
do {
|
|
var changes: [String] = []
|
|
|
|
let removeEnrollment = resetAll || resetEnrollmentProfile
|
|
let removeLock = resetAll || resetLockProfile
|
|
let removeApp = resetAll || resetApp
|
|
|
|
let installedProfileIDs = await DeviceDetector.installedProfileIDs()
|
|
var profileIDs: [String] = []
|
|
if removeEnrollment, installedProfileIDs.contains(DeviceState.enrollmentProfileID) {
|
|
profileIDs.append(DeviceState.enrollmentProfileID)
|
|
}
|
|
if removeLock, installedProfileIDs.contains(DeviceState.lockProfileID) {
|
|
profileIDs.append(DeviceState.lockProfileID)
|
|
}
|
|
if !profileIDs.isEmpty {
|
|
try await DeviceDetector.removeProfiles(identifiers: profileIDs)
|
|
changes.append("Profile gelöscht: \(profileIDs.joined(separator: ", "))")
|
|
}
|
|
|
|
if removeApp {
|
|
try await DeviceDetector.removeApp(bundleID: "org.rebreak.app")
|
|
changes.append("App gelöscht: org.rebreak.app")
|
|
}
|
|
|
|
switch supervisionMode {
|
|
case .forceSupervised:
|
|
_ = try await SuperviseRunner.supervise(verbose: false) { _ in }
|
|
changes.append("Mode gesetzt: supervised")
|
|
case .forceUnsupervised:
|
|
_ = try await SuperviseRunner.unsupervise { _ in }
|
|
changes.append("Mode gesetzt: unsupervised")
|
|
case .none:
|
|
break
|
|
}
|
|
|
|
let nowInstalledProfiles = await DeviceDetector.installedProfileIDs()
|
|
let nowApps = await DeviceDetector.installedAppBundleIDs()
|
|
let status = await DeviceDetector.readSupervisionStatus()
|
|
|
|
await MainActor.run {
|
|
if changes.isEmpty {
|
|
resetStatus = "Keine Aktion gewählt."
|
|
} else {
|
|
resetStatus = "✓ \(changes.joined(separator: " · "))"
|
|
}
|
|
|
|
if var device = self.device {
|
|
device.installedProfileIDs = nowInstalledProfiles
|
|
device.installedAppBundleIDs = nowApps
|
|
device.isSupervised = status.isSupervised
|
|
device.supervisorOrgName = status.organizationName
|
|
device.isFmiOn = status.findMyEnabled
|
|
device.isEnrolled = nowInstalledProfiles.contains(DeviceState.enrollmentProfileID)
|
|
if !nowApps.contains("org.rebreak.app") { device.isManaged = false }
|
|
if !nowInstalledProfiles.contains(DeviceState.lockProfileID) { device.isFilterActive = false }
|
|
self.device = device
|
|
}
|
|
|
|
resetRunning = false
|
|
}
|
|
} catch {
|
|
await MainActor.run {
|
|
resetStatus = "✗ Reset fehlgeschlagen: \(error.localizedDescription)"
|
|
resetRunning = false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|