Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WYqycDFsynHH9VnnK7LNSf
87 lines
2.6 KiB
Swift
87 lines
2.6 KiB
Swift
//
|
|
// UnlockViewModel.swift
|
|
// MyPass
|
|
//
|
|
|
|
import Foundation
|
|
import Combine
|
|
import MyPassCore
|
|
|
|
@MainActor
|
|
final class UnlockViewModel: ObservableObject {
|
|
@Published var password: String = ""
|
|
@Published var errorMessage: String?
|
|
@Published var isUnlocking: Bool = false
|
|
@Published var showFilePicker: Bool = false
|
|
|
|
private let session: VaultSession
|
|
private let bookmarkService: FileBookmarkService
|
|
private let keychainStore: KeychainStore
|
|
private let biometricService: BiometricAuthService
|
|
|
|
private let keychainAccount = "masterPassword"
|
|
|
|
init(
|
|
session: VaultSession,
|
|
bookmarkService: FileBookmarkService = .init(),
|
|
keychainStore: KeychainStore = .init(accessGroup: "org.antiloop222.mypass"),
|
|
biometricService: BiometricAuthService = .init()
|
|
) {
|
|
self.session = session
|
|
self.bookmarkService = bookmarkService
|
|
self.keychainStore = keychainStore
|
|
self.biometricService = biometricService
|
|
}
|
|
|
|
var canUseBiometrics: Bool {
|
|
biometricService.isAvailable && keychainStore.exists(for: keychainAccount)
|
|
}
|
|
|
|
var hasVault: Bool { bookmarkService.hasBookmark }
|
|
|
|
func unlockWithBiometrics() {
|
|
Task {
|
|
isUnlocking = true
|
|
errorMessage = nil
|
|
do {
|
|
try await biometricService.authenticate(reason: "Unlock MyPass")
|
|
let storedPassword = try keychainStore.load(for: keychainAccount)
|
|
let url = try bookmarkService.resolveURL()
|
|
defer { bookmarkService.stopAccess(url: url) }
|
|
try session.unlock(url: url, password: storedPassword)
|
|
} catch {
|
|
errorMessage = error.localizedDescription
|
|
}
|
|
isUnlocking = false
|
|
}
|
|
}
|
|
|
|
func unlockWithPassword() {
|
|
Task {
|
|
isUnlocking = true
|
|
errorMessage = nil
|
|
do {
|
|
let url = try bookmarkService.resolveURL()
|
|
defer { bookmarkService.stopAccess(url: url) }
|
|
try session.unlock(url: url, password: password)
|
|
try keychainStore.save(password: password, for: keychainAccount)
|
|
password = ""
|
|
} catch KDBXError.invalidPassword {
|
|
errorMessage = "Incorrect password."
|
|
} catch {
|
|
errorMessage = error.localizedDescription
|
|
}
|
|
isUnlocking = false
|
|
}
|
|
}
|
|
|
|
func openFile(url: URL) {
|
|
do {
|
|
try bookmarkService.save(url: url)
|
|
unlockWithPassword()
|
|
} catch {
|
|
errorMessage = error.localizedDescription
|
|
}
|
|
}
|
|
}
|