Support selects a credential identity from the QuickType bar
This commit is contained in:
parent
d4669bbfcb
commit
29d74c48e5
6 changed files with 125 additions and 30 deletions
70
passAutoFillExtension/Services/CredentialProvider.swift
Normal file
70
passAutoFillExtension/Services/CredentialProvider.swift
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
//
|
||||
// CredentialProvider.swift
|
||||
// passAutoFillExtension
|
||||
//
|
||||
// Created by Sun, Mingshen on 1/2/21.
|
||||
// Copyright © 2021 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import AuthenticationServices
|
||||
import passKit
|
||||
|
||||
class CredentialProvider {
|
||||
var identifier: ASCredentialServiceIdentifier?
|
||||
weak var extensionContext: ASCredentialProviderExtensionContext?
|
||||
weak var viewController: UIViewController?
|
||||
|
||||
init(viewController: UIViewController, extensionContext: ASCredentialProviderExtensionContext) {
|
||||
self.viewController = viewController
|
||||
self.extensionContext = extensionContext
|
||||
}
|
||||
|
||||
func credentials(for identity: ASPasswordCredentialIdentity) {
|
||||
guard let recordIdentifier = identity.recordIdentifier else {
|
||||
return
|
||||
}
|
||||
guard let pwCredentials = provideCredentials(in: viewController, with: recordIdentifier) else {
|
||||
return
|
||||
}
|
||||
|
||||
extensionContext?.completeRequest(withSelectedCredential: pwCredentials)
|
||||
}
|
||||
|
||||
func persistAndProvideCredentials(with passwordPath: String) {
|
||||
guard let pwCredentials = provideCredentials(in: viewController, with: passwordPath) else {
|
||||
return
|
||||
}
|
||||
guard let credentialIdentity = provideCredentialIdentity(for: identifier, user: pwCredentials.user, recordIdentifier: passwordPath) else {
|
||||
return
|
||||
}
|
||||
|
||||
let store = ASCredentialIdentityStore.shared
|
||||
store.getState { state in
|
||||
if state.isEnabled {
|
||||
ASCredentialIdentityStore.shared.saveCredentialIdentities([credentialIdentity])
|
||||
}
|
||||
}
|
||||
extensionContext?.completeRequest(withSelectedCredential: pwCredentials)
|
||||
}
|
||||
}
|
||||
|
||||
private func provideCredentialIdentity(for identifier: ASCredentialServiceIdentifier?, user: String, recordIdentifier: String?) -> ASPasswordCredentialIdentity? {
|
||||
guard let serviceIdentifier = identifier else {
|
||||
return nil
|
||||
}
|
||||
return ASPasswordCredentialIdentity(serviceIdentifier: serviceIdentifier, user: user, recordIdentifier: recordIdentifier)
|
||||
}
|
||||
|
||||
private func provideCredentials(in viewController: UIViewController?, with path: String) -> ASPasswordCredential? {
|
||||
print(path)
|
||||
guard let viewController = viewController else {
|
||||
return nil
|
||||
}
|
||||
var credential: ASPasswordCredential?
|
||||
decryptPassword(in: viewController, with: path) { password in
|
||||
let username = password.getUsernameForCompletion()
|
||||
let password = password.password
|
||||
credential = ASPasswordCredential(user: username, password: password)
|
||||
}
|
||||
return credential
|
||||
}
|
||||
|
|
@ -9,30 +9,22 @@
|
|||
import UIKit
|
||||
import passKit
|
||||
|
||||
func decryptPassword(in controller: UIViewController, with passwordEntity: PasswordEntity, using keyID: String? = nil, completion: @escaping ((Password) -> Void)) {
|
||||
DispatchQueue.global(qos: .userInteractive).async {
|
||||
do {
|
||||
let requestPGPKeyPassphrase = Utils.createRequestPGPKeyPassphraseHandler(controller: controller)
|
||||
let decryptedPassword = try PasswordStore.shared.decrypt(passwordEntity: passwordEntity, keyID: keyID, requestPGPKeyPassphrase: requestPGPKeyPassphrase)
|
||||
func decryptPassword(in controller: UIViewController, with passwordPath: String, using keyID: String? = nil, completion: @escaping ((Password) -> Void)) {
|
||||
do {
|
||||
let requestPGPKeyPassphrase = Utils.createRequestPGPKeyPassphraseHandler(controller: controller)
|
||||
let decryptedPassword = try PasswordStore.shared.decrypt(path: passwordPath, keyID: keyID, requestPGPKeyPassphrase: requestPGPKeyPassphrase)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
completion(decryptedPassword)
|
||||
}
|
||||
} catch let AppError.pgpPrivateKeyNotFound(keyID: key) {
|
||||
DispatchQueue.main.async {
|
||||
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.pgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction.cancelAndPopView(controller: controller))
|
||||
let selectKey = UIAlertAction.selectKey(controller: controller) { action in
|
||||
decryptPassword(in: controller, with: passwordEntity, using: action.title, completion: completion)
|
||||
}
|
||||
alert.addAction(selectKey)
|
||||
|
||||
controller.present(alert, animated: true)
|
||||
}
|
||||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
Utils.alert(title: "CannotCopyPassword".localize(), message: error.localizedDescription, controller: controller)
|
||||
}
|
||||
completion(decryptedPassword)
|
||||
} catch let AppError.pgpPrivateKeyNotFound(keyID: key) {
|
||||
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.pgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction.cancelAndPopView(controller: controller))
|
||||
let selectKey = UIAlertAction.selectKey(controller: controller) { action in
|
||||
decryptPassword(in: controller, with: passwordPath, using: action.title, completion: completion)
|
||||
}
|
||||
alert.addAction(selectKey)
|
||||
|
||||
controller.present(alert, animated: true)
|
||||
} catch {
|
||||
Utils.alert(title: "CannotCopyPassword".localize(), message: error.localizedDescription, controller: controller)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue