Promote "history sharing on invite" out of developer options (#5480)
* Enable key-share-on-invite irrespective of feature flag * Remove feature-flag dep: warning on starting chat with new people * Remove feature-flag dep: invite from room member details * Remove feature-flag dep: warning on new users in invite screen * Remove feature-flag dep: from room details screen * Remove feature-flag dep: starting chat from user profile screen * Remove feature-flag dep: timeline info on forwarded keys * Remove feature-flag dep: RoomScreenModel * Remove `enableKeyShareOnInvite` from AppSettings * Remove `enableKeyShareOnInvite` feature flag * Remove outdated comments * Update preview test room snapshots as their header now includes the history sharing icon
This commit is contained in:
committed by
GitHub
parent
d0e60becf4
commit
bc32a05a2c
@@ -23,7 +23,6 @@ protocol CommonSettingsProtocol: AnyObject {
|
||||
var bugReportRageshakeURL: RemotePreference<RageshakeConfiguration> { get }
|
||||
|
||||
var enableOnlySignedDeviceIsolationMode: Bool { get }
|
||||
var enableKeyShareOnInvite: Bool { get }
|
||||
var threadsEnabled: Bool { get }
|
||||
var hideQuietNotificationAlerts: Bool { get }
|
||||
}
|
||||
@@ -76,7 +75,6 @@ final class AppSettings {
|
||||
case fuzzyRoomListSearchEnabled
|
||||
case lowPriorityFilterEnabled
|
||||
case enableOnlySignedDeviceIsolationMode
|
||||
case enableKeyShareOnInvite
|
||||
case knockingEnabled
|
||||
case threadsEnabled
|
||||
case roomThreadListEnabled
|
||||
@@ -433,10 +431,6 @@ final class AppSettings {
|
||||
@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.knockingEnabled, defaultValue: false, storageType: .userDefaults(store))
|
||||
var knockingEnabled
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ extension ClientBuilder {
|
||||
sessionDelegate: ClientSessionDelegate,
|
||||
appHooks: AppHooks,
|
||||
enableOnlySignedDeviceIsolationMode: Bool,
|
||||
enableKeyShareOnInvite: Bool,
|
||||
requestTimeout: UInt64? = 30000,
|
||||
maxRequestRetryTime: UInt64? = nil,
|
||||
threadsEnabled: Bool) -> ClientBuilder {
|
||||
@@ -40,7 +39,7 @@ extension ClientBuilder {
|
||||
builder = builder
|
||||
.autoEnableCrossSigning(autoEnableCrossSigning: true)
|
||||
.backupDownloadStrategy(backupDownloadStrategy: .afterDecryptionFailure)
|
||||
.enableShareHistoryOnInvite(enableShareHistoryOnInvite: enableKeyShareOnInvite)
|
||||
.enableShareHistoryOnInvite(enableShareHistoryOnInvite: true)
|
||||
.autoEnableBackups(autoEnableBackups: true)
|
||||
}
|
||||
|
||||
|
||||
@@ -61,8 +61,7 @@ class InviteUsersScreenViewModel: InviteUsersScreenViewModelType, InviteUsersScr
|
||||
case .cancel:
|
||||
actionsSubject.send(.dismiss)
|
||||
case .proceed:
|
||||
guard appSettings.enableKeyShareOnInvite,
|
||||
roomProxy.details.historySharingState != RoomHistorySharingState.hidden,
|
||||
guard roomProxy.details.historySharingState != RoomHistorySharingState.hidden,
|
||||
!state.usersToConfirm.isEmpty,
|
||||
!state.isSkippable else {
|
||||
inviteUsers(state.selectedUsers.map(\.userID), roomProxy: roomProxy)
|
||||
@@ -107,11 +106,7 @@ class InviteUsersScreenViewModel: InviteUsersScreenViewModelType, InviteUsersScr
|
||||
}
|
||||
|
||||
private func inviteUsers(_ users: [String], roomProxy: JoinedRoomProxyProtocol) {
|
||||
if appSettings.enableKeyShareOnInvite {
|
||||
showLoadingIndicator(title: L10n.screenRoomDetailsInvitePeoplePreparing, message: L10n.screenRoomDetailsInvitePeopleDontClose)
|
||||
} else {
|
||||
showLoadingIndicator()
|
||||
}
|
||||
showLoadingIndicator(title: L10n.screenRoomDetailsInvitePeoplePreparing, message: L10n.screenRoomDetailsInvitePeopleDontClose)
|
||||
|
||||
Task {
|
||||
defer {
|
||||
|
||||
@@ -61,13 +61,7 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
||||
|
||||
let topic = attributedStringBuilder.fromPlain(roomProxy.infoPublisher.value.topic)
|
||||
|
||||
// Clear details.historySharingState manually while we are still behind a feature flag.
|
||||
var details = roomProxy.details
|
||||
if !appSettings.enableKeyShareOnInvite {
|
||||
details.historySharingState = nil
|
||||
}
|
||||
|
||||
super.init(initialViewState: .init(details: details,
|
||||
super.init(initialViewState: .init(details: roomProxy.details,
|
||||
isEncrypted: roomProxy.infoPublisher.value.isEncrypted,
|
||||
isDirect: roomProxy.infoPublisher.value.isDirect,
|
||||
topic: topic,
|
||||
@@ -280,14 +274,7 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
||||
state.joinedMembersCount = roomInfo.joinedMembersCount
|
||||
|
||||
state.details = roomProxy.details
|
||||
|
||||
// Set state.details.historySharingState manually while we are still behind
|
||||
// a feature flag.
|
||||
if appSettings.enableKeyShareOnInvite {
|
||||
state.details.historySharingState = roomInfo.historySharingState
|
||||
} else {
|
||||
state.details.historySharingState = nil
|
||||
}
|
||||
state.details.historySharingState = roomInfo.historySharingState
|
||||
|
||||
let topic = attributedStringBuilder.fromPlain(roomInfo.topic)
|
||||
state.topic = topic
|
||||
|
||||
@@ -374,7 +374,6 @@ struct RoomDetailsScreen_Previews: PreviewProvider, TestablePreview {
|
||||
}
|
||||
|
||||
private static func makeGenericRoomViewModel(historyVisibility: RoomHistoryVisibility) -> RoomDetailsScreenViewModel {
|
||||
ServiceLocator.shared.settings.enableKeyShareOnInvite = true
|
||||
ServiceLocator.shared.settings.knockingEnabled = true
|
||||
let knockRequests: [KnockRequestProxyMock] = [.init()]
|
||||
|
||||
@@ -418,7 +417,6 @@ struct RoomDetailsScreen_Previews: PreviewProvider, TestablePreview {
|
||||
}
|
||||
|
||||
private static func makeSimpleRoomViewModel() -> RoomDetailsScreenViewModel {
|
||||
ServiceLocator.shared.settings.enableKeyShareOnInvite = true
|
||||
ServiceLocator.shared.settings.knockingEnabled = true
|
||||
let knockRequests: [KnockRequestProxyMock] = [.init()]
|
||||
|
||||
@@ -448,8 +446,6 @@ struct RoomDetailsScreen_Previews: PreviewProvider, TestablePreview {
|
||||
}
|
||||
|
||||
private static func makeDMViewModel(verificationState: UserIdentityVerificationState) -> RoomDetailsScreenViewModel {
|
||||
ServiceLocator.shared.settings.enableKeyShareOnInvite = true
|
||||
|
||||
let members: [RoomMemberProxyMock] = [
|
||||
.mockMe,
|
||||
.mockDan
|
||||
|
||||
@@ -200,7 +200,7 @@ class RoomMemberDetailsScreenViewModel: RoomMemberDetailsScreenViewModelType, Ro
|
||||
case .success(let roomID):
|
||||
if let roomID {
|
||||
actionsSubject.send(.openDirectChat(roomID: roomID))
|
||||
} else if appSettings.enableKeyShareOnInvite, roomProxy.details.historySharingState != RoomHistorySharingState.hidden {
|
||||
} else if roomProxy.details.historySharingState != RoomHistorySharingState.hidden {
|
||||
Task {
|
||||
let identity = await self.userSession.clientProxy.userIdentity(for: roomMemberProxy.userID, fallBackToServer: false)
|
||||
let user: UserProfileProxy = .init(userID: roomMemberProxy.userID, displayName: roomMemberProxy.displayName, avatarURL: roomMemberProxy.avatarURL)
|
||||
|
||||
@@ -94,7 +94,7 @@ struct RoomScreenViewState: BindableState {
|
||||
(canAcceptKnocks || canDeclineKnocks || canBan)
|
||||
}
|
||||
|
||||
/// If `enableKeyShareOnInvite` is set, determines the current history sharing state.
|
||||
/// The current history sharing state.
|
||||
var roomHistorySharingState: RoomHistorySharingState?
|
||||
|
||||
var footerDetails: RoomScreenFooterViewDetails?
|
||||
|
||||
@@ -67,18 +67,12 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
self.initialSelectedPinnedEventID = initialSelectedPinnedEventID
|
||||
pinnedEventStringBuilder = .pinnedEventStringBuilder(userID: roomProxy.ownUserID)
|
||||
|
||||
let roomHistorySharingState: RoomHistorySharingState? = if appSettings.enableKeyShareOnInvite {
|
||||
roomProxy.infoPublisher.value.historySharingState
|
||||
} else {
|
||||
nil
|
||||
}
|
||||
|
||||
let viewState = RoomScreenViewState(roomTitle: roomProxy.infoPublisher.value.displayName ?? roomProxy.id,
|
||||
roomAvatar: roomProxy.infoPublisher.value.avatar,
|
||||
hasOngoingCall: roomProxy.infoPublisher.value.hasRoomCall,
|
||||
isDirectOneToOneRoom: roomProxy.isDirectOneToOneRoom,
|
||||
hasSuccessor: roomProxy.infoPublisher.value.successor != nil,
|
||||
roomHistorySharingState: roomHistorySharingState)
|
||||
roomHistorySharingState: roomProxy.infoPublisher.value.historySharingState)
|
||||
super.init(initialViewState: appHooks.roomScreenHook.update(viewState),
|
||||
mediaProvider: userSession.mediaProvider)
|
||||
|
||||
@@ -371,13 +365,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
state.canBan = powerLevels.canOwnUserBan()
|
||||
}
|
||||
|
||||
// This causes the UI to become inconsistent with the user's mental model if the user
|
||||
// does not restart the app after disabling the feature flag. We can probably ignore
|
||||
// such cases, since we explicitly ask for an app restart in the caption of the feature
|
||||
// flag switch.
|
||||
if appSettings.enableKeyShareOnInvite {
|
||||
state.roomHistorySharingState = roomInfo.historySharingState
|
||||
}
|
||||
state.roomHistorySharingState = roomInfo.historySharingState
|
||||
}
|
||||
|
||||
private func setupPinnedEventsTimelineItemProviderIfNeeded() {
|
||||
|
||||
@@ -55,7 +55,6 @@ protocol DeveloperOptionsProtocol: AnyObject {
|
||||
var traceLogPacks: Set<TraceLogPack> { get set }
|
||||
|
||||
var enableOnlySignedDeviceIsolationMode: Bool { get set }
|
||||
var enableKeyShareOnInvite: Bool { get set }
|
||||
var hideQuietNotificationAlerts: Bool { get set }
|
||||
var focusEventOnNotificationTap: Bool { get set }
|
||||
var automaticBackPaginationEnabled: Bool { get set }
|
||||
|
||||
@@ -113,16 +113,6 @@ 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("Element Call remote URL override") {
|
||||
TextField("Leave empty to use EC locally", text: $elementCallURLOverrideString)
|
||||
.autocorrectionDisabled(true)
|
||||
|
||||
@@ -67,20 +67,15 @@ class StartChatScreenViewModel: StartChatScreenViewModelType, StartChatScreenVie
|
||||
hideLoadingIndicator()
|
||||
actionsSubject.send(.showRoom(roomID: roomId))
|
||||
case .success:
|
||||
if appSettings.enableKeyShareOnInvite {
|
||||
Task {
|
||||
// If an error occured while fetching the identity, assume they are unknown.
|
||||
let isUnknown = if case .success(let identity) = await self.userSession.clientProxy.userIdentity(for: user.userID, fallBackToServer: false) {
|
||||
identity == nil
|
||||
} else {
|
||||
true
|
||||
}
|
||||
self.state.bindings.selectedUserToInvite = UserToInvite(user: user, isUnknown: isUnknown)
|
||||
hideLoadingIndicator()
|
||||
Task {
|
||||
// If an error occured while fetching the identity, assume they are unknown.
|
||||
let isUnknown = if case .success(let identity) = await self.userSession.clientProxy.userIdentity(for: user.userID, fallBackToServer: false) {
|
||||
identity == nil
|
||||
} else {
|
||||
true
|
||||
}
|
||||
} else {
|
||||
self.state.bindings.selectedUserToInvite = UserToInvite(user: user, isUnknown: isUnknown)
|
||||
hideLoadingIndicator()
|
||||
state.bindings.selectedUserToInvite = UserToInvite(user: user, isUnknown: false)
|
||||
}
|
||||
case .failure:
|
||||
hideLoadingIndicator()
|
||||
|
||||
@@ -144,8 +144,6 @@ struct TimelineViewState: BindableState {
|
||||
|
||||
var mapTilerConfiguration: MapTilerConfiguration
|
||||
|
||||
var enableKeyShareOnInvite: Bool
|
||||
|
||||
var stoppedLiveLocationIDs: Set<TimelineItemIdentifier> = []
|
||||
|
||||
var bindings: TimelineViewStateBindings
|
||||
|
||||
@@ -107,7 +107,6 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
||||
emojiProvider: emojiProvider,
|
||||
linkMetadataProvider: hideTimelineMedia ? nil : linkMetadataProvider,
|
||||
mapTilerConfiguration: appSettings.mapTilerConfiguration,
|
||||
enableKeyShareOnInvite: appSettings.enableKeyShareOnInvite,
|
||||
bindings: .init(reactionsCollapsed: [:])),
|
||||
mediaProvider: userSession.mediaProvider)
|
||||
|
||||
|
||||
@@ -335,7 +335,6 @@ private extension TimelineItemKeyForwarder {
|
||||
struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview {
|
||||
static let viewModel: TimelineViewModel = {
|
||||
let appSettings = AppSettings()
|
||||
appSettings.enableKeyShareOnInvite = true
|
||||
appSettings.threadsEnabled = true
|
||||
|
||||
let roomProxy = JoinedRoomProxyMock(.init())
|
||||
|
||||
@@ -15,8 +15,7 @@ extension View {
|
||||
adjustedDeliveryStatus: TimelineItemDeliveryStatus?,
|
||||
context: TimelineViewModel.Context) -> some View {
|
||||
modifier(TimelineItemSendInfoModifier(sendInfo: .init(timelineItem: timelineItem,
|
||||
adjustedDeliveryStatus: adjustedDeliveryStatus,
|
||||
enableKeyShareOnInvite: context.viewState.enableKeyShareOnInvite),
|
||||
adjustedDeliveryStatus: adjustedDeliveryStatus),
|
||||
context: context))
|
||||
}
|
||||
}
|
||||
@@ -150,7 +149,7 @@ private struct TimelineItemSendInfo {
|
||||
}
|
||||
|
||||
private extension TimelineItemSendInfo {
|
||||
init(timelineItem: EventBasedTimelineItemProtocol, adjustedDeliveryStatus: TimelineItemDeliveryStatus?, enableKeyShareOnInvite: Bool) {
|
||||
init(timelineItem: EventBasedTimelineItemProtocol, adjustedDeliveryStatus: TimelineItemDeliveryStatus?) {
|
||||
itemID = timelineItem.id
|
||||
localizedString = timelineItem.localizedSendInfo
|
||||
|
||||
@@ -158,7 +157,7 @@ private extension TimelineItemSendInfo {
|
||||
.sendingFailed
|
||||
} else if let authenticity = timelineItem.properties.encryptionAuthenticity {
|
||||
.encryptionAuthenticity(authenticity)
|
||||
} else if enableKeyShareOnInvite, let forwarder = timelineItem.properties.encryptionForwarder {
|
||||
} else if let forwarder = timelineItem.properties.encryptionForwarder {
|
||||
.encryptionForwarder(forwarder)
|
||||
} else {
|
||||
nil
|
||||
|
||||
@@ -127,17 +127,13 @@ class UserProfileScreenViewModel: UserProfileScreenViewModelType, UserProfileScr
|
||||
if let roomID {
|
||||
actionsSubject.send(.openDirectChat(roomID: roomID))
|
||||
} else {
|
||||
if appSettings.enableKeyShareOnInvite {
|
||||
Task {
|
||||
let isUnknown = if case let .success(identity) = await userSession.clientProxy.userIdentity(for: userProfile.userID, fallBackToServer: false) {
|
||||
identity == nil
|
||||
} else {
|
||||
true
|
||||
}
|
||||
state.bindings.inviteConfirmationUser = .init(user: userProfile, isUnknown: isUnknown)
|
||||
Task {
|
||||
let isUnknown = if case let .success(identity) = await userSession.clientProxy.userIdentity(for: userProfile.userID, fallBackToServer: false) {
|
||||
identity == nil
|
||||
} else {
|
||||
true
|
||||
}
|
||||
} else {
|
||||
state.bindings.inviteConfirmationUser = .init(user: userProfile, isUnknown: false)
|
||||
state.bindings.inviteConfirmationUser = .init(user: userProfile, isUnknown: isUnknown)
|
||||
}
|
||||
}
|
||||
case .failure:
|
||||
|
||||
@@ -38,7 +38,6 @@ struct AuthenticationClientFactory: AuthenticationClientFactoryProtocol {
|
||||
sessionDelegate: clientSessionDelegate,
|
||||
appHooks: appHooks,
|
||||
enableOnlySignedDeviceIsolationMode: appSettings.enableOnlySignedDeviceIsolationMode,
|
||||
enableKeyShareOnInvite: appSettings.enableKeyShareOnInvite,
|
||||
threadsEnabled: appSettings.threadsEnabled)
|
||||
.sqliteStore(config: .init(dataPath: sessionDirectories.dataPath, cachePath: sessionDirectories.cachePath)
|
||||
.passphrase(passphrase: passphrase))
|
||||
@@ -56,7 +55,6 @@ struct AuthenticationClientFactory: AuthenticationClientFactoryProtocol {
|
||||
sessionDelegate: clientSessionDelegate,
|
||||
appHooks: appHooks,
|
||||
enableOnlySignedDeviceIsolationMode: appSettings.enableOnlySignedDeviceIsolationMode,
|
||||
enableKeyShareOnInvite: appSettings.enableKeyShareOnInvite,
|
||||
threadsEnabled: appSettings.threadsEnabled)
|
||||
.inMemoryStore()
|
||||
.serverNameOrHomeserverUrl(serverNameOrUrl: homeserverAddress)
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
/// Enumeration of the two possible cases in which history sharing under MSC4268 is enabled. These
|
||||
/// variants implicitly assume that the feature flag, `enableKeyShareOnInvite`, is set.
|
||||
/// Enumeration of the two possible cases in which history sharing under MSC4268 is enabled.
|
||||
enum RoomHistorySharingState: Equatable {
|
||||
/// The feature flag is set, and the room history visibility is either `invited` or `joined`. New
|
||||
/// members of the room cannot read the room history.
|
||||
|
||||
@@ -136,8 +136,7 @@ extension RoomInfoProxyProtocol {
|
||||
return alternativeAliases.first
|
||||
}
|
||||
|
||||
/// If present, the state of history sharing in this room. This *does not* consider the `enableKeyShareOnInvite`
|
||||
/// feature flag, so consumers should be careful to check the flag is true before utilising this property.
|
||||
/// If present, the state of history sharing in this room.
|
||||
var historySharingState: RoomHistorySharingState? {
|
||||
guard isEncrypted else {
|
||||
return nil
|
||||
|
||||
@@ -136,7 +136,6 @@ class UserSessionStore: UserSessionStoreProtocol {
|
||||
sessionDelegate: keychainController,
|
||||
appHooks: appHooks,
|
||||
enableOnlySignedDeviceIsolationMode: appSettings.enableOnlySignedDeviceIsolationMode,
|
||||
enableKeyShareOnInvite: appSettings.enableKeyShareOnInvite,
|
||||
threadsEnabled: appSettings.threadsEnabled)
|
||||
.sqliteStore(config: .init(dataPath: credentials.restorationToken.sessionDirectories.dataPath,
|
||||
cachePath: credentials.restorationToken.sessionDirectories.cachePath)
|
||||
|
||||
Reference in New Issue
Block a user