diff --git a/Shared/Coordinators/UserSignInCoordinator.swift b/Shared/Coordinators/UserSignInCoordinator.swift index 52264128..adf88edc 100644 --- a/Shared/Coordinators/UserSignInCoordinator.swift +++ b/Shared/Coordinators/UserSignInCoordinator.swift @@ -15,7 +15,7 @@ final class UserSignInCoordinator: NavigationCoordinatable { struct SecurityParameters { let pinHint: Binding - let signInPolicy: Binding + let accessPolicy: Binding } let stack = NavigationStack(initial: \UserSignInCoordinator.start) @@ -48,7 +48,7 @@ final class UserSignInCoordinator: NavigationCoordinatable { NavigationViewCoordinator { UserSignInView.SecurityView( pinHint: parameters.pinHint, - signInPolicy: parameters.signInPolicy + accessPolicy: parameters.accessPolicy ) } } diff --git a/Shared/SwiftfinStore/StoredValue/StoredValues+Temp.swift b/Shared/SwiftfinStore/StoredValue/StoredValues+Temp.swift index 41cbf039..ef20d0c2 100644 --- a/Shared/SwiftfinStore/StoredValue/StoredValues+Temp.swift +++ b/Shared/SwiftfinStore/StoredValue/StoredValues+Temp.swift @@ -42,7 +42,7 @@ extension StoredValues.Keys { enum Temp { - static let userSignInPolicy: Key = TempKey( + static let userAccessPolicy: Key = TempKey( "userSignInPolicy", ownerID: "temporary", domain: "userSignInPolicy", diff --git a/Shared/SwiftfinStore/SwiftinStore+UserState.swift b/Shared/SwiftfinStore/SwiftinStore+UserState.swift index c9e0c2c6..034225cc 100644 --- a/Shared/SwiftfinStore/SwiftinStore+UserState.swift +++ b/Shared/SwiftfinStore/SwiftinStore+UserState.swift @@ -72,8 +72,7 @@ extension UserState { } } - // TODO: rename to accessPolicy and fix all uses - var signInPolicy: UserAccessPolicy { + var accessPolicy: UserAccessPolicy { get { StoredValues[.User.accessPolicy(id: id)] } diff --git a/Shared/ViewModels/SelectUserViewModel.swift b/Shared/ViewModels/SelectUserViewModel.swift index 21bbb38c..e46adfb4 100644 --- a/Shared/ViewModels/SelectUserViewModel.swift +++ b/Shared/ViewModels/SelectUserViewModel.swift @@ -77,7 +77,7 @@ class SelectUserViewModel: ViewModel, Eventful, Stateful { } case let .signIn(user, pin): - if user.signInPolicy == .requirePin, let storedPin = keychain.get("\(user.id)-pin") { + if user.accessPolicy == .requirePin, let storedPin = keychain.get("\(user.id)-pin") { if pin != storedPin { eventSubject.send(.error(.init("Incorrect pin for \(user.username)"))) diff --git a/Shared/ViewModels/UserLocalSecurityViewModel.swift b/Shared/ViewModels/UserLocalSecurityViewModel.swift index 53ce6b87..5de3f238 100644 --- a/Shared/ViewModels/UserLocalSecurityViewModel.swift +++ b/Shared/ViewModels/UserLocalSecurityViewModel.swift @@ -31,7 +31,7 @@ class UserLocalSecurityViewModel: ViewModel, Eventful { // Will throw and send event if needing to prompt for old auth. func checkForOldPolicy() throws { - let oldPolicy = userSession.user.signInPolicy + let oldPolicy = userSession.user.accessPolicy switch oldPolicy { case .requireDeviceAuthentication: @@ -75,7 +75,7 @@ class UserLocalSecurityViewModel: ViewModel, Eventful { keychain.delete(StoredValues[.Temp.userLocalPin]) } - userSession.user.signInPolicy = newPolicy + userSession.user.accessPolicy = newPolicy userSession.user.pinHint = newPinHint } } diff --git a/Shared/ViewModels/UserSignInViewModel.swift b/Shared/ViewModels/UserSignInViewModel.swift index f9d74278..63138fba 100644 --- a/Shared/ViewModels/UserSignInViewModel.swift +++ b/Shared/ViewModels/UserSignInViewModel.swift @@ -92,7 +92,7 @@ final class UserSignInViewModel: ViewModel, Eventful, Stateful { guard let self else { return } Task { - await self.send(.signInQuickConnect(secret: secret, policy: StoredValues[.Temp.userSignInPolicy])) + await self.send(.signInQuickConnect(secret: secret, policy: StoredValues[.Temp.userAccessPolicy])) } } } @@ -236,7 +236,7 @@ final class UserSignInViewModel: ViewModel, Eventful, Stateful { } StoredValues[.Temp.userData] = userData - StoredValues[.Temp.userSignInPolicy] = policy + StoredValues[.Temp.userAccessPolicy] = policy let newState = UserState( id: id, @@ -263,7 +263,7 @@ final class UserSignInViewModel: ViewModel, Eventful, Stateful { } StoredValues[.Temp.userData] = userData - StoredValues[.Temp.userSignInPolicy] = policy + StoredValues[.Temp.userAccessPolicy] = policy let newState = UserState( id: id, @@ -304,13 +304,13 @@ final class UserSignInViewModel: ViewModel, Eventful, Stateful { } user.data = StoredValues[.Temp.userData] - user.signInPolicy = StoredValues[.Temp.userSignInPolicy] + user.accessPolicy = StoredValues[.Temp.userAccessPolicy] keychain.set(StoredValues[.Temp.userLocalPin], forKey: "\(user.id)-pin") user.pinHint = StoredValues[.Temp.userLocalPinHint] // TODO: remove when implemented periodic cleanup elsewhere - StoredValues[.Temp.userSignInPolicy] = .none + StoredValues[.Temp.userAccessPolicy] = .none StoredValues[.Temp.userLocalPin] = "" StoredValues[.Temp.userLocalPinHint] = "" } diff --git a/Swiftfin/Views/SelectUserView/SelectUserView.swift b/Swiftfin/Views/SelectUserView/SelectUserView.swift index af251b51..f0bebdac 100644 --- a/Swiftfin/Views/SelectUserView/SelectUserView.swift +++ b/Swiftfin/Views/SelectUserView/SelectUserView.swift @@ -139,7 +139,7 @@ struct SelectUserView: View { Task { @MainActor in selectedUsers.insert(user) - switch user.signInPolicy { + switch user.accessPolicy { case .requireDeviceAuthentication: try await performDeviceAuthentication(reason: "User \(user.username) requires device authentication") case .requirePin: diff --git a/Swiftfin/Views/SettingsView/UserProfileSettingsView/UserLocalSecurityView.swift b/Swiftfin/Views/SettingsView/UserProfileSettingsView/UserLocalSecurityView.swift index 835d9019..db4f0c35 100644 --- a/Swiftfin/Views/SettingsView/UserProfileSettingsView/UserLocalSecurityView.swift +++ b/Swiftfin/Views/SettingsView/UserProfileSettingsView/UserLocalSecurityView.swift @@ -158,7 +158,7 @@ struct UserLocalSecurityView: View { .navigationBarTitleDisplayMode(.inline) .onFirstAppear { pinHint = viewModel.userSession.user.pinHint - signInPolicy = viewModel.userSession.user.signInPolicy + signInPolicy = viewModel.userSession.user.accessPolicy } .onReceive(viewModel.events) { event in switch event { @@ -210,7 +210,7 @@ struct UserLocalSecurityView: View { checkOldPolicy() } label: { Group { - if signInPolicy == .requirePin, signInPolicy == viewModel.userSession.user.signInPolicy { + if signInPolicy == .requirePin, signInPolicy == viewModel.userSession.user.accessPolicy { Text("Change Pin") } else { Text("Save") diff --git a/Swiftfin/Views/UserSignInView/Components/UserSignInSecurityView.swift b/Swiftfin/Views/UserSignInView/Components/UserSignInSecurityView.swift index 9f43e1b4..df1c7fd5 100644 --- a/Swiftfin/Views/UserSignInView/Components/UserSignInSecurityView.swift +++ b/Swiftfin/Views/UserSignInView/Components/UserSignInSecurityView.swift @@ -20,7 +20,7 @@ extension UserSignInView { @Binding private var pinHint: String @Binding - private var signInPolicy: UserAccessPolicy + private var accessPolicy: UserAccessPolicy @State private var listSize: CGSize = .zero @@ -31,12 +31,12 @@ extension UserSignInView { init( pinHint: Binding, - signInPolicy: Binding + accessPolicy: Binding ) { self._pinHint = pinHint - self._signInPolicy = signInPolicy + self._accessPolicy = accessPolicy self._updatePinHint = State(initialValue: pinHint.wrappedValue) - self._updateSignInPolicy = State(initialValue: signInPolicy.wrappedValue) + self._updateSignInPolicy = State(initialValue: accessPolicy.wrappedValue) } var body: some View { @@ -82,7 +82,7 @@ extension UserSignInView { } } - if signInPolicy == .requirePin { + if accessPolicy == .requirePin { Section { TextField("Hint", text: $updatePinHint) } header: { @@ -92,7 +92,7 @@ extension UserSignInView { } } } - .animation(.linear, value: signInPolicy) + .animation(.linear, value: accessPolicy) .navigationTitle("Security") .navigationBarTitleDisplayMode(.inline) .navigationBarCloseButton { @@ -107,7 +107,7 @@ extension UserSignInView { pinHint = newValue } .onChange(of: updateSignInPolicy) { newValue in - signInPolicy = newValue + accessPolicy = newValue } .trackingSize($listSize) } diff --git a/Swiftfin/Views/UserSignInView/UserSignInView.swift b/Swiftfin/Views/UserSignInView/UserSignInView.swift index a5c31edd..d5d964be 100644 --- a/Swiftfin/Views/UserSignInView/UserSignInView.swift +++ b/Swiftfin/Views/UserSignInView/UserSignInView.swift @@ -47,7 +47,7 @@ struct UserSignInView: View { @State private var pinHint: String = "" @State - private var signInPolicy: UserAccessPolicy = .none + private var accessPolicy: UserAccessPolicy = .none @State private var username: String = "" @@ -58,11 +58,32 @@ struct UserSignInView: View { self._viewModel = StateObject(wrappedValue: UserSignInViewModel(server: server)) } + private func handleSignIn(_ event: UserSignInViewModel.Event) { + switch event { + case let .duplicateUser(duplicateUser): + UIDevice.impact(.medium) + + self.duplicateUser = duplicateUser + isPresentingDuplicateUser = true + case let .error(eventError): + UIDevice.feedback(.error) + + error = eventError + isPresentingError = true + case let .signedIn(user): + UIDevice.feedback(.success) + + Defaults[.lastSignedInUserID] = user.id + UserSession.current.reset() + Notifications[.didSignIn].post() + } + } + // TODO: don't have multiple ways to handle device authentication vs required pin private func openQuickConnect(needsPin: Bool = true) { Task { - switch signInPolicy { + switch accessPolicy { case .none: () case .requireDeviceAuthentication: try await performDeviceAuthentication( @@ -84,27 +105,27 @@ struct UserSignInView: View { private func signInUserPassword(needsPin: Bool = true) { Task { - switch signInPolicy { + switch accessPolicy { case .none: () case .requireDeviceAuthentication: try await performDeviceAuthentication(reason: "Require device authentication to sign in to \(username) on this device") case .requirePin: if needsPin { onPinCompletion = { - viewModel.send(.signIn(username: username, password: password, policy: signInPolicy)) + viewModel.send(.signIn(username: username, password: password, policy: accessPolicy)) } isPresentingLocalPin = true return } } - viewModel.send(.signIn(username: username, password: password, policy: signInPolicy)) + viewModel.send(.signIn(username: username, password: password, policy: accessPolicy)) } } private func signInUplicate(user: UserState, needsPin: Bool = true, replace: Bool) { Task { - switch user.signInPolicy { + switch user.accessPolicy { case .none: () case .requireDeviceAuthentication: try await performDeviceAuthentication(reason: "User \(user.username) requires device authentication") @@ -185,7 +206,7 @@ struct UserSignInView: View { } header: { Text(L10n.signInToServer(viewModel.server.name)) } footer: { - switch signInPolicy { + switch accessPolicy { case .requireDeviceAuthentication: HStack { Image(systemName: "exclamationmark.circle.fill") @@ -298,30 +319,13 @@ struct UserSignInView: View { .onChange(of: pinHint) { newValue in StoredValues[.Temp.userLocalPinHint] = newValue } - .onChange(of: signInPolicy) { newValue in + .onChange(of: accessPolicy) { newValue in // necessary for Quick Connect sign in, but could // just use for general sign in - StoredValues[.Temp.userSignInPolicy] = newValue + StoredValues[.Temp.userAccessPolicy] = newValue } .onReceive(viewModel.events) { event in - switch event { - case let .duplicateUser(duplicateUser): - UIDevice.impact(.medium) - - self.duplicateUser = duplicateUser - isPresentingDuplicateUser = true - case let .error(eventError): - UIDevice.feedback(.error) - - error = eventError - isPresentingError = true - case let .signedIn(user): - UIDevice.feedback(.success) - - Defaults[.lastSignedInUserID] = user.id - UserSession.current.reset() - Notifications[.didSignIn].post() - } + handleSignIn(event) } .onFirstAppear { focusedTextField = 0 @@ -335,7 +339,7 @@ struct UserSignInView: View { Button("Security", systemImage: "gearshape.fill") { let parameters = UserSignInCoordinator.SecurityParameters( pinHint: $pinHint, - signInPolicy: $signInPolicy + accessPolicy: $accessPolicy ) router.route(to: \.security, parameters) }