Expose the store passphrase as Data instead of a base64 string.

This commit is contained in:
Stefan Ceriu
2026-09-22 20:20:18 +03:00
parent 18201ac248
commit b1923b418f
11 changed files with 47 additions and 42 deletions
@@ -2219,14 +2219,14 @@ nonisolated class ClientFactoryMock: ClientFactoryProtocol, @unchecked Sendable
return makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount > 0 return makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount > 0
} }
private let makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksReceivedArgumentsLock = NSLock() private let makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksReceivedArgumentsLock = NSLock()
private nonisolated(unsafe) var makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksUnderlyingReceivedArguments: (serverNameOrBaseURL: String, sessionDirectories: SessionDirectories, passphrase: String, clientSessionDelegate: ClientSessionDelegate, appSettings: AppSettings, appHooks: AppHooks)? private nonisolated(unsafe) var makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksUnderlyingReceivedArguments: (serverNameOrBaseURL: String, sessionDirectories: SessionDirectories, passphrase: Data, clientSessionDelegate: ClientSessionDelegate, appSettings: AppSettings, appHooks: AppHooks)?
var makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksReceivedArguments: (serverNameOrBaseURL: String, sessionDirectories: SessionDirectories, passphrase: String, clientSessionDelegate: ClientSessionDelegate, appSettings: AppSettings, appHooks: AppHooks)? { var makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksReceivedArguments: (serverNameOrBaseURL: String, sessionDirectories: SessionDirectories, passphrase: Data, clientSessionDelegate: ClientSessionDelegate, appSettings: AppSettings, appHooks: AppHooks)? {
get { makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksReceivedArgumentsLock.withLock { makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksUnderlyingReceivedArguments } } get { makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksReceivedArgumentsLock.withLock { makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksUnderlyingReceivedArguments } }
set { makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksReceivedArgumentsLock.withLock { makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksUnderlyingReceivedArguments = newValue } } set { makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksReceivedArgumentsLock.withLock { makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksUnderlyingReceivedArguments = newValue } }
} }
private let makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksReceivedInvocationsLock = NSLock() private let makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksReceivedInvocationsLock = NSLock()
private nonisolated(unsafe) var makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksUnderlyingReceivedInvocations: [(serverNameOrBaseURL: String, sessionDirectories: SessionDirectories, passphrase: String, clientSessionDelegate: ClientSessionDelegate, appSettings: AppSettings, appHooks: AppHooks)] = [] private nonisolated(unsafe) var makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksUnderlyingReceivedInvocations: [(serverNameOrBaseURL: String, sessionDirectories: SessionDirectories, passphrase: Data, clientSessionDelegate: ClientSessionDelegate, appSettings: AppSettings, appHooks: AppHooks)] = []
var makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksReceivedInvocations: [(serverNameOrBaseURL: String, sessionDirectories: SessionDirectories, passphrase: String, clientSessionDelegate: ClientSessionDelegate, appSettings: AppSettings, appHooks: AppHooks)] { var makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksReceivedInvocations: [(serverNameOrBaseURL: String, sessionDirectories: SessionDirectories, passphrase: Data, clientSessionDelegate: ClientSessionDelegate, appSettings: AppSettings, appHooks: AppHooks)] {
get { makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksReceivedInvocationsLock.withLock { makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksUnderlyingReceivedInvocations } } get { makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksReceivedInvocationsLock.withLock { makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksUnderlyingReceivedInvocations } }
set { makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksReceivedInvocationsLock.withLock { makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksUnderlyingReceivedInvocations = newValue } } set { makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksReceivedInvocationsLock.withLock { makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksUnderlyingReceivedInvocations = newValue } }
} }
@@ -2237,9 +2237,9 @@ nonisolated class ClientFactoryMock: ClientFactoryProtocol, @unchecked Sendable
get { makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksReturnValueLock.withLock { makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksUnderlyingReturnValue } } get { makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksReturnValueLock.withLock { makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksUnderlyingReturnValue } }
set { makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksReturnValueLock.withLock { makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksUnderlyingReturnValue = newValue } } set { makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksReturnValueLock.withLock { makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksUnderlyingReturnValue = newValue } }
} }
nonisolated(unsafe) var makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksClosure: ((String, SessionDirectories, String, ClientSessionDelegate, AppSettings, AppHooks) async throws -> ClientProtocol)? nonisolated(unsafe) var makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksClosure: ((String, SessionDirectories, Data, ClientSessionDelegate, AppSettings, AppHooks) async throws -> ClientProtocol)?
@concurrent func makeAuthenticationClient(serverNameOrBaseURL: String, sessionDirectories: SessionDirectories, passphrase: String, clientSessionDelegate: ClientSessionDelegate, appSettings: AppSettings, appHooks: AppHooks) async throws -> ClientProtocol { @concurrent func makeAuthenticationClient(serverNameOrBaseURL: String, sessionDirectories: SessionDirectories, passphrase: Data, clientSessionDelegate: ClientSessionDelegate, appSettings: AppSettings, appHooks: AppHooks) async throws -> ClientProtocol {
if let error = makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksThrowableError { if let error = makeAuthenticationClientServerNameOrBaseURLSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksThrowableError {
throw error throw error
} }
@@ -14631,14 +14631,14 @@ nonisolated class UserSessionStoreMock: UserSessionStoreProtocol, @unchecked Sen
return userSessionForSessionDirectoriesPassphraseCallsCount > 0 return userSessionForSessionDirectoriesPassphraseCallsCount > 0
} }
private let userSessionForSessionDirectoriesPassphraseReceivedArgumentsLock = NSLock() private let userSessionForSessionDirectoriesPassphraseReceivedArgumentsLock = NSLock()
private nonisolated(unsafe) var userSessionForSessionDirectoriesPassphraseUnderlyingReceivedArguments: (client: ClientProtocol, sessionDirectories: SessionDirectories, passphrase: String)? private nonisolated(unsafe) var userSessionForSessionDirectoriesPassphraseUnderlyingReceivedArguments: (client: ClientProtocol, sessionDirectories: SessionDirectories, passphrase: Data)?
var userSessionForSessionDirectoriesPassphraseReceivedArguments: (client: ClientProtocol, sessionDirectories: SessionDirectories, passphrase: String)? { var userSessionForSessionDirectoriesPassphraseReceivedArguments: (client: ClientProtocol, sessionDirectories: SessionDirectories, passphrase: Data)? {
get { userSessionForSessionDirectoriesPassphraseReceivedArgumentsLock.withLock { userSessionForSessionDirectoriesPassphraseUnderlyingReceivedArguments } } get { userSessionForSessionDirectoriesPassphraseReceivedArgumentsLock.withLock { userSessionForSessionDirectoriesPassphraseUnderlyingReceivedArguments } }
set { userSessionForSessionDirectoriesPassphraseReceivedArgumentsLock.withLock { userSessionForSessionDirectoriesPassphraseUnderlyingReceivedArguments = newValue } } set { userSessionForSessionDirectoriesPassphraseReceivedArgumentsLock.withLock { userSessionForSessionDirectoriesPassphraseUnderlyingReceivedArguments = newValue } }
} }
private let userSessionForSessionDirectoriesPassphraseReceivedInvocationsLock = NSLock() private let userSessionForSessionDirectoriesPassphraseReceivedInvocationsLock = NSLock()
private nonisolated(unsafe) var userSessionForSessionDirectoriesPassphraseUnderlyingReceivedInvocations: [(client: ClientProtocol, sessionDirectories: SessionDirectories, passphrase: String)] = [] private nonisolated(unsafe) var userSessionForSessionDirectoriesPassphraseUnderlyingReceivedInvocations: [(client: ClientProtocol, sessionDirectories: SessionDirectories, passphrase: Data)] = []
var userSessionForSessionDirectoriesPassphraseReceivedInvocations: [(client: ClientProtocol, sessionDirectories: SessionDirectories, passphrase: String)] { var userSessionForSessionDirectoriesPassphraseReceivedInvocations: [(client: ClientProtocol, sessionDirectories: SessionDirectories, passphrase: Data)] {
get { userSessionForSessionDirectoriesPassphraseReceivedInvocationsLock.withLock { userSessionForSessionDirectoriesPassphraseUnderlyingReceivedInvocations } } get { userSessionForSessionDirectoriesPassphraseReceivedInvocationsLock.withLock { userSessionForSessionDirectoriesPassphraseUnderlyingReceivedInvocations } }
set { userSessionForSessionDirectoriesPassphraseReceivedInvocationsLock.withLock { userSessionForSessionDirectoriesPassphraseUnderlyingReceivedInvocations = newValue } } set { userSessionForSessionDirectoriesPassphraseReceivedInvocationsLock.withLock { userSessionForSessionDirectoriesPassphraseUnderlyingReceivedInvocations = newValue } }
} }
@@ -14649,9 +14649,9 @@ nonisolated class UserSessionStoreMock: UserSessionStoreProtocol, @unchecked Sen
get { userSessionForSessionDirectoriesPassphraseReturnValueLock.withLock { userSessionForSessionDirectoriesPassphraseUnderlyingReturnValue } } get { userSessionForSessionDirectoriesPassphraseReturnValueLock.withLock { userSessionForSessionDirectoriesPassphraseUnderlyingReturnValue } }
set { userSessionForSessionDirectoriesPassphraseReturnValueLock.withLock { userSessionForSessionDirectoriesPassphraseUnderlyingReturnValue = newValue } } set { userSessionForSessionDirectoriesPassphraseReturnValueLock.withLock { userSessionForSessionDirectoriesPassphraseUnderlyingReturnValue = newValue } }
} }
nonisolated(unsafe) var userSessionForSessionDirectoriesPassphraseClosure: ((ClientProtocol, SessionDirectories, String) async -> Result<UserSessionProtocol, UserSessionStoreError>)? nonisolated(unsafe) var userSessionForSessionDirectoriesPassphraseClosure: ((ClientProtocol, SessionDirectories, Data) async -> Result<UserSessionProtocol, UserSessionStoreError>)?
@concurrent func userSession(for client: ClientProtocol, sessionDirectories: SessionDirectories, passphrase: String) async -> Result<UserSessionProtocol, UserSessionStoreError> { @concurrent func userSession(for client: ClientProtocol, sessionDirectories: SessionDirectories, passphrase: Data) async -> Result<UserSessionProtocol, UserSessionStoreError> {
userSessionForSessionDirectoriesPassphraseCallsCountLock.withLock { userSessionForSessionDirectoriesPassphraseUnderlyingCallsCount += 1 } userSessionForSessionDirectoriesPassphraseCallsCountLock.withLock { userSessionForSessionDirectoriesPassphraseUnderlyingCallsCount += 1 }
userSessionForSessionDirectoriesPassphraseReceivedArguments = (client: client, sessionDirectories: sessionDirectories, passphrase: passphrase) userSessionForSessionDirectoriesPassphraseReceivedArguments = (client: client, sessionDirectories: sessionDirectories, passphrase: passphrase)
userSessionForSessionDirectoriesPassphraseReceivedInvocationsLock.withLock { userSessionForSessionDirectoriesPassphraseUnderlyingReceivedInvocations.append((client: client, sessionDirectories: sessionDirectories, passphrase: passphrase)) } userSessionForSessionDirectoriesPassphraseReceivedInvocationsLock.withLock { userSessionForSessionDirectoriesPassphraseUnderlyingReceivedInvocations.append((client: client, sessionDirectories: sessionDirectories, passphrase: passphrase)) }
@@ -13,7 +13,7 @@ import MatrixRustSDK
class AuthenticationService: AuthenticationServiceProtocol { class AuthenticationService: AuthenticationServiceProtocol {
private var client: ClientProtocol? private var client: ClientProtocol?
private var sessionDirectories: SessionDirectories private var sessionDirectories: SessionDirectories
private let passphrase: String private let passphrase: Data
private let userSessionStore: UserSessionStoreProtocol private let userSessionStore: UserSessionStoreProtocol
private let classicAppManager: ClassicAppManagerProtocol? private let classicAppManager: ClassicAppManagerProtocol?
@@ -40,7 +40,7 @@ class AuthenticationService: AuthenticationServiceProtocol {
appSettings: AppSettings, appSettings: AppSettings,
appHooks: AppHooks) { appHooks: AppHooks) {
sessionDirectories = .init() sessionDirectories = .init()
passphrase = encryptionKeyProvider.generateKey().base64EncodedString() passphrase = encryptionKeyProvider.generateKey()
self.userSessionStore = userSessionStore self.userSessionStore = userSessionStore
self.classicAppManager = classicAppManager self.classicAppManager = classicAppManager
@@ -16,7 +16,7 @@ nonisolated struct ClientFactory: ClientFactoryProtocol {
#if IS_MAIN_APP #if IS_MAIN_APP
func makeAuthenticationClient(serverNameOrBaseURL: String, func makeAuthenticationClient(serverNameOrBaseURL: String,
sessionDirectories: SessionDirectories, sessionDirectories: SessionDirectories,
passphrase: String, passphrase: Data,
clientSessionDelegate: ClientSessionDelegate, clientSessionDelegate: ClientSessionDelegate,
appSettings: AppSettings, appSettings: AppSettings,
appHooks: AppHooks) async throws -> ClientProtocol { appHooks: AppHooks) async throws -> ClientProtocol {
@@ -28,7 +28,7 @@ nonisolated struct ClientFactory: ClientFactoryProtocol {
threadsEnabled: appSettings.threadsEnabled) threadsEnabled: appSettings.threadsEnabled)
.enableAutomaticBackPagination(enableAutomaticBackPagination: true) .enableAutomaticBackPagination(enableAutomaticBackPagination: true)
.sqliteStore(config: .init(dataPath: sessionDirectories.dataPath, cachePath: sessionDirectories.cachePath) .sqliteStore(config: .init(dataPath: sessionDirectories.dataPath, cachePath: sessionDirectories.cachePath)
.highEntropyPassphrase(passphrase: Data(base64Encoded: passphrase), base64Variant: .padded)) .highEntropyPassphrase(passphrase: passphrase, base64Variant: .padded))
.serverNameOrHomeserverUrl(serverNameOrUrl: serverNameOrBaseURL) .serverNameOrHomeserverUrl(serverNameOrUrl: serverNameOrBaseURL)
return try await build(builder, for: .authentication, appHooks: appHooks) return try await build(builder, for: .authentication, appHooks: appHooks)
@@ -67,9 +67,9 @@ nonisolated struct ClientFactory: ClientFactoryProtocol {
.enableAutomaticBackPagination(enableAutomaticBackPagination: true) .enableAutomaticBackPagination(enableAutomaticBackPagination: true)
.sqliteStore(config: .init(dataPath: credentials.restorationToken.sessionDirectories.dataPath, .sqliteStore(config: .init(dataPath: credentials.restorationToken.sessionDirectories.dataPath,
cachePath: credentials.restorationToken.sessionDirectories.cachePath) cachePath: credentials.restorationToken.sessionDirectories.cachePath)
.highEntropyPassphrase(passphrase: Data(base64Encoded: credentials.restorationToken.passphrase), base64Variant: .padded)) .highEntropyPassphrase(passphrase: credentials.restorationToken.passphrase, base64Variant: .padded))
.withSearchIndexStore(path: credentials.restorationToken.sessionDirectories.dataPath, .withSearchIndexStore(path: credentials.restorationToken.sessionDirectories.dataPath,
password: credentials.restorationToken.passphrase) password: credentials.restorationToken.passphrase.base64EncodedString())
.homeserverUrl(url: homeserverURL) .homeserverUrl(url: homeserverURL)
return try await build(builder, for: .restoration(credentials.restorationToken.session, .all), appHooks: appHooks) return try await build(builder, for: .restoration(credentials.restorationToken.session, .all), appHooks: appHooks)
@@ -95,7 +95,7 @@ nonisolated struct ClientFactory: ClientFactoryProtocol {
.systemIsMemoryConstrained() .systemIsMemoryConstrained()
.sqliteStore(config: .init(dataPath: credentials.restorationToken.sessionDirectories.dataPath, .sqliteStore(config: .init(dataPath: credentials.restorationToken.sessionDirectories.dataPath,
cachePath: credentials.restorationToken.sessionDirectories.cachePath) cachePath: credentials.restorationToken.sessionDirectories.cachePath)
.highEntropyPassphrase(passphrase: Data(base64Encoded: credentials.restorationToken.passphrase), base64Variant: .padded)) .highEntropyPassphrase(passphrase: credentials.restorationToken.passphrase, base64Variant: .padded))
.homeserverUrl(url: homeserverURL) .homeserverUrl(url: homeserverURL)
return try await build(builder, for: .restoration(credentials.restorationToken.session, .one(roomId: roomID)), appHooks: appHooks) return try await build(builder, for: .restoration(credentials.restorationToken.session, .one(roomId: roomID)), appHooks: appHooks)
@@ -5,6 +5,7 @@
// Please see LICENSE files in the repository root for full details. // Please see LICENSE files in the repository root for full details.
// //
import Foundation
import MatrixRustSDK import MatrixRustSDK
// sourcery: AutoMockable // sourcery: AutoMockable
@@ -14,7 +15,7 @@ nonisolated protocol ClientFactoryProtocol {
#if IS_MAIN_APP #if IS_MAIN_APP
func makeAuthenticationClient(serverNameOrBaseURL: String, func makeAuthenticationClient(serverNameOrBaseURL: String,
sessionDirectories: SessionDirectories, sessionDirectories: SessionDirectories,
passphrase: String, passphrase: Data,
clientSessionDelegate: ClientSessionDelegate, clientSessionDelegate: ClientSessionDelegate,
appSettings: AppSettings, appSettings: AppSettings,
appHooks: AppHooks) async throws -> ClientProtocol appHooks: AppHooks) async throws -> ClientProtocol
@@ -16,7 +16,7 @@ enum RestorationTokenError: Error {
nonisolated struct RestorationToken: Equatable { nonisolated struct RestorationToken: Equatable {
let session: MatrixRustSDK.Session let session: MatrixRustSDK.Session
let sessionDirectories: SessionDirectories let sessionDirectories: SessionDirectories
let passphrase: String let passphrase: Data
let pusherNotificationClientIdentifier: String? let pusherNotificationClientIdentifier: String?
enum CodingKeys: CodingKey { enum CodingKeys: CodingKey {
@@ -42,9 +42,14 @@ nonisolated extension RestorationToken: Codable {
SessionDirectories(dataDirectory: dataDirectory) SessionDirectories(dataDirectory: dataDirectory)
} }
let base64Passphrase = try container.decode(String.self, forKey: .passphrase)
guard let passphrase = Data(base64Encoded: base64Passphrase) else {
throw DecodingError.dataCorruptedError(forKey: .passphrase, in: container, debugDescription: "The passphrase isn't valid base64.")
}
self = try .init(session: session, self = try .init(session: session,
sessionDirectories: sessionDirectories, sessionDirectories: sessionDirectories,
passphrase: container.decode(String.self, forKey: .passphrase), passphrase: passphrase,
pusherNotificationClientIdentifier: container.decodeIfPresent(String.self, forKey: .pusherNotificationClientIdentifier)) pusherNotificationClientIdentifier: container.decodeIfPresent(String.self, forKey: .pusherNotificationClientIdentifier))
} }
@@ -53,7 +58,7 @@ nonisolated extension RestorationToken: Codable {
try container.encode(session, forKey: .session) try container.encode(session, forKey: .session)
try container.encode(sessionDirectories.dataDirectory, forKey: .sessionDirectory) try container.encode(sessionDirectories.dataDirectory, forKey: .sessionDirectory)
try container.encode(sessionDirectories.cacheDirectory, forKey: .cacheDirectory) try container.encode(sessionDirectories.cacheDirectory, forKey: .cacheDirectory)
try container.encode(passphrase, forKey: .passphrase) try container.encode(passphrase.base64EncodedString(), forKey: .passphrase)
try container.encode(pusherNotificationClientIdentifier, forKey: .pusherNotificationClientIdentifier) try container.encode(pusherNotificationClientIdentifier, forKey: .pusherNotificationClientIdentifier)
} }
} }
@@ -73,7 +73,7 @@ class UserSessionStore: UserSessionStoreProtocol {
} }
} }
func userSession(for client: ClientProtocol, sessionDirectories: SessionDirectories, passphrase: String) async -> Result<UserSessionProtocol, UserSessionStoreError> { func userSession(for client: ClientProtocol, sessionDirectories: SessionDirectories, passphrase: Data) async -> Result<UserSessionProtocol, UserSessionStoreError> {
do { do {
let session = try client.session() let session = try client.session()
let userID = try client.userId() let userID = try client.userId()
@@ -34,7 +34,7 @@ protocol UserSessionStoreProtocol {
func restoreUserSession() async -> Result<UserSessionProtocol, UserSessionStoreError> func restoreUserSession() async -> Result<UserSessionProtocol, UserSessionStoreError>
/// Creates a user session for a new client from the SDK along with the passphrase used for the data stores. /// Creates a user session for a new client from the SDK along with the passphrase used for the data stores.
func userSession(for client: ClientProtocol, sessionDirectories: SessionDirectories, passphrase: String) async -> Result<UserSessionProtocol, UserSessionStoreError> func userSession(for client: ClientProtocol, sessionDirectories: SessionDirectories, passphrase: Data) async -> Result<UserSessionProtocol, UserSessionStoreError>
/// Logs out of the specified session. /// Logs out of the specified session.
func logout(userSession: UserSessionProtocol) func logout(userSession: UserSessionProtocol)
@@ -37,8 +37,7 @@ struct AuthenticationServiceTests {
case .success: case .success:
#expect(client.loginUsernamePasswordInitialDeviceNameDeviceIdCallsCount == 1) #expect(client.loginUsernamePasswordInitialDeviceNameDeviceIdCallsCount == 1)
#expect(userSessionStore.userSessionForSessionDirectoriesPassphraseCallsCount == 1) #expect(userSessionStore.userSessionForSessionDirectoriesPassphraseCallsCount == 1)
#expect(userSessionStore.userSessionForSessionDirectoriesPassphraseReceivedArguments?.passphrase == #expect(userSessionStore.userSessionForSessionDirectoriesPassphraseReceivedArguments?.passphrase == encryptionKeyProvider.generateKey())
encryptionKeyProvider.generateKey().base64EncodedString())
case .failure(let error): case .failure(let error):
Issue.record("Unexpected failure: \(error)") Issue.record("Unexpected failure: \(error)")
} }
@@ -36,7 +36,7 @@ struct KeychainControllerTests {
oauthData: "oauthData", oauthData: "oauthData",
slidingSyncVersion: .native), slidingSyncVersion: .native),
sessionDirectories: .init(), sessionDirectories: .init(),
passphrase: "passphrase", passphrase: Data("passphrase".utf8),
pusherNotificationClientIdentifier: "pusherClientID") pusherNotificationClientIdentifier: "pusherClientID")
keychain.setRestorationToken(restorationToken, forUsername: username) keychain.setRestorationToken(restorationToken, forUsername: username)
@@ -56,7 +56,7 @@ struct KeychainControllerTests {
oauthData: "oauthData", oauthData: "oauthData",
slidingSyncVersion: .native), slidingSyncVersion: .native),
sessionDirectories: .init(), sessionDirectories: .init(),
passphrase: "passphrase", passphrase: Data("passphrase".utf8),
pusherNotificationClientIdentifier: "pusherClientID") pusherNotificationClientIdentifier: "pusherClientID")
keychain.setRestorationToken(restorationToken, forUsername: username) keychain.setRestorationToken(restorationToken, forUsername: username)
#expect(keychain.restorationTokens().count == 1, "The keychain should have 1 restoration token.") #expect(keychain.restorationTokens().count == 1, "The keychain should have 1 restoration token.")
@@ -82,7 +82,7 @@ struct KeychainControllerTests {
oauthData: "oauthData", oauthData: "oauthData",
slidingSyncVersion: .native), slidingSyncVersion: .native),
sessionDirectories: .init(), sessionDirectories: .init(),
passphrase: "passphrase", passphrase: Data("passphrase".utf8),
pusherNotificationClientIdentifier: "pusherClientID") pusherNotificationClientIdentifier: "pusherClientID")
keychain.setRestorationToken(restorationToken, forUsername: "@test\(index):example.com") keychain.setRestorationToken(restorationToken, forUsername: "@test\(index):example.com")
} }
@@ -107,7 +107,7 @@ struct KeychainControllerTests {
oauthData: "oauthData", oauthData: "oauthData",
slidingSyncVersion: .native), slidingSyncVersion: .native),
sessionDirectories: .init(), sessionDirectories: .init(),
passphrase: "passphrase", passphrase: Data("passphrase".utf8),
pusherNotificationClientIdentifier: "pusherClientID") pusherNotificationClientIdentifier: "pusherClientID")
keychain.setRestorationToken(restorationToken, forUsername: "@test\(index):example.com") keychain.setRestorationToken(restorationToken, forUsername: "@test\(index):example.com")
} }
@@ -141,7 +141,7 @@ struct KeychainControllerTests {
oidcData: nil, oidcData: nil,
slidingSyncVersion: .proxy(url: "https://sync.example.com")), slidingSyncVersion: .proxy(url: "https://sync.example.com")),
sessionDirectory: .sessionsBaseDirectory.appending(component: UUID().uuidString), sessionDirectory: .sessionsBaseDirectory.appending(component: UUID().uuidString),
passphrase: "passphrase", passphrase: Data("passphrase".utf8).base64EncodedString(),
pusherNotificationClientIdentifier: "pusherClientID") pusherNotificationClientIdentifier: "pusherClientID")
let tokenData = try JSONEncoder().encode(unsupportedToken) let tokenData = try JSONEncoder().encode(unsupportedToken)
try underlyingKeychain.set(tokenData, key: "@test:example.com") try underlyingKeychain.set(tokenData, key: "@test:example.com")
@@ -23,7 +23,7 @@ struct RestorationTokenTests {
oidcData: "data-from-mas", oidcData: "data-from-mas",
slidingSyncVersion: .proxy(url: "https://sync.example.com")), slidingSyncVersion: .proxy(url: "https://sync.example.com")),
sessionDirectory: .sessionsBaseDirectory.appending(component: UUID().uuidString), sessionDirectory: .sessionsBaseDirectory.appending(component: UUID().uuidString),
passphrase: "passphrase", passphrase: Data("passphrase".utf8).base64EncodedString(),
pusherNotificationClientIdentifier: "pusher-identifier") pusherNotificationClientIdentifier: "pusher-identifier")
let data = try JSONEncoder().encode(originalToken) let data = try JSONEncoder().encode(originalToken)
@@ -46,7 +46,7 @@ struct RestorationTokenTests {
oidcData: "data-from-mas", oidcData: "data-from-mas",
slidingSyncVersion: .native), slidingSyncVersion: .native),
sessionDirectory: .sessionsBaseDirectory.appending(component: sessionDirectoryName), sessionDirectory: .sessionsBaseDirectory.appending(component: sessionDirectoryName),
passphrase: "passphrase", passphrase: Data("passphrase".utf8).base64EncodedString(),
pusherNotificationClientIdentifier: "pusher-identifier") pusherNotificationClientIdentifier: "pusher-identifier")
let data = try JSONEncoder().encode(originalToken) let data = try JSONEncoder().encode(originalToken)
@@ -55,7 +55,7 @@ struct RestorationTokenTests {
// Then the output should be a valid token with the expected store directories. // Then the output should be a valid token with the expected store directories.
assertEqual(session: decodedToken.session, originalSession: originalToken.session) assertEqual(session: decodedToken.session, originalSession: originalToken.session)
#expect(decodedToken.passphrase == originalToken.passphrase, "The passphrase should not be changed.") #expect(decodedToken.passphrase.base64EncodedString() == originalToken.passphrase, "The passphrase should not be changed.")
#expect(decodedToken.pusherNotificationClientIdentifier == originalToken.pusherNotificationClientIdentifier, #expect(decodedToken.pusherNotificationClientIdentifier == originalToken.pusherNotificationClientIdentifier,
"The push notification client identifier should not be changed.") "The push notification client identifier should not be changed.")
#expect(decodedToken.sessionDirectories.dataDirectory == originalToken.sessionDirectory, #expect(decodedToken.sessionDirectories.dataDirectory == originalToken.sessionDirectory,
@@ -77,7 +77,7 @@ struct RestorationTokenTests {
slidingSyncVersion: .native), slidingSyncVersion: .native),
sessionDirectory: .sessionsBaseDirectory.appending(component: sessionDirectoryName), sessionDirectory: .sessionsBaseDirectory.appending(component: sessionDirectoryName),
cacheDirectory: .sessionCachesBaseDirectory.appending(component: sessionDirectoryName), cacheDirectory: .sessionCachesBaseDirectory.appending(component: sessionDirectoryName),
passphrase: "passphrase", passphrase: Data("passphrase".utf8).base64EncodedString(),
pusherNotificationClientIdentifier: "pusher-identifier") pusherNotificationClientIdentifier: "pusher-identifier")
let data = try JSONEncoder().encode(originalToken) let data = try JSONEncoder().encode(originalToken)
@@ -86,7 +86,7 @@ struct RestorationTokenTests {
// Then the output should be a valid token. // Then the output should be a valid token.
assertEqual(session: decodedToken.session, originalSession: originalToken.session) assertEqual(session: decodedToken.session, originalSession: originalToken.session)
#expect(decodedToken.passphrase == originalToken.passphrase, "The passphrase should not be changed.") #expect(decodedToken.passphrase.base64EncodedString() == originalToken.passphrase, "The passphrase should not be changed.")
#expect(decodedToken.pusherNotificationClientIdentifier == originalToken.pusherNotificationClientIdentifier, #expect(decodedToken.pusherNotificationClientIdentifier == originalToken.pusherNotificationClientIdentifier,
"The push notification client identifier should not be changed.") "The push notification client identifier should not be changed.")
#expect(decodedToken.sessionDirectories.dataDirectory == originalToken.sessionDirectory, #expect(decodedToken.sessionDirectories.dataDirectory == originalToken.sessionDirectory,
@@ -106,7 +106,7 @@ struct RestorationTokenTests {
oauthData: "data-from-mas", oauthData: "data-from-mas",
slidingSyncVersion: .native), slidingSyncVersion: .native),
sessionDirectories: .init(), sessionDirectories: .init(),
passphrase: "passphrase", passphrase: Data("passphrase".utf8),
pusherNotificationClientIdentifier: "pusher-identifier") pusherNotificationClientIdentifier: "pusher-identifier")
let data = try JSONEncoder().encode(originalToken) let data = try JSONEncoder().encode(originalToken)
@@ -114,7 +114,7 @@ struct UserSessionStoreTests {
let sessionDirectories = SessionDirectories() let sessionDirectories = SessionDirectories()
// When creating a user session for it. // When creating a user session for it.
guard case .success(let userSession) = await store.userSession(for: client, sessionDirectories: sessionDirectories, passphrase: "passphrase") else { guard case .success(let userSession) = await store.userSession(for: client, sessionDirectories: sessionDirectories, passphrase: Data("passphrase".utf8)) else {
Issue.record("Creating the session should succeed.") Issue.record("Creating the session should succeed.")
return return
} }
@@ -122,7 +122,7 @@ struct UserSessionStoreTests {
// Then the session should be built and its restoration token persisted. // Then the session should be built and its restoration token persisted.
#expect(userSession.clientProxy.userID == "@alice:matrix.org") #expect(userSession.clientProxy.userID == "@alice:matrix.org")
#expect(keychainController.setRestorationTokenForUsernameReceivedArguments?.forUsername == "@alice:matrix.org") #expect(keychainController.setRestorationTokenForUsernameReceivedArguments?.forUsername == "@alice:matrix.org")
#expect(keychainController.setRestorationTokenForUsernameReceivedArguments?.restorationToken.passphrase == "passphrase") #expect(keychainController.setRestorationTokenForUsernameReceivedArguments?.restorationToken.passphrase == Data("passphrase".utf8))
} }
@Test @Test
@@ -132,7 +132,7 @@ struct UserSessionStoreTests {
client.sessionThrowableError = TestError.generic client.sessionThrowableError = TestError.generic
// When creating a user session for it. // When creating a user session for it.
guard case .failure(.failedSettingUpSession) = await store.userSession(for: client, sessionDirectories: .init(), passphrase: "passphrase") else { guard case .failure(.failedSettingUpSession) = await store.userSession(for: client, sessionDirectories: .init(), passphrase: Data("passphrase".utf8)) else {
Issue.record("Creating the session should fail.") Issue.record("Creating the session should fail.")
return return
} }
@@ -177,7 +177,7 @@ struct UserSessionStoreTests {
slidingSyncVersion: .native) slidingSyncVersion: .native)
let restorationToken = RestorationToken(session: session, let restorationToken = RestorationToken(session: session,
sessionDirectories: sessionDirectories, sessionDirectories: sessionDirectories,
passphrase: "passphrase", passphrase: Data("passphrase".utf8),
pusherNotificationClientIdentifier: nil) pusherNotificationClientIdentifier: nil)
return KeychainCredentials(userID: userID, restorationToken: restorationToken) return KeychainCredentials(userID: userID, restorationToken: restorationToken)
} }