2017-06-14 00:25:38 +08:00
|
|
|
//
|
|
|
|
|
// PasswordsViewController.swift
|
|
|
|
|
// pass
|
|
|
|
|
//
|
|
|
|
|
// Created by Yishi Lin on 13/6/17.
|
|
|
|
|
// Copyright © 2017 Bob Sun. All rights reserved.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
import Foundation
|
|
|
|
|
import MobileCoreServices
|
|
|
|
|
import passKit
|
|
|
|
|
|
2021-01-10 13:40:17 -08:00
|
|
|
class ExtensionViewController: UIViewController {
|
|
|
|
|
var passcodelock: PasscodeExtensionDisplay {
|
|
|
|
|
PasscodeExtensionDisplay(extensionContext: self.extensionContext!)
|
|
|
|
|
}
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2021-01-10 13:40:17 -08:00
|
|
|
var embeddedNavigationController: UINavigationController {
|
|
|
|
|
children.first as! UINavigationController
|
|
|
|
|
}
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2021-01-10 13:40:17 -08:00
|
|
|
var passwordsViewController: PasswordsViewController {
|
|
|
|
|
embeddedNavigationController.viewControllers.first as! PasswordsViewController
|
|
|
|
|
}
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2017-06-23 21:57:03 +08:00
|
|
|
enum Action {
|
|
|
|
|
case findLogin, fillBrowser, unknown
|
|
|
|
|
}
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2021-01-10 13:40:17 -08:00
|
|
|
private var action = Action.unknown
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2021-01-10 13:40:17 -08:00
|
|
|
lazy var credentialProvider = CredentialProvider(viewController: self, extensionContext: self.extensionContext!)
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2021-01-10 13:40:17 -08:00
|
|
|
override func viewDidLoad() {
|
|
|
|
|
super.viewDidLoad()
|
|
|
|
|
passcodelock.presentPasscodeLockIfNeeded(self)
|
2020-06-28 21:25:40 +02:00
|
|
|
|
2021-01-10 13:40:17 -08:00
|
|
|
let passwordsTableEntries = PasswordStore.shared.fetchPasswordEntityCoreData(withDir: false).compactMap { PasswordTableEntry($0) }
|
|
|
|
|
let dataSource = PasswordsTableDataSource(entries: passwordsTableEntries)
|
|
|
|
|
passwordsViewController.dataSource = dataSource
|
|
|
|
|
passwordsViewController.selectionDelegate = self
|
|
|
|
|
passwordsViewController.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancel))
|
2017-06-14 00:25:38 +08:00
|
|
|
}
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2017-06-14 19:14:56 +08:00
|
|
|
override func viewWillAppear(_ animated: Bool) {
|
|
|
|
|
super.viewWillAppear(animated)
|
2021-01-10 13:40:17 -08:00
|
|
|
prepareCredentialList()
|
2017-06-14 19:14:56 +08:00
|
|
|
}
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2021-01-10 13:40:17 -08:00
|
|
|
@objc
|
|
|
|
|
private func cancel(_: AnyObject?) {
|
|
|
|
|
self.extensionContext?.completeRequest(returningItems: nil)
|
|
|
|
|
}
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2021-01-10 13:40:17 -08:00
|
|
|
func prepareCredentialList() {
|
|
|
|
|
guard let attachments = self.extensionContext?.attachments else {
|
2017-06-25 12:52:08 +08:00
|
|
|
return
|
2017-06-23 21:57:03 +08:00
|
|
|
}
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2021-01-10 13:40:17 -08:00
|
|
|
func completeTask(_ text: String?) {
|
|
|
|
|
DispatchQueue.main.async {
|
|
|
|
|
self.passwordsViewController.showPasswordsWithSuggstion(matching: text ?? "")
|
|
|
|
|
self.passwordsViewController.navigationItem.prompt = text
|
2017-06-25 12:52:08 +08:00
|
|
|
}
|
2017-06-14 00:25:38 +08:00
|
|
|
}
|
2021-01-10 13:40:17 -08:00
|
|
|
DispatchQueue.global(qos: .userInitiated).async {
|
|
|
|
|
for attachment in attachments {
|
|
|
|
|
if attachment.hasURL {
|
|
|
|
|
self.action = .fillBrowser
|
|
|
|
|
attachment.extractSearchText { completeTask($0) }
|
|
|
|
|
} else if attachment.hasFindLoginAction {
|
|
|
|
|
self.action = .findLogin
|
|
|
|
|
attachment.extractSearchText { completeTask($0) }
|
|
|
|
|
} else if attachment.hasPropertyList {
|
|
|
|
|
self.action = .fillBrowser
|
|
|
|
|
attachment.extractSearchText { completeTask($0) }
|
|
|
|
|
} else {
|
|
|
|
|
self.action = .unknown
|
|
|
|
|
}
|
2020-09-19 17:15:49 +02:00
|
|
|
}
|
|
|
|
|
}
|
2017-06-14 00:25:38 +08:00
|
|
|
}
|
2021-01-10 13:40:17 -08:00
|
|
|
}
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2021-01-10 13:40:17 -08:00
|
|
|
extension ExtensionViewController: PasswordSelectionDelegate {
|
|
|
|
|
func selected(password: PasswordTableEntry) {
|
|
|
|
|
switch action {
|
|
|
|
|
case .findLogin:
|
|
|
|
|
credentialProvider.provideCredentialsFindLogin(with: password.passwordEntity.getPath())
|
|
|
|
|
case .fillBrowser:
|
|
|
|
|
credentialProvider.provideCredentialsBrowser(with: password.passwordEntity.getPath())
|
|
|
|
|
default:
|
|
|
|
|
self.extensionContext?.completeRequest(returningItems: nil, completionHandler: nil)
|
2017-06-14 00:25:38 +08:00
|
|
|
}
|
2020-04-18 22:35:17 -07:00
|
|
|
}
|
2021-01-10 13:40:17 -08:00
|
|
|
}
|
2020-04-18 22:35:17 -07:00
|
|
|
|
2021-01-10 13:40:17 -08:00
|
|
|
extension NSDictionary {
|
|
|
|
|
func extractSearchText() -> String? {
|
|
|
|
|
if let value = self[PassExtensionKey.URLStringKey] as? String {
|
|
|
|
|
if let host = URL(string: value)?.host {
|
|
|
|
|
return host
|
|
|
|
|
} else {
|
|
|
|
|
return value
|
|
|
|
|
}
|
|
|
|
|
} else if let value = self[NSExtensionJavaScriptPreprocessingResultsKey] as? String {
|
|
|
|
|
if let host = URL(string: value)?.host {
|
|
|
|
|
return host
|
|
|
|
|
} else {
|
|
|
|
|
return value
|
2017-06-14 00:25:38 +08:00
|
|
|
}
|
|
|
|
|
}
|
2021-01-10 13:40:17 -08:00
|
|
|
return nil
|
2017-06-14 00:25:38 +08:00
|
|
|
}
|
2021-01-10 13:40:17 -08:00
|
|
|
}
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2021-01-10 13:40:17 -08:00
|
|
|
extension NSItemProvider {
|
|
|
|
|
var hasFindLoginAction: Bool {
|
|
|
|
|
hasItemConformingToTypeIdentifier(PassExtensionActions.findLogin)
|
2017-06-14 00:25:38 +08:00
|
|
|
}
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2021-01-10 13:40:17 -08:00
|
|
|
var hasURL: Bool {
|
|
|
|
|
hasItemConformingToTypeIdentifier(kUTTypeURL as String) && registeredTypeIdentifiers.count == 1
|
2017-06-14 00:25:38 +08:00
|
|
|
}
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2021-01-10 13:40:17 -08:00
|
|
|
var hasPropertyList: Bool {
|
|
|
|
|
hasItemConformingToTypeIdentifier(kUTTypePropertyList as String)
|
2017-06-14 00:25:38 +08:00
|
|
|
}
|
2021-01-10 13:40:17 -08:00
|
|
|
}
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2021-01-10 13:40:17 -08:00
|
|
|
extension NSExtensionContext {
|
|
|
|
|
/// Get all the attachments to this post.
|
|
|
|
|
var attachments: [NSItemProvider] {
|
|
|
|
|
guard let items = inputItems as? [NSExtensionItem] else {
|
|
|
|
|
return []
|
|
|
|
|
}
|
|
|
|
|
return items.flatMap { $0.attachments ?? [] }
|
2017-06-14 00:25:38 +08:00
|
|
|
}
|
2021-01-10 13:40:17 -08:00
|
|
|
}
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2021-01-10 13:40:17 -08:00
|
|
|
extension NSItemProvider {
|
|
|
|
|
/// Extracts the URL from the item provider
|
|
|
|
|
func extractSearchText(completion: @escaping (String?) -> Void) {
|
|
|
|
|
self.loadItem(forTypeIdentifier: kUTTypeURL as String) { item, _ in
|
|
|
|
|
if let url = item as? NSURL {
|
|
|
|
|
completion(url.host)
|
|
|
|
|
} else {
|
|
|
|
|
completion(nil)
|
|
|
|
|
}
|
2017-06-14 00:25:38 +08:00
|
|
|
}
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2021-01-10 13:40:17 -08:00
|
|
|
self.loadItem(forTypeIdentifier: kUTTypePropertyList as String) { item, _ in
|
|
|
|
|
if let dict = item as? NSDictionary {
|
|
|
|
|
if let result = dict[NSExtensionJavaScriptPreprocessingResultsKey] as? NSDictionary {
|
|
|
|
|
completion(result.extractSearchText())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2021-01-10 13:40:17 -08:00
|
|
|
self.loadItem(forTypeIdentifier: PassExtensionActions.findLogin) { item, _ in
|
|
|
|
|
if let dict = item as? NSDictionary {
|
|
|
|
|
let text = dict.extractSearchText()
|
|
|
|
|
completion(text)
|
|
|
|
|
}
|
2017-06-14 00:25:38 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|