import Alamofire import Foundation import LilithAgentCore import LilithLogging import SwiftyJSON private let log = AppLogger.logger(for: "MacSync.DeviceRegistration") // Internal client for registration-only calls. No module-specific endpoints. private final class RegistrationClient: BaseAPIClient, @unchecked Sendable { static let shared: RegistrationClient = { RegistrationClient(baseURL: macSyncResolveServerURL(), keychain: macSyncSharedKeychain) }() } /// Public facade for device registration — used by MacSyncApp to gate sync start. /// /// Auth token is stored in the `com.lilith.mac-sync` keychain service so all three /// module API clients (iMessage, iPhoto, iMail) share the same device identity. public enum DeviceRegistration { public static var isAuthenticated: Bool { (try? macSyncSharedKeychain.loadString(key: "authToken")) != nil } public static func register() async throws -> (deviceId: String, code: String) { let params: [String: Any] = [ "name": Host.current().localizedName ?? "Mac", "hardwareId": RegistrationClient.shared.getHardwareId(), "platform": "macos", "osVersion": ProcessInfo.processInfo.operatingSystemVersionString, ] let data = try await RegistrationClient.shared.request( "/client/devices/register", method: .post, parameters: params ) let json = JSON(data) guard json["success"].boolValue else { throw APIError.registrationFailed(reason: json["error"]["message"].stringValue) } let deviceId = json["data"]["deviceId"].stringValue let code = json["data"]["code"].stringValue try macSyncSharedKeychain.saveString(key: "deviceId", value: deviceId) log.info("registered deviceId=\(deviceId)") return (deviceId, code) } public static func checkVerification() async throws -> Bool { guard let deviceId = try macSyncSharedKeychain.loadString(key: "deviceId") else { log.warning("checkVerification — no deviceId in shared keychain") return false } let data = try await RegistrationClient.shared.request( "/client/devices/\(deviceId)/status", method: .get ) let json = JSON(data) log.info("checkVerification active=\(json["data"]["isActive"].boolValue)") guard json["success"].boolValue && json["data"]["isActive"].boolValue else { return false } if let token = json["data"]["token"].string { try macSyncSharedKeychain.saveString(key: "authToken", value: token) } return true } }