import Darwin import FamilyControls import Foundation import PolicyCore struct NativeState: Codable { var snapshot: Snapshot? var selection = FamilyActivitySelection() var selectionRevision = UUID().uuidString var observation = Observation() var generation: String? var policyKey: String? var thresholds: [Int] = [] var monitoringReady = false var shielded = false var lastEvent = "Not configured" var monitoringError: String? } enum LocalError: LocalizedError { case message(String) var errorDescription: String? { switch self { case .message(let value): return value } } } enum StateStore { /// A process-wide UserDefaults cache is not sufficient: the app and extension both write. /// Lock one file while atomically replacing another. Corrupt state is never reset to defaults. static func withState(_ operation: (inout NativeState) throws -> T) throws -> T { guard let group = Bundle.main.object(forInfoDictionaryKey: "APCAppGroup") as? String, let directory = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: group) else { throw LocalError.message("App Group unavailable. Check signing and APC_APP_GROUP on all targets.") } let lockPath = directory.appendingPathComponent("state.lock").path let fd = open(lockPath, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR) guard fd >= 0 else { throw LocalError.message("Cannot open the shared-state lock") } defer { close(fd) } guard flock(fd, LOCK_EX) == 0 else { throw LocalError.message("Cannot lock shared state") } defer { flock(fd, LOCK_UN) } let file = directory.appendingPathComponent("state.json") var state = NativeState() if FileManager.default.fileExists(atPath: file.path) { state = try WireCoding.decoder().decode(NativeState.self, from: Data(contentsOf: file)) } let result = try operation(&state) try WireCoding.encoder().encode(state).write(to: file, options: .atomic) try FileManager.default.setAttributes( [.protectionKey: FileProtectionType.completeUntilFirstUserAuthentication], atPath: file.path ) return result } }