import Foundation struct UserProfile: Codable, Equatable { let id: String let username: String let displayName: String } struct AuthResponse: Codable { let token: String let user: UserProfile } struct AccessKeySummary: Codable, Equatable, Identifiable { let id: String let credentialId: String let label: String let transports: [String] let deviceType: String let backedUp: Bool let aaguid: String let createdAt: String } struct AccessKeyListResponse: Codable { let credentials: [AccessKeySummary] } struct SessionResponse: Codable { let user: UserProfile } struct RegistrationOptionsResponse: Codable { struct RelyingParty: Codable { let name: String let id: String } struct UserEntity: Codable { let id: String let name: String let displayName: String } let expectedOrigin: String? let rp: RelyingParty let user: UserEntity let challenge: String } struct AuthenticationOptionsResponse: Codable { let attemptId: String let expectedOrigin: String? let challenge: String let rpId: String? } struct APIErrorResponse: Codable, Error { let message: String } struct PasskeyRegistrationPayload: Encodable { struct Response: Encodable { let clientDataJSON: String let attestationObject: String let transports: [String]? } let id: String let rawId: String let response: Response let clientExtensionResults: [String: String] let type: String } struct PasskeyAuthenticationPayload: Encodable { struct Response: Encodable { let clientDataJSON: String let authenticatorData: String let signature: String let userHandle: String? } let id: String let rawId: String let response: Response let clientExtensionResults: [String: String] let type: String } extension Data { init?(base64URLEncoded value: String) { var normalized = value.replacingOccurrences(of: "-", with: "+").replacingOccurrences(of: "_", with: "/") let padding = (4 - normalized.count % 4) % 4 normalized.append(String(repeating: "=", count: padding)) self.init(base64Encoded: normalized) } func base64URLEncodedString() -> String { base64EncodedString() .replacingOccurrences(of: "+", with: "-") .replacingOccurrences(of: "/", with: "_") .replacingOccurrences(of: "=", with: "") } } extension Encodable { func jsonString() -> String { let encoder = JSONEncoder() encoder.outputFormatting = [.withoutEscapingSlashes] guard let data = try? encoder.encode(AnyEncodable(self)), let string = String(data: data, encoding: .utf8) else { return "null" } return string } } private struct AnyEncodable: Encodable { private let encodeValue: (Encoder) throws -> Void init(_ value: some Encodable) { encodeValue = value.encode } func encode(to encoder: Encoder) throws { try encodeValue(encoder) } }