70 lines
2.6 KiB
Swift
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
|
|
)
|
|
}
|
|
}
|