Add a developer option for history sharing on invite

Adds a new developer flag, enabling our experimental support for MSC4268.
This commit is contained in:
Richard van der Hoff
2025-06-05 13:34:33 +01:00
committed by Stefan Ceriu
parent db3f9f4d26
commit 394eb008ab
7 changed files with 25 additions and 3 deletions
@@ -17,6 +17,7 @@ protocol CommonSettingsProtocol {
var logLevel: LogLevel { get } var logLevel: LogLevel { get }
var traceLogPacks: Set<TraceLogPack> { get } var traceLogPacks: Set<TraceLogPack> { get }
var enableOnlySignedDeviceIsolationMode: Bool { get } var enableOnlySignedDeviceIsolationMode: Bool { get }
var enableKeyShareOnInvite: Bool { get }
var hideQuietNotificationAlerts: Bool { get } var hideQuietNotificationAlerts: Bool { get }
} }
@@ -52,6 +53,7 @@ final class AppSettings {
case publicSearchEnabled case publicSearchEnabled
case fuzzyRoomListSearchEnabled case fuzzyRoomListSearchEnabled
case enableOnlySignedDeviceIsolationMode case enableOnlySignedDeviceIsolationMode
case enableKeyShareOnInvite
case knockingEnabled case knockingEnabled
case threadsEnabled case threadsEnabled
case developerOptionsEnabled case developerOptionsEnabled
@@ -363,7 +365,11 @@ final class AppSettings {
/// Configuration to enable only signed device isolation mode for crypto. In this mode only devices signed by their owner will be considered in e2ee rooms. /// Configuration to enable only signed device isolation mode for crypto. In this mode only devices signed by their owner will be considered in e2ee rooms.
@UserPreference(key: UserDefaultsKeys.enableOnlySignedDeviceIsolationMode, defaultValue: false, storageType: .userDefaults(store)) @UserPreference(key: UserDefaultsKeys.enableOnlySignedDeviceIsolationMode, defaultValue: false, storageType: .userDefaults(store))
var enableOnlySignedDeviceIsolationMode var enableOnlySignedDeviceIsolationMode
/// Configuration to enable encrypted history sharing on invite, and accepting keys from inviters.
@UserPreference(key: UserDefaultsKeys.enableKeyShareOnInvite, defaultValue: false, storageType: .userDefaults(store))
var enableKeyShareOnInvite
@UserPreference(key: UserDefaultsKeys.hideQuietNotificationAlerts, defaultValue: false, storageType: .userDefaults(store)) @UserPreference(key: UserDefaultsKeys.hideQuietNotificationAlerts, defaultValue: false, storageType: .userDefaults(store))
var hideQuietNotificationAlerts var hideQuietNotificationAlerts
} }
@@ -16,6 +16,7 @@ extension ClientBuilder {
sessionDelegate: ClientSessionDelegate, sessionDelegate: ClientSessionDelegate,
appHooks: AppHooks, appHooks: AppHooks,
enableOnlySignedDeviceIsolationMode: Bool, enableOnlySignedDeviceIsolationMode: Bool,
enableKeyShareOnInvite: Bool,
requestTimeout: UInt64? = 30000, requestTimeout: UInt64? = 30000,
maxRequestRetryTime: UInt64? = nil) -> ClientBuilder { maxRequestRetryTime: UInt64? = nil) -> ClientBuilder {
var builder = ClientBuilder() var builder = ClientBuilder()
@@ -37,6 +38,7 @@ extension ClientBuilder {
builder = builder builder = builder
.autoEnableCrossSigning(autoEnableCrossSigning: true) .autoEnableCrossSigning(autoEnableCrossSigning: true)
.backupDownloadStrategy(backupDownloadStrategy: .afterDecryptionFailure) .backupDownloadStrategy(backupDownloadStrategy: .afterDecryptionFailure)
.enableShareHistoryOnInvite(enableShareHistoryOnInvite: enableKeyShareOnInvite)
.autoEnableBackups(autoEnableBackups: true) .autoEnableBackups(autoEnableBackups: true)
if enableOnlySignedDeviceIsolationMode { if enableOnlySignedDeviceIsolationMode {
@@ -42,6 +42,7 @@ protocol DeveloperOptionsProtocol: AnyObject {
var hideUnreadMessagesBadge: Bool { get set } var hideUnreadMessagesBadge: Bool { get set }
var fuzzyRoomListSearchEnabled: Bool { get set } var fuzzyRoomListSearchEnabled: Bool { get set }
var enableOnlySignedDeviceIsolationMode: Bool { get set } var enableOnlySignedDeviceIsolationMode: Bool { get set }
var enableKeyShareOnInvite: Bool { get set }
var elementCallBaseURLOverride: URL? { get set } var elementCallBaseURLOverride: URL? { get set }
var knockingEnabled: Bool { get set } var knockingEnabled: Bool { get set }
var threadsEnabled: Bool { get set } var threadsEnabled: Bool { get set }
@@ -75,6 +75,16 @@ struct DeveloperOptionsScreen: View {
Text("This setting controls how end-to-end encryption (E2EE) keys are exchanged. Enabling it will prevent the inclusion of devices that have not been explicitly verified by their owners.") Text("This setting controls how end-to-end encryption (E2EE) keys are exchanged. Enabling it will prevent the inclusion of devices that have not been explicitly verified by their owners.")
} }
Section {
Toggle(isOn: $context.enableKeyShareOnInvite) {
Text("Share encrypted history with new members")
Text("Requires app reboot")
}
} footer: {
Text("When inviting a user to an encrypted room that has history visibility set to \"shared\", share encrypted history with that user, and accept encrypted history when you are invited to such a room.")
Text("WARNING: this feature is EXPERIMENTAL and not all security precautions are implemented. Do not enable on production accounts.")
}
Section { Section {
TextField("Leave empty to use EC locally", text: $elementCallURLOverrideString) TextField("Leave empty to use EC locally", text: $elementCallURLOverrideString)
.autocorrectionDisabled(true) .autocorrectionDisabled(true)
@@ -48,7 +48,8 @@ struct AuthenticationClientBuilder: AuthenticationClientBuilderProtocol {
slidingSync: .discover, slidingSync: .discover,
sessionDelegate: clientSessionDelegate, sessionDelegate: clientSessionDelegate,
appHooks: appHooks, appHooks: appHooks,
enableOnlySignedDeviceIsolationMode: appSettings.enableOnlySignedDeviceIsolationMode) enableOnlySignedDeviceIsolationMode: appSettings.enableOnlySignedDeviceIsolationMode,
enableKeyShareOnInvite: appSettings.enableKeyShareOnInvite)
.sessionPaths(dataPath: sessionDirectories.dataPath, .sessionPaths(dataPath: sessionDirectories.dataPath,
cachePath: sessionDirectories.cachePath) cachePath: sessionDirectories.cachePath)
.sessionPassphrase(passphrase: passphrase) .sessionPassphrase(passphrase: passphrase)
@@ -123,7 +123,8 @@ class UserSessionStore: UserSessionStoreProtocol {
slidingSync: .restored, slidingSync: .restored,
sessionDelegate: keychainController, sessionDelegate: keychainController,
appHooks: appHooks, appHooks: appHooks,
enableOnlySignedDeviceIsolationMode: appSettings.enableOnlySignedDeviceIsolationMode) enableOnlySignedDeviceIsolationMode: appSettings.enableOnlySignedDeviceIsolationMode,
enableKeyShareOnInvite: appSettings.enableKeyShareOnInvite)
.sessionPaths(dataPath: credentials.restorationToken.sessionDirectories.dataPath, .sessionPaths(dataPath: credentials.restorationToken.sessionDirectories.dataPath,
cachePath: credentials.restorationToken.sessionDirectories.cachePath) cachePath: credentials.restorationToken.sessionDirectories.cachePath)
.username(username: credentials.userID) .username(username: credentials.userID)
+1
View File
@@ -61,6 +61,7 @@ final class NSEUserSession {
sessionDelegate: clientSessionDelegate, sessionDelegate: clientSessionDelegate,
appHooks: appHooks, appHooks: appHooks,
enableOnlySignedDeviceIsolationMode: appSettings.enableOnlySignedDeviceIsolationMode, enableOnlySignedDeviceIsolationMode: appSettings.enableOnlySignedDeviceIsolationMode,
enableKeyShareOnInvite: appSettings.enableKeyShareOnInvite,
requestTimeout: 15000, requestTimeout: 15000,
maxRequestRetryTime: 5000) maxRequestRetryTime: 5000)
.systemIsMemoryConstrained() .systemIsMemoryConstrained()