Files
Kecalek_python/ios_client 0.8.5/Kecalek/Models/DeviceBundle.swift
2026-03-14 12:43:56 +01:00

70 lines
2.6 KiB
Swift

import Foundation
/// Key bundle for one device, used in X3DH
struct DeviceBundle {
let deviceId: String
let identityKey: Data // Ed25519 public key (32 bytes)
let spk: Data // X25519 public key (32 bytes)
let spkSignature: Data // Ed25519 signature (64 bytes)
let spkId: String
let opk: Data? // X25519 public key (32 bytes), optional
let opkId: String?
/// Parse from server response dictionary
/// Server uses: signed_prekey, signed_prekey_id, one_time_prekey, one_time_prekey_id (base64)
static func fromDict(_ dict: [String: Any], identityKey: Data? = nil) throws -> DeviceBundle {
guard let deviceId = dict["device_id"] as? String else {
throw ChatError.invalidData("Missing device_id")
}
// Identity key can be passed in (from parent) or in dict
let ik: Data
if let passedIk = identityKey {
ik = passedIk
} else if let ikB64 = dict["identity_key"] as? String,
let ikData = Data(base64Encoded: ikB64) {
ik = ikData
} else {
throw ChatError.invalidData("Missing identity_key")
}
// SPK - try both naming conventions, base64 encoded
let spkB64 = dict["signed_prekey"] as? String ?? dict["spk"] as? String
guard let spkB64 = spkB64,
let spk = Data(base64Encoded: spkB64) else {
throw ChatError.invalidData("Missing signed_prekey")
}
// SPK signature - base64 encoded
guard let spkSigB64 = dict["spk_signature"] as? String,
let spkSig = Data(base64Encoded: spkSigB64) else {
throw ChatError.invalidData("Missing spk_signature")
}
// SPK ID - try both naming conventions
let spkId = dict["signed_prekey_id"] as? String ?? dict["spk_id"] as? String
guard let spkId = spkId else {
throw ChatError.invalidData("Missing signed_prekey_id")
}
// OPK - optional, base64 encoded
var opk: Data?
var opkId: String?
let opkB64 = dict["one_time_prekey"] as? String ?? dict["opk"] as? String
if let opkB64 = opkB64, let opkData = Data(base64Encoded: opkB64) {
opk = opkData
opkId = dict["one_time_prekey_id"] as? String ?? dict["opk_id"] as? String
}
return DeviceBundle(
deviceId: deviceId,
identityKey: ik,
spk: spk,
spkSignature: spkSig,
spkId: spkId,
opk: opk,
opkId: opkId
)
}
}