82 lines
2.3 KiB
Swift
82 lines
2.3 KiB
Swift
//
|
|
// Swiftfin is subject to the terms of the Mozilla Public
|
|
// License, v2.0. If a copy of the MPL was not distributed with this
|
|
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
|
//
|
|
// Copyright (c) 2024 Jellyfin & Jellyfin Contributors
|
|
//
|
|
|
|
import Combine
|
|
import Foundation
|
|
import KeychainSwift
|
|
|
|
class UserLocalSecurityViewModel: ViewModel, Eventful {
|
|
|
|
enum Event: Hashable {
|
|
case error(JellyfinAPIError)
|
|
case promptForOldDeviceAuth
|
|
case promptForOldPin
|
|
case promptForNewDeviceAuth
|
|
case promptForNewPin
|
|
}
|
|
|
|
var events: AnyPublisher<Event, Never> {
|
|
eventSubject
|
|
.receive(on: RunLoop.main)
|
|
.eraseToAnyPublisher()
|
|
}
|
|
|
|
private var eventSubject: PassthroughSubject<Event, Never> = .init()
|
|
|
|
// Will throw and send event if needing to prompt for old auth.
|
|
func checkForOldPolicy() throws {
|
|
|
|
let oldPolicy = userSession.user.accessPolicy
|
|
|
|
switch oldPolicy {
|
|
case .requireDeviceAuthentication:
|
|
eventSubject.send(.promptForOldDeviceAuth)
|
|
|
|
throw JellyfinAPIError("Prompt for old device auth")
|
|
case .requirePin:
|
|
eventSubject.send(.promptForOldPin)
|
|
|
|
throw JellyfinAPIError("Prompt for old pin")
|
|
case .none: ()
|
|
}
|
|
}
|
|
|
|
// Will throw and send event if needing to prompt for new auth.
|
|
func checkFor(newPolicy: UserAccessPolicy) throws {
|
|
switch newPolicy {
|
|
case .requireDeviceAuthentication:
|
|
eventSubject.send(.promptForNewDeviceAuth)
|
|
case .requirePin:
|
|
eventSubject.send(.promptForNewPin)
|
|
case .none: ()
|
|
}
|
|
}
|
|
|
|
func check(oldPin: String) throws {
|
|
|
|
if let storedPin = keychain.get("\(userSession.user.id)-pin") {
|
|
if oldPin != storedPin {
|
|
eventSubject.send(.error(.init("Incorrect pin for \(userSession.user.username)")))
|
|
throw JellyfinAPIError("invalid pin")
|
|
}
|
|
}
|
|
}
|
|
|
|
func set(newPolicy: UserAccessPolicy, newPin: String, newPinHint: String) {
|
|
|
|
if newPolicy == .requirePin {
|
|
keychain.set(newPin, forKey: "\(userSession.user.id)-pin")
|
|
} else {
|
|
keychain.delete(StoredValues[.Temp.userLocalPin])
|
|
}
|
|
|
|
userSession.user.accessPolicy = newPolicy
|
|
userSession.user.pinHint = newPinHint
|
|
}
|
|
}
|