From d2773b36f302d7e8cf3b6fd13721ee09ca11199a Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Tue, 12 Sep 2023 10:56:41 +0300 Subject: [PATCH 1/6] Prepare for new sprint --- Config/AppVersion.xcconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Config/AppVersion.xcconfig b/Config/AppVersion.xcconfig index ad10bbd700..eabcc9b01e 100644 --- a/Config/AppVersion.xcconfig +++ b/Config/AppVersion.xcconfig @@ -15,5 +15,5 @@ // // Version -MARKETING_VERSION = 1.11.2 -CURRENT_PROJECT_VERSION = 1.11.2 +MARKETING_VERSION = 1.11.3 +CURRENT_PROJECT_VERSION = 1.11.3 From 718ecdad42e2c3e4bf33404eff0adaa5fcd82907 Mon Sep 17 00:00:00 2001 From: Doug <6060466+pixlwave@users.noreply.github.com> Date: Tue, 12 Sep 2023 13:46:36 +0100 Subject: [PATCH 2/6] Hide sign out x/all buttons in the Device Manager when using OIDC. (#7674) --- .../UserSessionsFlowCoordinator.swift | 4 +- .../UserOtherSessionsCoordinator.swift | 2 + .../MockUserOtherSessionsScreenState.swift | 5 +++ .../UserOtherSessionsViewModelTests.swift | 40 +++++++++++++------ .../UserOtherSessionsModels.swift | 1 + .../UserOtherSessionsViewModel.swift | 4 +- .../View/UserOtherSessions.swift | 1 + .../View/UserOtherSessionsToolbar.swift | 3 +- .../UserSessionsOverviewCoordinator.swift | 5 ++- .../MockUserSessionsOverviewScreenState.swift | 2 +- .../UserSessionsOverviewViewModelTests.swift | 16 ++++++-- .../UserSessionsOverviewModels.swift | 1 + .../UserSessionsOverviewViewModel.swift | 4 +- .../View/UserSessionsOverview.swift | 12 +++--- changelog.d/7672.bugfix | 1 + 15 files changed, 72 insertions(+), 29 deletions(-) create mode 100644 changelog.d/7672.bugfix diff --git a/RiotSwiftUI/Modules/UserSessions/Coordinator/UserSessionsFlowCoordinator.swift b/RiotSwiftUI/Modules/UserSessions/Coordinator/UserSessionsFlowCoordinator.swift index 041f5a1ae0..5225b9fd0a 100644 --- a/RiotSwiftUI/Modules/UserSessions/Coordinator/UserSessionsFlowCoordinator.swift +++ b/RiotSwiftUI/Modules/UserSessions/Coordinator/UserSessionsFlowCoordinator.swift @@ -188,9 +188,11 @@ final class UserSessionsFlowCoordinator: NSObject, Coordinator, Presentable { private func createOtherSessionsCoordinator(sessionInfos: [UserSessionInfo], filterBy filter: UserOtherSessionsFilter, title: String) -> UserOtherSessionsCoordinator { + let shouldShowDeviceLogout = parameters.session.homeserverWellknown.authentication == nil let parameters = UserOtherSessionsCoordinatorParameters(sessionInfos: sessionInfos, filter: filter, - title: title) + title: title, + showDeviceLogout: shouldShowDeviceLogout) return UserOtherSessionsCoordinator(parameters: parameters) } diff --git a/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/Coordinator/UserOtherSessionsCoordinator.swift b/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/Coordinator/UserOtherSessionsCoordinator.swift index 8f9dab072a..a848a2bf89 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/Coordinator/UserOtherSessionsCoordinator.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/Coordinator/UserOtherSessionsCoordinator.swift @@ -21,6 +21,7 @@ struct UserOtherSessionsCoordinatorParameters { let sessionInfos: [UserSessionInfo] let filter: UserOtherSessionsFilter let title: String + let showDeviceLogout: Bool } final class UserOtherSessionsCoordinator: Coordinator, Presentable { @@ -40,6 +41,7 @@ final class UserOtherSessionsCoordinator: Coordinator, Presentable { let viewModel = UserOtherSessionsViewModel(sessionInfos: parameters.sessionInfos, filter: parameters.filter, title: parameters.title, + showDeviceLogout: parameters.showDeviceLogout, settingsService: RiotSettings.shared) let view = UserOtherSessions(viewModel: viewModel.context) userOtherSessionsViewModel = viewModel diff --git a/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/MockUserOtherSessionsScreenState.swift b/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/MockUserOtherSessionsScreenState.swift index e81bb7f050..e357e77d03 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/MockUserOtherSessionsScreenState.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/MockUserOtherSessionsScreenState.swift @@ -49,26 +49,31 @@ enum MockUserOtherSessionsScreenState: MockScreenState, CaseIterable { viewModel = UserOtherSessionsViewModel(sessionInfos: allSessions(), filter: .all, title: VectorL10n.userSessionsOverviewOtherSessionsSectionTitle, + showDeviceLogout: true, settingsService: MockUserSessionSettings()) case .none: viewModel = UserOtherSessionsViewModel(sessionInfos: [], filter: .all, title: VectorL10n.userSessionsOverviewOtherSessionsSectionTitle, + showDeviceLogout: true, settingsService: MockUserSessionSettings()) case .inactiveSessions: viewModel = UserOtherSessionsViewModel(sessionInfos: inactiveSessions(), filter: .inactive, title: VectorL10n.userOtherSessionSecurityRecommendationTitle, + showDeviceLogout: true, settingsService: MockUserSessionSettings()) case .unverifiedSessions: viewModel = UserOtherSessionsViewModel(sessionInfos: unverifiedSessions(), filter: .unverified, title: VectorL10n.userOtherSessionSecurityRecommendationTitle, + showDeviceLogout: true, settingsService: MockUserSessionSettings()) case .verifiedSessions: viewModel = UserOtherSessionsViewModel(sessionInfos: verifiedSessions(), filter: .verified, title: VectorL10n.userOtherSessionSecurityRecommendationTitle, + showDeviceLogout: true, settingsService: MockUserSessionSettings()) } diff --git a/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/Test/Unit/UserOtherSessionsViewModelTests.swift b/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/Test/Unit/UserOtherSessionsViewModelTests.swift index 270891d912..58d8b2dc7b 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/Test/Unit/UserOtherSessionsViewModelTests.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/Test/Unit/UserOtherSessionsViewModelTests.swift @@ -63,7 +63,8 @@ class UserOtherSessionsViewModelTests: XCTestCase { emptyItemsTitle: VectorL10n.userOtherSessionNoInactiveSessions, allItemsSelected: false, enableSignOutButton: false, - showLocationInfo: false) + showLocationInfo: false, + showDeviceLogout: true) XCTAssertEqual(sut.state, expectedState) } @@ -81,7 +82,8 @@ class UserOtherSessionsViewModelTests: XCTestCase { emptyItemsTitle: "", allItemsSelected: false, enableSignOutButton: false, - showLocationInfo: false) + showLocationInfo: false, + showDeviceLogout: true) XCTAssertEqual(sut.state, expectedState) } @@ -104,7 +106,8 @@ class UserOtherSessionsViewModelTests: XCTestCase { emptyItemsTitle: VectorL10n.userOtherSessionNoUnverifiedSessions, allItemsSelected: false, enableSignOutButton: false, - showLocationInfo: false) + showLocationInfo: false, + showDeviceLogout: true) XCTAssertEqual(expectedItems.count, 2) XCTAssertEqual(sut.state, expectedState) } @@ -123,7 +126,8 @@ class UserOtherSessionsViewModelTests: XCTestCase { emptyItemsTitle: VectorL10n.userOtherSessionNoVerifiedSessions, allItemsSelected: false, enableSignOutButton: false, - showLocationInfo: false) + showLocationInfo: false, + showDeviceLogout: true) XCTAssertEqual(sut.state, expectedState) } @@ -139,7 +143,8 @@ class UserOtherSessionsViewModelTests: XCTestCase { emptyItemsTitle: VectorL10n.userOtherSessionNoVerifiedSessions, allItemsSelected: false, enableSignOutButton: false, - showLocationInfo: false) + showLocationInfo: false, + showDeviceLogout: true) XCTAssertEqual(sut.state, expectedState) } @@ -155,7 +160,8 @@ class UserOtherSessionsViewModelTests: XCTestCase { emptyItemsTitle: VectorL10n.userOtherSessionNoUnverifiedSessions, allItemsSelected: false, enableSignOutButton: false, - showLocationInfo: false) + showLocationInfo: false, + showDeviceLogout: true) XCTAssertEqual(sut.state, expectedState) } @@ -171,7 +177,8 @@ class UserOtherSessionsViewModelTests: XCTestCase { emptyItemsTitle: VectorL10n.userOtherSessionNoInactiveSessions, allItemsSelected: false, enableSignOutButton: false, - showLocationInfo: false) + showLocationInfo: false, + showDeviceLogout: true) XCTAssertEqual(sut.state, expectedState) } @@ -192,7 +199,8 @@ class UserOtherSessionsViewModelTests: XCTestCase { emptyItemsTitle: "", allItemsSelected: true, enableSignOutButton: true, - showLocationInfo: false) + showLocationInfo: false, + showDeviceLogout: true) XCTAssertEqual(sut.state, expectedState) } @@ -213,7 +221,8 @@ class UserOtherSessionsViewModelTests: XCTestCase { emptyItemsTitle: "", allItemsSelected: false, enableSignOutButton: false, - showLocationInfo: false) + showLocationInfo: false, + showDeviceLogout: true) XCTAssertEqual(sut.state, expectedState) } @@ -233,7 +242,8 @@ class UserOtherSessionsViewModelTests: XCTestCase { emptyItemsTitle: "", allItemsSelected: false, enableSignOutButton: true, - showLocationInfo: false) + showLocationInfo: false, + showDeviceLogout: true) XCTAssertEqual(sut.state, expectedState) } @@ -253,7 +263,8 @@ class UserOtherSessionsViewModelTests: XCTestCase { emptyItemsTitle: "", allItemsSelected: true, enableSignOutButton: true, - showLocationInfo: false) + showLocationInfo: false, + showDeviceLogout: true) XCTAssertEqual(sut.state, expectedState) } @@ -273,7 +284,8 @@ class UserOtherSessionsViewModelTests: XCTestCase { emptyItemsTitle: "", allItemsSelected: false, enableSignOutButton: false, - showLocationInfo: false) + showLocationInfo: false, + showDeviceLogout: true) XCTAssertEqual(sut.state, expectedState) } @@ -296,7 +308,8 @@ class UserOtherSessionsViewModelTests: XCTestCase { emptyItemsTitle: "", allItemsSelected: false, enableSignOutButton: false, - showLocationInfo: false) + showLocationInfo: false, + showDeviceLogout: true) XCTAssertEqual(sut.state, expectedState) } @@ -352,6 +365,7 @@ class UserOtherSessionsViewModelTests: XCTestCase { UserOtherSessionsViewModel(sessionInfos: sessionInfos, filter: filter, title: title, + showDeviceLogout: true, settingsService: MockUserSessionSettings()) } diff --git a/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/UserOtherSessionsModels.swift b/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/UserOtherSessionsModels.swift index deeb5ab955..d486e1cc4c 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/UserOtherSessionsModels.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/UserOtherSessionsModels.swift @@ -43,6 +43,7 @@ struct UserOtherSessionsViewState: BindableState, Equatable { var allItemsSelected: Bool var enableSignOutButton: Bool var showLocationInfo: Bool + var showDeviceLogout: Bool } struct UserOtherSessionsBindings: Equatable { diff --git a/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/UserOtherSessionsViewModel.swift b/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/UserOtherSessionsViewModel.swift index 84ea6f9ad1..abfb5e99fe 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/UserOtherSessionsViewModel.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/UserOtherSessionsViewModel.swift @@ -28,6 +28,7 @@ class UserOtherSessionsViewModel: UserOtherSessionsViewModelType, UserOtherSessi init(sessionInfos: [UserSessionInfo], filter: UserOtherSessionsFilter, title: String, + showDeviceLogout: Bool, settingsService: UserSessionSettingsProtocol) { self.sessionInfos = sessionInfos defaultTitle = title @@ -41,7 +42,8 @@ class UserOtherSessionsViewModel: UserOtherSessionsViewModelType, UserOtherSessi emptyItemsTitle: filter.userOtherSessionsViewEmptyResultsTitle, allItemsSelected: false, enableSignOutButton: false, - showLocationInfo: settingsService.showIPAddressesInSessionsManager)) + showLocationInfo: settingsService.showIPAddressesInSessionsManager, + showDeviceLogout: showDeviceLogout)) } // MARK: - Public diff --git a/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/View/UserOtherSessions.swift b/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/View/UserOtherSessions.swift index 41d79fe547..92eb505b03 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/View/UserOtherSessions.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/View/UserOtherSessions.swift @@ -60,6 +60,7 @@ struct UserOtherSessions: View { set: { _ in withAnimation { viewModel.send(viewAction: .showLocationInfo) } }), allItemsSelected: viewModel.viewState.allItemsSelected, sessionCount: viewModel.viewState.sessionItems.count, + showDeviceLogout: viewModel.viewState.showDeviceLogout, onToggleSelection: { viewModel.send(viewAction: .toggleAllSelection) }, onSignOut: { viewModel.send(viewAction: .logoutAllUserSessions) }) } diff --git a/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/View/UserOtherSessionsToolbar.swift b/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/View/UserOtherSessionsToolbar.swift index 331ede0c3b..d3c0b3bb04 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/View/UserOtherSessionsToolbar.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/View/UserOtherSessionsToolbar.swift @@ -24,6 +24,7 @@ struct UserOtherSessionsToolbar: ToolbarContent { @Binding var isShowLocationEnabled: Bool let allItemsSelected: Bool let sessionCount: Int + let showDeviceLogout: Bool let onToggleSelection: () -> Void let onSignOut: () -> Void @@ -94,7 +95,7 @@ struct UserOtherSessionsToolbar: ToolbarContent { Label(showLocationInfo: isShowLocationEnabled) } - if sessionCount > 0 { + if sessionCount > 0, showDeviceLogout { DestructiveButton { onSignOut() } label: { diff --git a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/Coordinator/UserSessionsOverviewCoordinator.swift b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/Coordinator/UserSessionsOverviewCoordinator.swift index 7d3d0437c2..20a88aaf12 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/Coordinator/UserSessionsOverviewCoordinator.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/Coordinator/UserSessionsOverviewCoordinator.swift @@ -39,7 +39,10 @@ final class UserSessionsOverviewCoordinator: Coordinator, Presentable { self.parameters = parameters service = parameters.service - viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: parameters.service, settingsService: RiotSettings.shared) + let shouldShowDeviceLogout = parameters.session.homeserverWellknown.authentication == nil + viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: parameters.service, + settingsService: RiotSettings.shared, + showDeviceLogout: shouldShowDeviceLogout) hostingViewController = VectorHostingController(rootView: UserSessionsOverview(viewModel: viewModel.context)) hostingViewController.vc_setLargeTitleDisplayMode(.never) diff --git a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/MockUserSessionsOverviewScreenState.swift b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/MockUserSessionsOverviewScreenState.swift index e09586b833..6132febae2 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/MockUserSessionsOverviewScreenState.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/MockUserSessionsOverviewScreenState.swift @@ -51,7 +51,7 @@ enum MockUserSessionsOverviewScreenState: MockScreenState, CaseIterable { fatalError() } - let viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: service, settingsService: MockUserSessionSettings()) + let viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: service, settingsService: MockUserSessionSettings(), showDeviceLogout: true) return ( [service, viewModel], diff --git a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/Test/Unit/UserSessionsOverviewViewModelTests.swift b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/Test/Unit/UserSessionsOverviewViewModelTests.swift index 8ce396a6ec..27237983fc 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/Test/Unit/UserSessionsOverviewViewModelTests.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/Test/Unit/UserSessionsOverviewViewModelTests.swift @@ -21,7 +21,9 @@ import XCTest class UserSessionsOverviewViewModelTests: XCTestCase { func testInitialStateEmpty() { - let viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: MockUserSessionsOverviewService(), settingsService: MockUserSessionSettings()) + let viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: MockUserSessionsOverviewService(), + settingsService: MockUserSessionSettings(), + showDeviceLogout: true) XCTAssertNil(viewModel.state.currentSessionViewData) XCTAssertTrue(viewModel.state.unverifiedSessionsViewData.isEmpty) @@ -31,7 +33,9 @@ class UserSessionsOverviewViewModelTests: XCTestCase { } func testLoadOnDidAppear() { - let viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: MockUserSessionsOverviewService(), settingsService: MockUserSessionSettings()) + let viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: MockUserSessionsOverviewService(), + settingsService: MockUserSessionSettings(), + showDeviceLogout: true) viewModel.process(viewAction: .viewAppeared) XCTAssertNotNil(viewModel.state.currentSessionViewData) @@ -42,7 +46,9 @@ class UserSessionsOverviewViewModelTests: XCTestCase { } func testSimpleActionProcessing() { - let viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: MockUserSessionsOverviewService(), settingsService: MockUserSessionSettings()) + let viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: MockUserSessionsOverviewService(), + settingsService: MockUserSessionSettings(), + showDeviceLogout: true) var result: UserSessionsOverviewViewModelResult? viewModel.completion = { action in @@ -69,7 +75,9 @@ class UserSessionsOverviewViewModelTests: XCTestCase { let service = MockUserSessionsOverviewService() service.updateOverviewData { _ in } - let viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: service, settingsService: MockUserSessionSettings()) + let viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: service, + settingsService: MockUserSessionSettings(), + showDeviceLogout: true) var result: UserSessionsOverviewViewModelResult? viewModel.completion = { action in diff --git a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/UserSessionsOverviewModels.swift b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/UserSessionsOverviewModels.swift index a7429f12f0..74f35a087f 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/UserSessionsOverviewModels.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/UserSessionsOverviewModels.swift @@ -51,6 +51,7 @@ struct UserSessionsOverviewViewState: BindableState { var showLoadingIndicator = false var linkDeviceButtonVisible = false var showLocationInfo: Bool + var showDeviceLogout: Bool } enum UserSessionsOverviewViewAction { diff --git a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/UserSessionsOverviewViewModel.swift b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/UserSessionsOverviewViewModel.swift index a2d92628a6..2441260080 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/UserSessionsOverviewViewModel.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/UserSessionsOverviewViewModel.swift @@ -24,11 +24,11 @@ class UserSessionsOverviewViewModel: UserSessionsOverviewViewModelType, UserSess var completion: ((UserSessionsOverviewViewModelResult) -> Void)? - init(userSessionsOverviewService: UserSessionsOverviewServiceProtocol, settingsService: UserSessionSettingsProtocol) { + init(userSessionsOverviewService: UserSessionsOverviewServiceProtocol, settingsService: UserSessionSettingsProtocol, showDeviceLogout: Bool) { self.userSessionsOverviewService = userSessionsOverviewService self.settingsService = settingsService - super.init(initialViewState: .init(showLocationInfo: settingsService.showIPAddressesInSessionsManager)) + super.init(initialViewState: .init(showLocationInfo: settingsService.showIPAddressesInSessionsManager, showDeviceLogout: showDeviceLogout)) userSessionsOverviewService.overviewDataPublisher.sink { [weak self] overviewData in self?.updateViewState(with: overviewData) diff --git a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/View/UserSessionsOverview.swift b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/View/UserSessionsOverview.swift index 9cfc89ca48..c78718346f 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/View/UserSessionsOverview.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/View/UserSessionsOverview.swift @@ -125,7 +125,7 @@ struct UserSessionsOverview: View { Label(VectorL10n.signOut, systemImage: "rectangle.portrait.and.arrow.right.fill") } } - if viewModel.viewState.otherSessionsViewData.count > 0 { + if viewModel.viewState.otherSessionsViewData.count > 0, viewModel.viewState.showDeviceLogout { DestructiveButton { viewModel.send(viewAction: .logoutOtherSessions) } label: { @@ -149,10 +149,12 @@ struct UserSessionsOverview: View { Label(showLocationInfo: viewModel.viewState.showLocationInfo) } - DestructiveButton { - viewModel.send(viewAction: .logoutOtherSessions) - } label: { - Label(VectorL10n.userOtherSessionMenuSignOutSessions(String(viewModel.viewState.otherSessionsViewData.count)), systemImage: "rectangle.portrait.and.arrow.forward.fill") + if viewModel.viewState.showDeviceLogout { + DestructiveButton { + viewModel.send(viewAction: .logoutOtherSessions) + } label: { + Label(VectorL10n.userOtherSessionMenuSignOutSessions(String(viewModel.viewState.otherSessionsViewData.count)), systemImage: "rectangle.portrait.and.arrow.forward.fill") + } } } label: { menuImage diff --git a/changelog.d/7672.bugfix b/changelog.d/7672.bugfix new file mode 100644 index 0000000000..d46797f9c8 --- /dev/null +++ b/changelog.d/7672.bugfix @@ -0,0 +1 @@ +Hide Sign Out X/All Sessions buttons in the Device Manager when using OIDC. \ No newline at end of file From b07ade15bb0ddcf8c60a7fde079748677d560bc1 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 12 Sep 2023 18:05:52 +0100 Subject: [PATCH 3/6] Use ASWebAuthenticationSession to display OIDC account management URL (#7671) Co-authored-by: Doug --- .../SSO/SSOAccountService.swift | 48 +++++++++++++++++++ .../SSO/SSOAuthenticationPresenter.swift | 4 +- .../SSO/SSOAuthenticationService.swift | 10 +++- .../ManageSessionViewController.m | 43 +++++++++++++---- .../Modules/Settings/SettingsViewController.m | 34 ++++++++++++- .../UserSessionsFlowCoordinator.swift | 37 +++++++++++--- changelog.d/7671.bugfix | 1 + 7 files changed, 158 insertions(+), 19 deletions(-) create mode 100644 Riot/Modules/Authentication/SSO/SSOAccountService.swift create mode 100644 changelog.d/7671.bugfix diff --git a/Riot/Modules/Authentication/SSO/SSOAccountService.swift b/Riot/Modules/Authentication/SSO/SSOAccountService.swift new file mode 100644 index 0000000000..4623fb84f8 --- /dev/null +++ b/Riot/Modules/Authentication/SSO/SSOAccountService.swift @@ -0,0 +1,48 @@ +// +// Copyright 2020 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation + +@objcMembers +/// A service for the SSOAuthenticationPresenter that allows to open an OIDC account management URL. +/// +/// Both `callBackURLScheme` and `loginToken` are unneeded for this use case and return `nil`. +final class SSOAccountService: NSObject, SSOAuthenticationServiceProtocol { + + // MARK: - Properties + + private let accountURL: URL + + let callBackURLScheme: String? = nil + + // MARK: - Setup + + init(accountURL: URL) { + self.accountURL = accountURL + super.init() + } + + // MARK: - Public + + func authenticationURL(for identityProvider: String?, transactionId: String) -> URL? { + accountURL + } + + func loginToken(from url: URL) -> String? { + MXLog.error("The account service shouldn't receive a completion callback.") + return nil + } +} diff --git a/Riot/Modules/Authentication/SSO/SSOAuthenticationPresenter.swift b/Riot/Modules/Authentication/SSO/SSOAuthenticationPresenter.swift index 1145d8651a..b45f3a804b 100644 --- a/Riot/Modules/Authentication/SSO/SSOAuthenticationPresenter.swift +++ b/Riot/Modules/Authentication/SSO/SSOAuthenticationPresenter.swift @@ -37,7 +37,7 @@ final class SSOAuthenticationPresenter: NSObject { // MARK: - Properties - private let ssoAuthenticationService: SSOAuthenticationService + private let ssoAuthenticationService: SSOAuthenticationServiceProtocol // MARK: Private @@ -53,7 +53,7 @@ final class SSOAuthenticationPresenter: NSObject { // MARK: - Setup - init(ssoAuthenticationService: SSOAuthenticationService) { + init(ssoAuthenticationService: SSOAuthenticationServiceProtocol) { self.ssoAuthenticationService = ssoAuthenticationService super.init() } diff --git a/Riot/Modules/Authentication/SSO/SSOAuthenticationService.swift b/Riot/Modules/Authentication/SSO/SSOAuthenticationService.swift index 706c3782d1..cb3d36d075 100644 --- a/Riot/Modules/Authentication/SSO/SSOAuthenticationService.swift +++ b/Riot/Modules/Authentication/SSO/SSOAuthenticationService.swift @@ -22,8 +22,16 @@ enum SSOAuthenticationServiceError: Error { case unknown } +@objc protocol SSOAuthenticationServiceProtocol { + var callBackURLScheme: String? { get } + + func authenticationURL(for identityProvider: String?, transactionId: String) -> URL? + + func loginToken(from url: URL) -> String? +} + @objcMembers -final class SSOAuthenticationService: NSObject { +final class SSOAuthenticationService: NSObject, SSOAuthenticationServiceProtocol { // MARK: - Constants diff --git a/Riot/Modules/Settings/Security/ManageSession/ManageSessionViewController.m b/Riot/Modules/Settings/Security/ManageSession/ManageSessionViewController.m index e1fd5c5e82..665f970acc 100644 --- a/Riot/Modules/Settings/Security/ManageSession/ManageSessionViewController.m +++ b/Riot/Modules/Settings/Security/ManageSession/ManageSessionViewController.m @@ -45,7 +45,7 @@ }; -@interface ManageSessionViewController () +@interface ManageSessionViewController () { // The device to display MXDevice *device; @@ -64,6 +64,8 @@ @interface ManageSessionViewController () +ChangePasswordCoordinatorBridgePresenterDelegate, +SSOAuthenticationPresenterDelegate> { // Current alert (if any). __weak UIAlertController *currentAlert; @@ -300,6 +301,8 @@ @interface SettingsViewController () Date: Wed, 13 Sep 2023 15:07:49 +0100 Subject: [PATCH 4/6] Also hide session selection with OIDC in the device manager. (#7675) --- .../View/UserOtherSessionsToolbar.swift | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/View/UserOtherSessionsToolbar.swift b/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/View/UserOtherSessionsToolbar.swift index d3c0b3bb04..ba844904ec 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/View/UserOtherSessionsToolbar.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/View/UserOtherSessionsToolbar.swift @@ -82,12 +82,14 @@ struct UserOtherSessionsToolbar: ToolbarContent { private func optionsMenu() -> some View { Button { } label: { Menu { - Button { - isEditModeEnabled = true - } label: { - Label(VectorL10n.userOtherSessionMenuSelectSessions, systemImage: "checkmark.circle") + if showDeviceLogout { // As you can only sign out the selected sessions, we don't allow selection when you're unable to sign out devices. + Button { + isEditModeEnabled = true + } label: { + Label(VectorL10n.userOtherSessionMenuSelectSessions, systemImage: "checkmark.circle") + } + .disabled(sessionCount == 0) } - .disabled(sessionCount == 0) Button { isShowLocationEnabled.toggle() From 77f16f041798c16b3dd566795a71ed8e64bc5090 Mon Sep 17 00:00:00 2001 From: Doug Date: Wed, 13 Sep 2023 15:19:11 +0100 Subject: [PATCH 5/6] version++ --- CHANGES.md | 8 ++++++++ changelog.d/7671.bugfix | 1 - changelog.d/7672.bugfix | 1 - 3 files changed, 8 insertions(+), 2 deletions(-) delete mode 100644 changelog.d/7671.bugfix delete mode 100644 changelog.d/7672.bugfix diff --git a/CHANGES.md b/CHANGES.md index 3a269699d9..9aacbd1686 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,11 @@ +## Changes in 1.11.3 (2023-09-13) + +🐛 Bugfixes + +- Show OIDC account management UI using embedded browser instead of system browser. ([#7671](https://github.com/vector-im/element-ios/issues/7671)) +- Hide Sign Out X/All Sessions buttons in the Device Manager when using OIDC. ([#7672](https://github.com/vector-im/element-ios/issues/7672)) + + ## Changes in 1.11.2 (2023-09-12) 🙌 Improvements diff --git a/changelog.d/7671.bugfix b/changelog.d/7671.bugfix deleted file mode 100644 index 99d153ad4b..0000000000 --- a/changelog.d/7671.bugfix +++ /dev/null @@ -1 +0,0 @@ -Show OIDC account management UI using embedded browser instead of system browser. \ No newline at end of file diff --git a/changelog.d/7672.bugfix b/changelog.d/7672.bugfix deleted file mode 100644 index d46797f9c8..0000000000 --- a/changelog.d/7672.bugfix +++ /dev/null @@ -1 +0,0 @@ -Hide Sign Out X/All Sessions buttons in the Device Manager when using OIDC. \ No newline at end of file From 12c90dd97436a9ebdaed3e2287e6af1f35e93037 Mon Sep 17 00:00:00 2001 From: Doug Date: Wed, 13 Sep 2023 16:06:20 +0100 Subject: [PATCH 6/6] finish version++