mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
Ensure that the current user is the device owner before linking a new device. (#5773)
This commit is contained in:
@@ -12,15 +12,19 @@ import SwiftUI
|
||||
typealias LinkNewDeviceScreenViewModelType = StateStoreViewModelV2<LinkNewDeviceScreenViewState, LinkNewDeviceScreenViewAction>
|
||||
|
||||
class LinkNewDeviceScreenViewModel: LinkNewDeviceScreenViewModelType, LinkNewDeviceScreenViewModelProtocol {
|
||||
private enum Device { case mobileDevice, desktopComputer }
|
||||
|
||||
private let clientProxy: ClientProxyProtocol
|
||||
private let appLockService: AppLockServiceProtocol
|
||||
|
||||
private let actionsSubject: PassthroughSubject<LinkNewDeviceScreenViewModelAction, Never> = .init()
|
||||
var actionsPublisher: AnyPublisher<LinkNewDeviceScreenViewModelAction, Never> {
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
init(clientProxy: ClientProxyProtocol, initialState: LinkNewDeviceScreenViewState? = nil) {
|
||||
init(clientProxy: ClientProxyProtocol, appLockService: AppLockServiceProtocol, initialState: LinkNewDeviceScreenViewState? = nil) {
|
||||
self.clientProxy = clientProxy
|
||||
self.appLockService = appLockService
|
||||
|
||||
if let initialState {
|
||||
super.init(initialViewState: initialState)
|
||||
@@ -41,9 +45,9 @@ class LinkNewDeviceScreenViewModel: LinkNewDeviceScreenViewModelType, LinkNewDev
|
||||
|
||||
switch viewAction {
|
||||
case .linkMobileDevice:
|
||||
Task { await linkMobileDevice() }
|
||||
Task { await verifyAndLink(.mobileDevice) }
|
||||
case .linkDesktopComputer:
|
||||
actionsSubject.send(.linkDesktopComputer)
|
||||
Task { await verifyAndLink(.desktopComputer) }
|
||||
case .errorAction(let action):
|
||||
handleErrorAction(action)
|
||||
case .dismiss:
|
||||
@@ -55,14 +59,41 @@ class LinkNewDeviceScreenViewModel: LinkNewDeviceScreenViewModelType, LinkNewDev
|
||||
|
||||
private func checkQRCodeLoginSupport() async {
|
||||
if await clientProxy.isLoginWithQRCodeSupported {
|
||||
state.mode = .readyToLink(isGeneratingCode: false)
|
||||
state.mode = .readyToLink(.idle)
|
||||
} else {
|
||||
state.mode = .error(.notSupported)
|
||||
}
|
||||
}
|
||||
|
||||
private func verifyAndLink(_ device: Device) async {
|
||||
state.mode = .readyToLink(.verifyingDeviceOwner)
|
||||
|
||||
switch await appLockService.verifyDeviceOwner(reason: L10n.screenLinkNewDeviceAuthenticationReasonIos) {
|
||||
case .verified, .unavailable:
|
||||
break
|
||||
case .appLockPINRequired:
|
||||
// Follow-up PR: present the App Lock PIN screen to verify the device owner.
|
||||
return
|
||||
case .cancelled, .unverified:
|
||||
state.mode = .readyToLink(.idle)
|
||||
return
|
||||
case .error:
|
||||
// TODO: Failure UX is pending product confirmation; using the generic error state for now.
|
||||
state.mode = .error(.unknown)
|
||||
return
|
||||
}
|
||||
|
||||
switch device {
|
||||
case .mobileDevice:
|
||||
await linkMobileDevice() // Automatically sets the state.
|
||||
case .desktopComputer:
|
||||
actionsSubject.send(.linkDesktopComputer)
|
||||
state.mode = .readyToLink(.idle)
|
||||
}
|
||||
}
|
||||
|
||||
private func linkMobileDevice() async {
|
||||
state.mode = .readyToLink(isGeneratingCode: true)
|
||||
state.mode = .readyToLink(.generatingCode)
|
||||
|
||||
let linkNewDeviceService = clientProxy.linkNewDeviceService()
|
||||
|
||||
@@ -77,7 +108,7 @@ class LinkNewDeviceScreenViewModel: LinkNewDeviceScreenViewModelType, LinkNewDev
|
||||
}
|
||||
|
||||
actionsSubject.send(.linkMobileDevice(progressPublisher))
|
||||
state.mode = .readyToLink(isGeneratingCode: false)
|
||||
state.mode = .readyToLink(.idle)
|
||||
} catch {
|
||||
// This is hard to share a mapping from the QRCodeLoginError with the
|
||||
// QRCodeLoginScreen given that some of those are scan errors…
|
||||
@@ -89,7 +120,7 @@ class LinkNewDeviceScreenViewModel: LinkNewDeviceScreenViewModelType, LinkNewDev
|
||||
switch action {
|
||||
case .startOver:
|
||||
// Reset to ready state to allow trying again.
|
||||
state.mode = .readyToLink(isGeneratingCode: false)
|
||||
state.mode = .readyToLink(.idle)
|
||||
case .openSettings, .signInManually:
|
||||
MXLog.error("Unexpected error action: \(action)")
|
||||
actionsSubject.send(.dismiss)
|
||||
|
||||
Reference in New Issue
Block a user