diff --git a/ElementX/Sources/Application/AppSettings.swift b/ElementX/Sources/Application/AppSettings.swift index 168b3c2dd..c4df2819d 100644 --- a/ElementX/Sources/Application/AppSettings.swift +++ b/ElementX/Sources/Application/AppSettings.swift @@ -17,6 +17,7 @@ protocol CommonSettingsProtocol { var logLevel: LogLevel { get } var traceLogPacks: Set { get } var enableOnlySignedDeviceIsolationMode: Bool { get } + var enableKeyShareOnInvite: Bool { get } var hideQuietNotificationAlerts: Bool { get } } @@ -52,6 +53,7 @@ final class AppSettings { case publicSearchEnabled case fuzzyRoomListSearchEnabled case enableOnlySignedDeviceIsolationMode + case enableKeyShareOnInvite case knockingEnabled case threadsEnabled 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. @UserPreference(key: UserDefaultsKeys.enableOnlySignedDeviceIsolationMode, defaultValue: false, storageType: .userDefaults(store)) 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)) var hideQuietNotificationAlerts } diff --git a/ElementX/Sources/Other/Extensions/ClientBuilder.swift b/ElementX/Sources/Other/Extensions/ClientBuilder.swift index 2ba5b096d..ed49db108 100644 --- a/ElementX/Sources/Other/Extensions/ClientBuilder.swift +++ b/ElementX/Sources/Other/Extensions/ClientBuilder.swift @@ -16,6 +16,7 @@ extension ClientBuilder { sessionDelegate: ClientSessionDelegate, appHooks: AppHooks, enableOnlySignedDeviceIsolationMode: Bool, + enableKeyShareOnInvite: Bool, requestTimeout: UInt64? = 30000, maxRequestRetryTime: UInt64? = nil) -> ClientBuilder { var builder = ClientBuilder() @@ -37,6 +38,7 @@ extension ClientBuilder { builder = builder .autoEnableCrossSigning(autoEnableCrossSigning: true) .backupDownloadStrategy(backupDownloadStrategy: .afterDecryptionFailure) + .enableShareHistoryOnInvite(enableShareHistoryOnInvite: enableKeyShareOnInvite) .autoEnableBackups(autoEnableBackups: true) if enableOnlySignedDeviceIsolationMode { diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift index cad121135..0ce737565 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift @@ -42,6 +42,7 @@ protocol DeveloperOptionsProtocol: AnyObject { var hideUnreadMessagesBadge: Bool { get set } var fuzzyRoomListSearchEnabled: Bool { get set } var enableOnlySignedDeviceIsolationMode: Bool { get set } + var enableKeyShareOnInvite: Bool { get set } var elementCallBaseURLOverride: URL? { get set } var knockingEnabled: Bool { get set } var threadsEnabled: Bool { get set } diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift index ab72abc19..6276b71e3 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift @@ -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.") } + 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 { TextField("Leave empty to use EC locally", text: $elementCallURLOverrideString) .autocorrectionDisabled(true) diff --git a/ElementX/Sources/Services/Authentication/AuthenticationClientBuilder.swift b/ElementX/Sources/Services/Authentication/AuthenticationClientBuilder.swift index 11d95e30a..afed1fcbe 100644 --- a/ElementX/Sources/Services/Authentication/AuthenticationClientBuilder.swift +++ b/ElementX/Sources/Services/Authentication/AuthenticationClientBuilder.swift @@ -48,7 +48,8 @@ struct AuthenticationClientBuilder: AuthenticationClientBuilderProtocol { slidingSync: .discover, sessionDelegate: clientSessionDelegate, appHooks: appHooks, - enableOnlySignedDeviceIsolationMode: appSettings.enableOnlySignedDeviceIsolationMode) + enableOnlySignedDeviceIsolationMode: appSettings.enableOnlySignedDeviceIsolationMode, + enableKeyShareOnInvite: appSettings.enableKeyShareOnInvite) .sessionPaths(dataPath: sessionDirectories.dataPath, cachePath: sessionDirectories.cachePath) .sessionPassphrase(passphrase: passphrase) diff --git a/ElementX/Sources/Services/UserSession/UserSessionStore.swift b/ElementX/Sources/Services/UserSession/UserSessionStore.swift index 883969b0d..0af170f21 100644 --- a/ElementX/Sources/Services/UserSession/UserSessionStore.swift +++ b/ElementX/Sources/Services/UserSession/UserSessionStore.swift @@ -123,7 +123,8 @@ class UserSessionStore: UserSessionStoreProtocol { slidingSync: .restored, sessionDelegate: keychainController, appHooks: appHooks, - enableOnlySignedDeviceIsolationMode: appSettings.enableOnlySignedDeviceIsolationMode) + enableOnlySignedDeviceIsolationMode: appSettings.enableOnlySignedDeviceIsolationMode, + enableKeyShareOnInvite: appSettings.enableKeyShareOnInvite) .sessionPaths(dataPath: credentials.restorationToken.sessionDirectories.dataPath, cachePath: credentials.restorationToken.sessionDirectories.cachePath) .username(username: credentials.userID) diff --git a/NSE/Sources/NSEUserSession.swift b/NSE/Sources/NSEUserSession.swift index 1d1c40d85..8f892ffc4 100644 --- a/NSE/Sources/NSEUserSession.swift +++ b/NSE/Sources/NSEUserSession.swift @@ -61,6 +61,7 @@ final class NSEUserSession { sessionDelegate: clientSessionDelegate, appHooks: appHooks, enableOnlySignedDeviceIsolationMode: appSettings.enableOnlySignedDeviceIsolationMode, + enableKeyShareOnInvite: appSettings.enableKeyShareOnInvite, requestTimeout: 15000, maxRequestRetryTime: 5000) .systemIsMemoryConstrained()