Multi session logut

This commit is contained in:
Aleksandrs Proskurins 2022-10-27 10:04:42 +03:00
parent 1a6486a41c
commit d2cde943de
6 changed files with 72 additions and 8 deletions

View file

@ -78,7 +78,7 @@ final class CrossSigningService: NSObject {
func setupCrossSigningRequest() -> AuthenticatedEndpointRequest {
let path = "\(kMXAPIPrefixPathUnstable)/keys/device_signing/upload"
return AuthenticatedEndpointRequest(path: path, httpMethod: "POST")
return AuthenticatedEndpointRequest(path: path, httpMethod: "POST", params: [:])
}
/// Setup cross-signing without authentication. Useful when a grace period is enabled.

View file

@ -47,7 +47,7 @@ enum DeactivateAccountServiceError: Error {
@objcMembers class DeactivateAccountService: NSObject {
private let session: MXSession
private let uiaService: UserInteractiveAuthenticationService
private let request = AuthenticatedEndpointRequest(path: "\(kMXAPIPrefixPathR0)/account/deactivate", httpMethod: "POST")
private let request = AuthenticatedEndpointRequest(path: "\(kMXAPIPrefixPathR0)/account/deactivate", httpMethod: "POST", params: [:])
/// The authentication session's ID if interactive authentication has begun, otherwise `nil`.
private var sessionID: String?

View file

@ -673,7 +673,7 @@ enum {
NSString *title = [VectorL10n deviceDetailsDeletePromptTitle];
NSString *message = [VectorL10n deviceDetailsDeletePromptMessage];
AuthenticatedEndpointRequest *deleteDeviceRequest = [[AuthenticatedEndpointRequest alloc] initWithPath:[NSString stringWithFormat:@"%@/devices/%@", kMXAPIPrefixPathR0, [MXTools encodeURIComponent:device.deviceId]] httpMethod:@"DELETE"];
AuthenticatedEndpointRequest *deleteDeviceRequest = [[AuthenticatedEndpointRequest alloc] initWithPath:[NSString stringWithFormat:@"%@/devices/%@", kMXAPIPrefixPathR0, [MXTools encodeURIComponent:device.deviceId]] httpMethod:@"DELETE" params:[[NSDictionary alloc] init]];
ReauthenticationCoordinatorParameters *coordinatorParameters = [[ReauthenticationCoordinatorParameters alloc] initWithSession:self.mainSession presenter:self title:title message:message authenticatedEndpointRequest:deleteDeviceRequest];

View file

@ -22,10 +22,11 @@ class AuthenticatedEndpointRequest: NSObject {
let path: String
let httpMethod: String
init(path: String, httpMethod: String) {
let params: [String: Any]
init(path: String, httpMethod: String, params: [String: Any]) {
self.path = path
self.httpMethod = httpMethod
self.params = params
super.init()
}
}
@ -37,6 +38,15 @@ extension AuthenticatedEndpointRequest {
/// - Parameter deviceID: The device ID that is to be deleted.
static func deleteDevice(_ deviceID: String) -> AuthenticatedEndpointRequest {
let path = String(format: "%@/devices/%@", kMXAPIPrefixPathR0, MXTools.encodeURIComponent(deviceID))
return AuthenticatedEndpointRequest(path: path, httpMethod: "DELETE")
return AuthenticatedEndpointRequest(path: path, httpMethod: "DELETE", params: [:])
}
}
extension AuthenticatedEndpointRequest {
/// Create an authenticated request on `_matrix/client/r0/delete_devices`.
/// - Parameter deviceID: The device ID that is to be deleted.
static func deleteDevices(_ deviceIDs: [String]) -> AuthenticatedEndpointRequest {
let path = String(format: "%@/delete_devices", kMXAPIPrefixPathR0)
return AuthenticatedEndpointRequest(path: path, httpMethod: "POST", params: ["devices": deviceIDs])
}
}

View file

@ -131,7 +131,7 @@ final class UserInteractiveAuthenticationService: NSObject {
success: @escaping (MXAuthenticationSession?) -> Void,
failure: @escaping (Error) -> Void) -> MXHTTPOperation {
// Get the authentication flow required for this API
return self.session.matrixRestClient.authSessionForRequest(withMethod: request.httpMethod, path: request.path, parameters: [:], success: { [weak self] (authenticationSession) in
return self.session.matrixRestClient.authSessionForRequest(withMethod: request.httpMethod, path: request.path, parameters: request.params, success: { [weak self] (authenticationSession) in
guard let self = self else {
return
}

View file

@ -184,7 +184,7 @@ final class UserSessionsFlowCoordinator: Coordinator, Presentable {
if sessionInfos.count == 1, let onlySession = sessionInfos.first {
self?.showLogoutAuthentication(for: onlySession)
} else {
// todo:
self?.showLogoutAuthenticationAndLogoutFromSessions(sessionInfos: sessionInfos)
}
})
alert.addAction(UIAlertAction(title: VectorL10n.cancel, style: .cancel))
@ -228,6 +228,60 @@ final class UserSessionsFlowCoordinator: Coordinator, Presentable {
reauthenticationPresenter = presenter
}
// TODO: move to into a command
private func showLogoutAuthenticationAndLogoutFromSessions(sessionInfos: [UserSessionInfo]) {
startLoading()
let deviceIds = sessionInfos.map { $0.id }
let deleteDeviceRequest = AuthenticatedEndpointRequest.deleteDevices(deviceIds)
let coordinatorParameters = ReauthenticationCoordinatorParameters(session: parameters.session,
presenter: navigationRouter.toPresentable(),
title: VectorL10n.deviceDetailsDeletePromptTitle,
message: VectorL10n.deviceDetailsDeletePromptMessage,
authenticatedEndpointRequest: deleteDeviceRequest)
let presenter = ReauthenticationCoordinatorBridgePresenter()
presenter.present(with: coordinatorParameters, animated: true) { [weak self] authenticationParameters in
self?.finalizeLogout2(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
}
private func finalizeLogout2(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()
}
}
/// Finishes the logout process by deleting the device from the user's account.
/// - Parameters:
/// - sessionInfo: The `UserSessionInfo` for the session to be removed.