import Foundation struct DeviceState: Equatable { var udid: String var productType: String var productVersion: String var deviceName: String var isFmiOn: Bool? // nil = unknown / not yet checked var isSdpOn: Bool? var isSupervised: Bool? var supervisorOrgName: String? // z.B. "ReBreak" wenn schon by uns gebunden var isEnrolled: Bool? var enrollmentStatus: EnrollmentStatus? // Real-Check via NanoMDM-DB var installedProfileIDs: [String] = [] // cfgutil-list — Ground-Truth! var installedAppBundleIDs: [String] = [] // cfgutil installedApps — für Pre-Check var isManaged: Bool? var isFilterActive: Bool? /// Identifier des Enrollment-Profils — muss mit ops/mdm/enrollment-profile matchen. static let enrollmentProfileID = "org.rebreak.mdm.enrollment" /// Identifier des Lock-Sideload-Profils. static let lockProfileID = "org.rebreak.protection.contentfilter.sideload" var isOwnedByReBreak: Bool { (isSupervised == true) && (normalizedSupervisorOrgName?.localizedCaseInsensitiveCompare("ReBreak") == .orderedSame) } /// Entfernt Quotes/Whitespace aus OrganizationName damit Skip-Logik robust ist /// (z.B. wenn Tools "ReBreak" statt ReBreak liefern). var normalizedSupervisorOrgName: String? { supervisorOrgName? .trimmingCharacters(in: .whitespacesAndNewlines) .trimmingCharacters(in: CharacterSet(charactersIn: "\"'")) } /// Ground-Truth: ist das Enrollment-Profil aktuell auf dem iPhone installiert? /// (cfgutil-Liste statt NanoMDM-DB — DB hat Lag wenn User Profil manuell entfernt.) var hasEnrollmentProfile: Bool { installedProfileIDs.contains(Self.enrollmentProfileID) } var hasLockProfile: Bool { installedProfileIDs.contains(Self.lockProfileID) } /// True nur wenn iPhone supervised durch uns IST, das Enrollment-Profil tatsächlich /// installiert ist, UND MDM-Channel kürzlich aktiv war. var isFullyBound: Bool { isOwnedByReBreak && hasEnrollmentProfile && (enrollmentStatus?.isFresh == true) } var displayModel: String { Self.modelMap[productType] ?? productType } private static let modelMap: [String: String] = [ "iPhone18,4": "iPhone Air", "iPhone17,1": "iPhone 16 Pro", "iPhone17,2": "iPhone 16 Pro Max", "iPhone17,3": "iPhone 16", "iPhone17,4": "iPhone 16 Plus", "iPhone16,1": "iPhone 15 Pro", "iPhone16,2": "iPhone 15 Pro Max", "iPhone15,4": "iPhone 15", "iPhone15,5": "iPhone 15 Plus", ] }