99 lines
4.4 KiB
Swift
99 lines
4.4 KiB
Swift
//
|
||
// Copyright 2025 Element Creations Ltd.
|
||
// Copyright 2022-2025 New Vector Ltd.
|
||
//
|
||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||
// Please see LICENSE files in the repository root for full details.
|
||
//
|
||
|
||
import Foundation
|
||
import MatrixRustSDK
|
||
|
||
enum RestorationTokenError: Error {
|
||
case slidingSyncProxyNotSupported
|
||
}
|
||
|
||
struct RestorationToken: Equatable {
|
||
let session: MatrixRustSDK.Session
|
||
let sessionDirectories: SessionDirectories
|
||
let passphrase: String
|
||
let pusherNotificationClientIdentifier: String?
|
||
|
||
enum CodingKeys: CodingKey {
|
||
case session
|
||
case sessionDirectory
|
||
case cacheDirectory
|
||
case passphrase
|
||
case pusherNotificationClientIdentifier
|
||
}
|
||
}
|
||
|
||
extension RestorationToken: Codable {
|
||
init(from decoder: Decoder) throws {
|
||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||
|
||
let session = try container.decode(Session.self, forKey: .session)
|
||
let dataDirectory = try container.decode(URL.self, forKey: .sessionDirectory)
|
||
let cacheDirectory = try container.decodeIfPresent(URL.self, forKey: .cacheDirectory)
|
||
|
||
let sessionDirectories = if let cacheDirectory {
|
||
SessionDirectories(dataDirectory: dataDirectory, cacheDirectory: cacheDirectory)
|
||
} else {
|
||
SessionDirectories(dataDirectory: dataDirectory)
|
||
}
|
||
|
||
self = try .init(session: session,
|
||
sessionDirectories: sessionDirectories,
|
||
passphrase: container.decode(String.self, forKey: .passphrase),
|
||
pusherNotificationClientIdentifier: container.decodeIfPresent(String.self, forKey: .pusherNotificationClientIdentifier))
|
||
}
|
||
|
||
func encode(to encoder: any Encoder) throws {
|
||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||
try container.encode(session, forKey: .session)
|
||
try container.encode(sessionDirectories.dataDirectory, forKey: .sessionDirectory)
|
||
try container.encode(sessionDirectories.cacheDirectory, forKey: .cacheDirectory)
|
||
try container.encode(passphrase, forKey: .passphrase)
|
||
try container.encode(pusherNotificationClientIdentifier, forKey: .pusherNotificationClientIdentifier)
|
||
}
|
||
}
|
||
|
||
extension MatrixRustSDK.Session: @retroactive Codable {
|
||
public init(from decoder: Decoder) throws {
|
||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||
|
||
// The SDK no longer supports sliding sync proxies. We must bail here otherwise the
|
||
// session would be restored using native sliding sync, but if the proxy was still
|
||
// active its sync loop would be stealing keys away from us.
|
||
//
|
||
// Note: As tempting as it is to use container.contains(.slidingSyncProxy), that will always
|
||
// return true as our coding keys have resulted in the key being encoded with a nil value 🤦♂️.
|
||
if (try? container.decodeIfPresent(String.self, forKey: .slidingSyncProxy)) != nil {
|
||
throw RestorationTokenError.slidingSyncProxyNotSupported
|
||
}
|
||
|
||
self = try .init(accessToken: container.decode(String.self, forKey: .accessToken),
|
||
refreshToken: container.decodeIfPresent(String.self, forKey: .refreshToken),
|
||
userId: container.decode(String.self, forKey: .userId),
|
||
deviceId: container.decode(String.self, forKey: .deviceId),
|
||
homeserverUrl: container.decode(String.self, forKey: .homeserverUrl),
|
||
oauthData: container.decodeIfPresent(String.self, forKey: .oauthData),
|
||
slidingSyncVersion: .native)
|
||
}
|
||
|
||
public func encode(to encoder: Encoder) throws {
|
||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||
try container.encode(accessToken, forKey: .accessToken)
|
||
try container.encode(refreshToken, forKey: .refreshToken)
|
||
try container.encode(userId, forKey: .userId)
|
||
try container.encode(deviceId, forKey: .deviceId)
|
||
try container.encode(homeserverUrl, forKey: .homeserverUrl)
|
||
try container.encode(oauthData, forKey: .oauthData)
|
||
}
|
||
|
||
enum CodingKeys: String, CodingKey {
|
||
case accessToken, refreshToken, userId, deviceId, homeserverUrl, slidingSyncProxy
|
||
case oauthData = "oidcData" // We're using the name from before the MSC was stabilised.
|
||
}
|
||
}
|