568 lines
25 KiB
Swift
568 lines
25 KiB
Swift
//
|
|
// Copyright 2022-2024 New Vector Ltd.
|
|
//
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
// Please see LICENSE in the repository root for full details.
|
|
//
|
|
|
|
import CommonKit
|
|
import Foundation
|
|
|
|
struct UserSessionsFlowCoordinatorParameters {
|
|
let session: MXSession
|
|
let router: NavigationRouterType
|
|
}
|
|
|
|
final class UserSessionsFlowCoordinator: NSObject, Coordinator, Presentable {
|
|
private let parameters: UserSessionsFlowCoordinatorParameters
|
|
private let allSessionsService: UserSessionsOverviewService
|
|
|
|
private let navigationRouter: NavigationRouterType
|
|
private var reauthenticationPresenter: ReauthenticationCoordinatorBridgePresenter?
|
|
private var signOutFlowPresenter: SignOutFlowPresenter?
|
|
private var errorPresenter: MXKErrorPresentation
|
|
private var indicatorPresenter: UserIndicatorTypePresenterProtocol
|
|
private var loadingIndicator: UserIndicator?
|
|
private var ssoAuthenticationPresenter: SSOAuthenticationPresenter?
|
|
|
|
/// The root coordinator for user session management.
|
|
private weak var sessionsOverviewCoordinator: UserSessionsOverviewCoordinator?
|
|
|
|
// Must be used only internally
|
|
var childCoordinators: [Coordinator] = []
|
|
var completion: (() -> Void)?
|
|
|
|
init(parameters: UserSessionsFlowCoordinatorParameters) {
|
|
self.parameters = parameters
|
|
|
|
let dataProvider = UserSessionsDataProvider(session: parameters.session)
|
|
allSessionsService = UserSessionsOverviewService(dataProvider: dataProvider)
|
|
|
|
navigationRouter = parameters.router
|
|
errorPresenter = MXKErrorAlertPresentation()
|
|
indicatorPresenter = UserIndicatorTypePresenter(presentingViewController: parameters.router.toPresentable())
|
|
}
|
|
|
|
// MARK: - Private
|
|
|
|
private func pushScreen(with coordinator: Coordinator & Presentable) {
|
|
add(childCoordinator: coordinator)
|
|
|
|
navigationRouter.push(coordinator, animated: true, popCompletion: { [weak self] in
|
|
self?.remove(childCoordinator: coordinator)
|
|
})
|
|
|
|
coordinator.start()
|
|
}
|
|
|
|
private func createUserSessionsOverviewCoordinator() -> UserSessionsOverviewCoordinator {
|
|
let parameters = UserSessionsOverviewCoordinatorParameters(session: parameters.session,
|
|
service: allSessionsService)
|
|
|
|
let coordinator = UserSessionsOverviewCoordinator(parameters: parameters)
|
|
coordinator.completion = { [weak self] result in
|
|
guard let self = self else { return }
|
|
switch result {
|
|
case .verifyCurrentSession:
|
|
self.showCompleteSecurity()
|
|
case let .renameSession(sessionInfo):
|
|
self.showRenameSessionScreen(for: sessionInfo)
|
|
case let .logoutOfSession(sessionInfo):
|
|
if sessionInfo.isCurrent {
|
|
self.showLogoutConfirmationForCurrentSession()
|
|
} else {
|
|
self.showLogoutConfirmation(for: [sessionInfo])
|
|
}
|
|
case let .openSessionOverview(sessionInfo: sessionInfo):
|
|
self.openSessionOverview(sessionInfo: sessionInfo)
|
|
case let .openOtherSessions(sessionInfos: sessionInfos, filter: filter):
|
|
self.openOtherSessions(sessionInfos: sessionInfos, filterBy: filter)
|
|
case .linkDevice:
|
|
self.openQRLoginScreen()
|
|
case let .logoutFromUserSessions(sessionInfos: sessionInfos):
|
|
self.showLogoutConfirmation(for: sessionInfos)
|
|
}
|
|
}
|
|
return coordinator
|
|
}
|
|
|
|
private func openSessionDetails(sessionInfo: UserSessionInfo) {
|
|
let coordinator = createUserSessionDetailsCoordinator(sessionInfo: sessionInfo)
|
|
pushScreen(with: coordinator)
|
|
}
|
|
|
|
private func createUserSessionDetailsCoordinator(sessionInfo: UserSessionInfo) -> UserSessionDetailsCoordinator {
|
|
let parameters = UserSessionDetailsCoordinatorParameters(sessionInfo: sessionInfo)
|
|
return UserSessionDetailsCoordinator(parameters: parameters)
|
|
}
|
|
|
|
private func openSessionOverview(sessionInfo: UserSessionInfo) {
|
|
let coordinator = createUserSessionOverviewCoordinator(sessionInfo: sessionInfo)
|
|
coordinator.completion = { [weak self] result in
|
|
guard let self = self else { return }
|
|
switch result {
|
|
case let .openSessionDetails(sessionInfo: sessionInfo):
|
|
self.openSessionDetails(sessionInfo: sessionInfo)
|
|
case let .verifySession(sessionInfo):
|
|
if sessionInfo.isCurrent {
|
|
self.showCompleteSecurity()
|
|
} else {
|
|
self.showVerification(for: sessionInfo)
|
|
}
|
|
case let .renameSession(sessionInfo):
|
|
self.showRenameSessionScreen(for: sessionInfo)
|
|
case let .logoutOfSession(sessionInfo):
|
|
self.handleLogoutOfSession(sessionInfo: sessionInfo)
|
|
case let .showSessionStateInfo(sessionInfo):
|
|
self.showInfoSheet(parameters: .init(userSessionInfo: sessionInfo, parentSize: self.toPresentable().view.bounds.size))
|
|
}
|
|
}
|
|
pushScreen(with: coordinator)
|
|
}
|
|
|
|
private func handleLogoutOfSession(sessionInfo: UserSessionInfo) {
|
|
if sessionInfo.isCurrent {
|
|
self.showLogoutConfirmationForCurrentSession()
|
|
} else {
|
|
if let authentication = self.parameters.session.homeserverWellknown.authentication {
|
|
if let logoutURL = authentication.getLogoutDeviceURL(fromID: sessionInfo.id) {
|
|
self.openDeviceLogoutRedirectURL(logoutURL)
|
|
} else {
|
|
self.showDeviceLogoutRedirectError()
|
|
}
|
|
} else {
|
|
self.showLogoutConfirmation(for: [sessionInfo])
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Shows the QR login screen.
|
|
private func openQRLoginScreen() {
|
|
let service = QRLoginService(client: parameters.session.matrixRestClient,
|
|
mode: .authenticated)
|
|
let parameters = AuthenticationQRLoginStartCoordinatorParameters(navigationRouter: navigationRouter,
|
|
qrLoginService: service)
|
|
let coordinator = AuthenticationQRLoginStartCoordinator(parameters: parameters)
|
|
coordinator.callback = { [weak self, weak coordinator] _ in
|
|
guard let self = self, let coordinator = coordinator else { return }
|
|
self.remove(childCoordinator: coordinator)
|
|
}
|
|
|
|
pushScreen(with: coordinator)
|
|
}
|
|
|
|
private func createUserSessionOverviewCoordinator(sessionInfo: UserSessionInfo) -> UserSessionOverviewCoordinator {
|
|
let parameters = UserSessionOverviewCoordinatorParameters(session: parameters.session,
|
|
sessionInfo: sessionInfo,
|
|
sessionsOverviewDataPublisher: allSessionsService.overviewDataPublisher)
|
|
return UserSessionOverviewCoordinator(parameters: parameters)
|
|
}
|
|
|
|
private func openOtherSessions(sessionInfos: [UserSessionInfo], filterBy filter: UserOtherSessionsFilter) {
|
|
let title = filter == .all ? VectorL10n.userSessionsOverviewOtherSessionsSectionTitle : VectorL10n.userOtherSessionSecurityRecommendationTitle
|
|
let coordinator = createOtherSessionsCoordinator(sessionInfos: sessionInfos,
|
|
filterBy: filter,
|
|
title: title)
|
|
coordinator.completion = { [weak self] result in
|
|
guard let self = self else { return }
|
|
switch result {
|
|
case let .openSessionOverview(sessionInfo: session):
|
|
self.openSessionOverview(sessionInfo: session)
|
|
case let .logoutFromUserSessions(sessionInfos: sessionInfos):
|
|
self.showLogoutConfirmation(for: sessionInfos)
|
|
case let .showSessionStateByFilter(filter):
|
|
self.showInfoSheet(parameters: .init(filter: filter, parentSize: self.toPresentable().view.bounds.size))
|
|
}
|
|
}
|
|
pushScreen(with: coordinator)
|
|
}
|
|
|
|
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,
|
|
showDeviceLogout: shouldShowDeviceLogout)
|
|
return UserOtherSessionsCoordinator(parameters: parameters)
|
|
}
|
|
|
|
private func openDeviceLogoutRedirectURL(_ url: URL) {
|
|
let alert = UIAlertController(title: VectorL10n.manageSessionRedirect, message: nil, preferredStyle: .alert)
|
|
alert.addAction(UIAlertAction(title: VectorL10n.ok, style: .default) { [weak self] _ in
|
|
guard let self else { return }
|
|
|
|
let service = SSOAccountService(accountURL: url)
|
|
let presenter = SSOAuthenticationPresenter(ssoAuthenticationService: service)
|
|
presenter.delegate = self
|
|
self.ssoAuthenticationPresenter = presenter
|
|
|
|
presenter.present(forIdentityProvider: nil, with: "", from: self.toPresentable(), animated: true)
|
|
})
|
|
alert.popoverPresentationController?.sourceView = toPresentable().view
|
|
navigationRouter.present(alert, animated: true)
|
|
}
|
|
|
|
private func showDeviceLogoutRedirectError() {
|
|
let alert = UIAlertController(title: VectorL10n.manageSessionRedirectError, message: nil, preferredStyle: .alert)
|
|
alert.popoverPresentationController?.sourceView = toPresentable().view
|
|
navigationRouter.present(alert, animated: true)
|
|
}
|
|
|
|
/// Shows a confirmation dialog to the user to sign out of a session.
|
|
private func showLogoutConfirmation(for sessionInfos: [UserSessionInfo]) {
|
|
// Use a UIAlertController as we don't have confirmationDialog in SwiftUI on iOS 14.
|
|
let alert = UIAlertController(title: VectorL10n.signOutConfirmationMessage, message: nil, preferredStyle: .actionSheet)
|
|
alert.addAction(UIAlertAction(title: VectorL10n.signOut, style: .destructive) { [weak self] _ in
|
|
self?.showLogoutAuthentication(for: sessionInfos)
|
|
})
|
|
alert.addAction(UIAlertAction(title: VectorL10n.cancel, style: .cancel))
|
|
alert.popoverPresentationController?.sourceView = toPresentable().view
|
|
|
|
navigationRouter.present(alert, animated: true)
|
|
}
|
|
|
|
private func showInfoSheet(parameters: InfoSheetCoordinatorParameters) {
|
|
let coordinator = InfoSheetCoordinator(parameters: parameters)
|
|
|
|
coordinator.toPresentable().presentationController?.delegate = self
|
|
coordinator.completion = { [weak self, weak coordinator] result in
|
|
guard let self = self, let coordinator = coordinator else { return }
|
|
|
|
switch result {
|
|
case .actionTriggered:
|
|
self.navigationRouter.dismissModule(animated: true, completion: nil)
|
|
self.remove(childCoordinator: coordinator)
|
|
}
|
|
}
|
|
|
|
add(childCoordinator: coordinator)
|
|
coordinator.start()
|
|
navigationRouter.present(coordinator, animated: true)
|
|
}
|
|
|
|
private func showLogoutConfirmationForCurrentSession() {
|
|
let flowPresenter = SignOutFlowPresenter(session: parameters.session, presentingViewController: toPresentable())
|
|
flowPresenter.delegate = self
|
|
|
|
flowPresenter.start()
|
|
signOutFlowPresenter = flowPresenter
|
|
}
|
|
|
|
/// Prompts the user to authenticate (if necessary) in order to log out of specific sessions.
|
|
private func showLogoutAuthentication(for sessionInfos: [UserSessionInfo]) {
|
|
startLoading()
|
|
|
|
let deviceIDs = sessionInfos.map(\.id)
|
|
let deleteDevicesRequest = AuthenticatedEndpointRequest.deleteDevices(deviceIDs)
|
|
let coordinatorParameters = ReauthenticationCoordinatorParameters(session: parameters.session,
|
|
presenter: navigationRouter.toPresentable(),
|
|
title: VectorL10n.deviceDetailsDeletePromptTitle,
|
|
message: VectorL10n.deviceDetailsDeletePromptMessage,
|
|
authenticatedEndpointRequest: deleteDevicesRequest)
|
|
let presenter = ReauthenticationCoordinatorBridgePresenter()
|
|
presenter.present(with: coordinatorParameters, animated: true) { [weak self] authenticationParameters in
|
|
self?.finalizeLogout(of: deviceIDs, with: authenticationParameters)
|
|
self?.reauthenticationPresenter = nil
|
|
} cancel: { [weak self] in
|
|
self?.stopLoading()
|
|
self?.reauthenticationPresenter = nil
|
|
} failure: { [weak self] error in
|
|
guard let self = self else { return }
|
|
self.stopLoading()
|
|
self.errorPresenter.presentError(from: self.toPresentable(), forError: error, animated: true, handler: { })
|
|
self.reauthenticationPresenter = nil
|
|
}
|
|
|
|
reauthenticationPresenter = presenter
|
|
}
|
|
|
|
/// Finishes the logout process by deleting the devices from the user's account.
|
|
/// - Parameters:
|
|
/// - deviceIDs: IDs for the sessions to be removed.
|
|
/// - authenticationParameters: The parameters from performing interactive authentication on the `devices` endpoint.
|
|
private func finalizeLogout(of deviceIDs: [String], with authenticationParameters: [String: Any]?) {
|
|
parameters.session.matrixRestClient.deleteDevices(deviceIDs,
|
|
authParameters: authenticationParameters ?? [:]) { [weak self] response in
|
|
guard let self = self else { return }
|
|
|
|
self.stopLoading()
|
|
|
|
guard response.isSuccess else {
|
|
MXLog.debug("[UserSessionsFlowCoordinator] Delete devices failed")
|
|
if let error = response.error {
|
|
self.errorPresenter.presentError(from: self.toPresentable(), forError: error, animated: true, handler: { })
|
|
} else {
|
|
self.errorPresenter.presentGenericError(from: self.toPresentable(), animated: true, handler: { })
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
self.popToSessionsOverview()
|
|
}
|
|
}
|
|
|
|
private func showRenameSessionScreen(for sessionInfo: UserSessionInfo) {
|
|
let parameters = UserSessionNameCoordinatorParameters(session: parameters.session, sessionInfo: sessionInfo)
|
|
let coordinator = UserSessionNameCoordinator(parameters: parameters)
|
|
|
|
coordinator.completion = { [weak self, weak coordinator] result in
|
|
guard let self = self, let coordinator = coordinator else { return }
|
|
switch result {
|
|
case .sessionNameUpdated:
|
|
self.allSessionsService.updateOverviewData { [weak self] _ in
|
|
self?.navigationRouter.dismissModule(animated: true, completion: nil)
|
|
self?.remove(childCoordinator: coordinator)
|
|
}
|
|
case .cancel:
|
|
self.navigationRouter.dismissModule(animated: true, completion: nil)
|
|
self.remove(childCoordinator: coordinator)
|
|
}
|
|
}
|
|
|
|
add(childCoordinator: coordinator)
|
|
let modalRouter = NavigationRouter(navigationController: RiotNavigationController())
|
|
modalRouter.setRootModule(coordinator)
|
|
coordinator.start()
|
|
modalRouter.toPresentable().presentationController?.delegate = self
|
|
navigationRouter.present(modalRouter, animated: true)
|
|
}
|
|
|
|
/// Shows a prompt to the user that it is not possible to verify
|
|
/// another session until the current session has been verified.
|
|
private func showCannotVerifyOtherSessionPrompt() {
|
|
let alert = UIAlertController(title: VectorL10n.securitySettingsCompleteSecurityAlertTitle,
|
|
message: VectorL10n.securitySettingsCompleteSecurityAlertMessage,
|
|
preferredStyle: .alert)
|
|
alert.addAction(UIAlertAction(title: VectorL10n.later, style: .cancel))
|
|
alert.addAction(UIAlertAction(title: VectorL10n.ok, style: .default) { [weak self] _ in
|
|
self?.showCompleteSecurity()
|
|
})
|
|
|
|
navigationRouter.present(alert, animated: true)
|
|
}
|
|
|
|
/// Shows the Complete Security modal for the user to verify their current session.
|
|
private func showCompleteSecurity() {
|
|
AppDelegate.theDelegate().presentCompleteSecurity(for: parameters.session)
|
|
}
|
|
|
|
/// Shows the verification screen for the specified session.
|
|
private func showVerification(for sessionInfo: UserSessionInfo) {
|
|
if sessionInfo.verificationState == .unknown {
|
|
showCannotVerifyOtherSessionPrompt()
|
|
return
|
|
}
|
|
|
|
let coordinator = UserVerificationCoordinator(presenter: toPresentable(),
|
|
session: parameters.session,
|
|
userId: parameters.session.myUserId,
|
|
userDisplayName: nil,
|
|
deviceId: sessionInfo.id)
|
|
coordinator.delegate = self
|
|
|
|
add(childCoordinator: coordinator)
|
|
coordinator.start()
|
|
}
|
|
|
|
/// Pops back to the root coordinator in the session management flow.
|
|
private func popToSessionsOverview() {
|
|
guard let sessionsOverviewCoordinator = sessionsOverviewCoordinator else { return }
|
|
if let coordinator = navigationRouter.modules.last as? UserSessionsOverviewCoordinator {
|
|
coordinator.refreshData()
|
|
} else {
|
|
navigationRouter.popToModule(sessionsOverviewCoordinator, animated: true)
|
|
}
|
|
}
|
|
|
|
/// Show an activity indicator whilst loading.
|
|
private func startLoading() {
|
|
loadingIndicator = indicatorPresenter.present(.loading(label: VectorL10n.loading, isInteractionBlocking: true))
|
|
}
|
|
|
|
/// Hide the currently displayed activity indicator.
|
|
private func stopLoading() {
|
|
loadingIndicator = nil
|
|
}
|
|
|
|
// MARK: - Public
|
|
|
|
func start() {
|
|
MXLog.debug("[UserSessionsFlowCoordinator] did start.")
|
|
|
|
let rootCoordinator = createUserSessionsOverviewCoordinator()
|
|
rootCoordinator.start()
|
|
|
|
add(childCoordinator: rootCoordinator)
|
|
|
|
if navigationRouter.modules.isEmpty == false {
|
|
navigationRouter.push(rootCoordinator, animated: true, popCompletion: { [weak self] in
|
|
self?.remove(childCoordinator: rootCoordinator)
|
|
self?.completion?()
|
|
})
|
|
} else {
|
|
navigationRouter.setRootModule(rootCoordinator) { [weak self] in
|
|
self?.remove(childCoordinator: rootCoordinator)
|
|
self?.completion?()
|
|
}
|
|
}
|
|
|
|
sessionsOverviewCoordinator = rootCoordinator
|
|
}
|
|
|
|
func toPresentable() -> UIViewController {
|
|
navigationRouter.toPresentable()
|
|
}
|
|
}
|
|
|
|
// MARK: SignOutFlowPresenter
|
|
|
|
extension UserSessionsFlowCoordinator: SignOutFlowPresenterDelegate {
|
|
func signOutFlowPresenterDidStartLoading(_ presenter: SignOutFlowPresenter) {
|
|
startLoading()
|
|
}
|
|
|
|
func signOutFlowPresenterDidStopLoading(_ presenter: SignOutFlowPresenter) {
|
|
stopLoading()
|
|
}
|
|
|
|
func signOutFlowPresenter(_ presenter: SignOutFlowPresenter, didFailWith error: Error) {
|
|
errorPresenter.presentError(from: toPresentable(), forError: error, animated: true, handler: { })
|
|
}
|
|
}
|
|
|
|
// MARK: CrossSigningSetupCoordinatorDelegate
|
|
|
|
extension UserSessionsFlowCoordinator: CrossSigningSetupCoordinatorDelegate {
|
|
func crossSigningSetupCoordinatorDidComplete(_ coordinator: CrossSigningSetupCoordinatorType) {
|
|
// The service is listening for changes so there's nothing to do here.
|
|
remove(childCoordinator: coordinator)
|
|
}
|
|
|
|
func crossSigningSetupCoordinatorDidCancel(_ coordinator: CrossSigningSetupCoordinatorType) {
|
|
remove(childCoordinator: coordinator)
|
|
}
|
|
|
|
func crossSigningSetupCoordinator(_ coordinator: CrossSigningSetupCoordinatorType, didFailWithError error: Error) {
|
|
remove(childCoordinator: coordinator)
|
|
errorPresenter.presentError(from: toPresentable(), forError: error, animated: true, handler: { })
|
|
}
|
|
}
|
|
|
|
// MARK: UserVerificationCoordinatorDelegate
|
|
|
|
extension UserSessionsFlowCoordinator: UserVerificationCoordinatorDelegate {
|
|
func userVerificationCoordinatorDidComplete(_ coordinator: UserVerificationCoordinatorType) {
|
|
// The service is listening for changes so there's nothing to do here.
|
|
remove(childCoordinator: coordinator)
|
|
}
|
|
}
|
|
|
|
// MARK: UIAdaptivePresentationControllerDelegate
|
|
|
|
extension UserSessionsFlowCoordinator: UIAdaptivePresentationControllerDelegate {
|
|
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
|
|
guard let coordinator = childCoordinators.last else {
|
|
return
|
|
}
|
|
|
|
remove(childCoordinator: coordinator)
|
|
}
|
|
}
|
|
|
|
// MARK: Private
|
|
|
|
private extension InfoSheetCoordinatorParameters {
|
|
init(userSessionInfo: UserSessionInfo, parentSize: CGSize) {
|
|
self.init(title: userSessionInfo.bottomSheetTitle,
|
|
description: userSessionInfo.bottomSheetDescription,
|
|
action: .init(text: VectorL10n.userSessionGotIt, action: { }),
|
|
parentSize: parentSize)
|
|
}
|
|
|
|
init(filter: UserOtherSessionsFilter, parentSize: CGSize) {
|
|
self.init(title: filter.bottomSheetTitle,
|
|
description: filter.bottomSheetDescription,
|
|
action: .init(text: VectorL10n.userSessionGotIt, action: { }),
|
|
parentSize: parentSize)
|
|
}
|
|
}
|
|
|
|
private extension UserSessionInfo {
|
|
var bottomSheetTitle: String {
|
|
switch verificationState {
|
|
case .unverified, .permanentlyUnverified:
|
|
return VectorL10n.userSessionUnverifiedSessionTitle
|
|
case .verified:
|
|
return VectorL10n.userSessionVerifiedSessionTitle
|
|
case .unknown:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
var bottomSheetDescription: String {
|
|
switch verificationState {
|
|
case .unverified:
|
|
return VectorL10n.userSessionUnverifiedSessionDescription
|
|
case .permanentlyUnverified:
|
|
return VectorL10n.userSessionPermanentlyUnverifiedSessionDescription
|
|
case .verified:
|
|
return VectorL10n.userSessionVerifiedSessionDescription
|
|
case .unknown:
|
|
return ""
|
|
}
|
|
}
|
|
}
|
|
|
|
private extension UserOtherSessionsFilter {
|
|
var bottomSheetTitle: String {
|
|
switch self {
|
|
case .unverified:
|
|
return VectorL10n.userSessionUnverifiedSessionTitle
|
|
case .verified:
|
|
return VectorL10n.userSessionVerifiedSessionTitle
|
|
case .inactive:
|
|
return VectorL10n.userSessionInactiveSessionTitle
|
|
case .all:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
var bottomSheetDescription: String {
|
|
switch self {
|
|
case .unverified:
|
|
return VectorL10n.userSessionUnverifiedSessionDescription
|
|
case .verified:
|
|
return VectorL10n.userSessionVerifiedSessionDescription
|
|
case .inactive:
|
|
return VectorL10n.userSessionInactiveSessionDescription
|
|
case .all:
|
|
return ""
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: ASWebAuthenticationPresentationContextProviding
|
|
|
|
extension UserSessionsFlowCoordinator: SSOAuthenticationPresenterDelegate {
|
|
func ssoAuthenticationPresenterDidCancel(_ presenter: SSOAuthenticationPresenter) {
|
|
ssoAuthenticationPresenter = nil
|
|
MXLog.info("OIDC account management complete.")
|
|
popToSessionsOverview()
|
|
}
|
|
|
|
func ssoAuthenticationPresenter(_ presenter: SSOAuthenticationPresenter, authenticationDidFailWithError error: Error) {
|
|
ssoAuthenticationPresenter = nil
|
|
MXLog.error("OIDC account management failed.")
|
|
}
|
|
|
|
func ssoAuthenticationPresenter(_ presenter: SSOAuthenticationPresenter,
|
|
authenticationSucceededWithToken token: String,
|
|
usingIdentityProvider identityProvider: SSOIdentityProvider?) {
|
|
ssoAuthenticationPresenter = nil
|
|
MXLog.warning("Unexpected callback after OIDC account management.")
|
|
}
|
|
}
|