diff --git a/pass.xcodeproj/project.pbxproj b/pass.xcodeproj/project.pbxproj
index 899d17e..3a0a0e1 100644
--- a/pass.xcodeproj/project.pbxproj
+++ b/pass.xcodeproj/project.pbxproj
@@ -1294,7 +1294,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_CFLAGS = "$(inherited)";
- PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforios.extension;
+ PRODUCT_BUNDLE_IDENTIFIER = "me.mssun.passforios.find-login-action-extension";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "9feb619f-73bb-429c-a2a8-856ddcbb9e33";
PROVISIONING_PROFILE_SPECIFIER = "match Development me.mssun.passforios.extension";
@@ -1326,7 +1326,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_CFLAGS = "$(inherited)";
- PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforios.extension;
+ PRODUCT_BUNDLE_IDENTIFIER = "me.mssun.passforios.find-login-action-extension";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "9b4419c3-a959-4af8-8810-8af134008ec5";
PROVISIONING_PROFILE_SPECIFIER = "match AppStore me.mssun.passforios.extension";
diff --git a/passExtension/ExtensionViewController.swift b/passExtension/ExtensionViewController.swift
index fa8871a..ff733ee 100644
--- a/passExtension/ExtensionViewController.swift
+++ b/passExtension/ExtensionViewController.swift
@@ -67,46 +67,66 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV
initPasswordsTableEntries()
// get the provider
- let item = extensionContext?.inputItems.first as! NSExtensionItem
- let provider: NSItemProvider
- if item.attachments?.count == 1 {
- // Safari
- provider = item.attachments?.first as! NSItemProvider
- } else {
- // e.g., Chrome, apps
- provider = item.attachments?[1] as! NSItemProvider
+ guard let extensionItems = extensionContext?.inputItems as? [NSExtensionItem] else {
+ return
}
- // search using the extensionContext inputs
- if provider.hasItemConformingToTypeIdentifier(OnePasswordExtensionActions.findLogin) {
- provider.loadItem(forTypeIdentifier: OnePasswordExtensionActions.findLogin, options: nil, completionHandler: { (item, error) -> Void in
- let dictionary = item as! NSDictionary
- var url: String?
- if var urlString = dictionary[OnePasswordExtensionKey.URLStringKey] as? String {
- if !urlString.hasPrefix("http://") && !urlString.hasPrefix("https://") {
- urlString = "http://" + urlString
+ for extensionItem in extensionItems {
+ if let itemProviders = extensionItem.attachments as? [NSItemProvider] {
+ for provider in itemProviders {
+ // search using the extensionContext inputs
+ if provider.hasItemConformingToTypeIdentifier(OnePasswordExtensionActions.findLogin) {
+ provider.loadItem(forTypeIdentifier: OnePasswordExtensionActions.findLogin, options: nil, completionHandler: { (item, error) -> Void in
+ let dictionary = item as! NSDictionary
+ var url: String?
+ if var urlString = dictionary[OnePasswordExtensionKey.URLStringKey] as? String {
+ if !urlString.hasPrefix("http://") && !urlString.hasPrefix("https://") {
+ urlString = "http://" + urlString
+ }
+ url = URL(string: urlString)?.host
+ }
+ DispatchQueue.main.async { [weak self] in
+ self?.extensionAction = .findLogin
+ // force search (set text, set active, force search)
+ self?.searchBar.text = url
+ self?.searchBar.becomeFirstResponder()
+ self?.searchBarSearchButtonClicked((self?.searchBar)!)
+ }
+ })
+ }
+ else if provider.hasItemConformingToTypeIdentifier(kUTTypePropertyList as String) {
+ provider.loadItem(forTypeIdentifier: kUTTypePropertyList as String, options: nil, completionHandler: { (item, error) -> Void in
+ var url: String?
+ if let dictionary = item as? NSDictionary,
+ let results = dictionary[NSExtensionJavaScriptPreprocessingResultsKey] as? NSDictionary,
+ var urlString = results[OnePasswordExtensionKey.URLStringKey] as? String {
+ if !urlString.hasPrefix("http://") && !urlString.hasPrefix("https://") {
+ urlString = "http://" + urlString
+ }
+ url = URL(string: urlString)?.host
+ }
+ DispatchQueue.main.async { [weak self] in
+ self?.extensionAction = .fillBrowser
+ // force search (set text, set active, force search)
+ self?.searchBar.text = url
+ self?.searchBar.becomeFirstResponder()
+ self?.searchBarSearchButtonClicked((self?.searchBar)!)
+ }
+ })
+ } else if provider.hasItemConformingToTypeIdentifier(kUTTypeURL as String) {
+ provider.loadItem(forTypeIdentifier: kUTTypeURL as String, options: nil, completionHandler: { (item, error) -> Void in
+ let url = (item as? NSURL)!.host
+ DispatchQueue.main.async { [weak self] in
+ self?.extensionAction = .fillBrowser
+ // force search (set text, set active, force search)
+ self?.searchBar.text = url
+ self?.searchBar.becomeFirstResponder()
+ self?.searchBarSearchButtonClicked((self?.searchBar)!)
+ }
+ })
}
- url = URL(string: urlString)?.host
}
- DispatchQueue.main.async { [weak self] in
- self?.extensionAction = .findLogin
- // force search (set text, set active, force search)
- self?.searchBar.text = url
- self?.searchBar.becomeFirstResponder()
- self?.searchBarSearchButtonClicked((self?.searchBar)!)
- }
- })
- } else if provider.hasItemConformingToTypeIdentifier(kUTTypeURL as String) {
- provider.loadItem(forTypeIdentifier: kUTTypeURL as String, options: nil, completionHandler: { (item, error) -> Void in
- let url = (item as? NSURL)!.host
- DispatchQueue.main.async { [weak self] in
- self?.extensionAction = .fillBrowser
- // force search (set text, set active, force search)
- self?.searchBar.text = url
- self?.searchBar.becomeFirstResponder()
- self?.searchBarSearchButtonClicked((self?.searchBar)!)
- }
- })
+ }
}
}
@@ -140,28 +160,28 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV
var decryptedPassword: Password?
do {
decryptedPassword = try self.passwordStore.decrypt(passwordEntity: passwordEntity, requestPGPKeyPassphrase: self.requestPGPKeyPassphrase)
- DispatchQueue.main.async {
+ let username = decryptedPassword?.getUsername() ?? ""
+ let password = decryptedPassword?.password ?? ""
+ DispatchQueue.main.async {// prepare a dictionary to return
switch self.extensionAction {
case .findLogin:
- // prepare a dictionary to return
let extensionItem = NSExtensionItem()
- var returnDictionary = [OnePasswordExtensionKey.usernameKey: decryptedPassword?.getUsername() ?? "",
- OnePasswordExtensionKey.passwordKey: decryptedPassword?.password ?? ""]
+ var returnDictionary = [OnePasswordExtensionKey.usernameKey: username,
+ OnePasswordExtensionKey.passwordKey: password]
if let totpPassword = decryptedPassword?.getOtp() {
returnDictionary[OnePasswordExtensionKey.totpKey] = totpPassword
}
extensionItem.attachments = [NSItemProvider(item: returnDictionary as NSSecureCoding, typeIdentifier: String(kUTTypePropertyList))]
self.extensionContext!.completeRequest(returningItems: [extensionItem], completionHandler: nil)
- default:
- // copy the password to the clipboard
+ case .fillBrowser:
Utils.copyToPasteboard(textToCopy: decryptedPassword?.password)
- let title = "Password Copied"
- let message = "Usename: " + (decryptedPassword?.getUsername() ?? "Unknown") + "\r\n(Remember to clear the clipboard.)"
- let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
- alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
- self.extensionContext!.completeRequest(returningItems: nil, completionHandler: nil)
- }))
- self.present(alert, animated: true, completion: nil)
+ // return a dictionary for JavaScript for best-effor fill in
+ let extensionItem = NSExtensionItem()
+ let returnDictionary = [NSExtensionJavaScriptFinalizeArgumentKey : ["username": username, "password": password]]
+ extensionItem.attachments = [NSItemProvider(item: returnDictionary as NSSecureCoding, typeIdentifier: String(kUTTypePropertyList))]
+ self.extensionContext!.completeRequest(returningItems: [extensionItem], completionHandler: nil)
+ default:
+ self.extensionContext!.completeRequest(returningItems: nil, completionHandler: nil)
}
}
} catch {
diff --git a/passExtension/Info.plist b/passExtension/Info.plist
index db41ae3..830754c 100644
--- a/passExtension/Info.plist
+++ b/passExtension/Info.plist
@@ -28,9 +28,13 @@
NSExtensionActivationSupportsText
+ NSExtensionActivationSupportsWebPageWithMaxCount
+ 1
NSExtensionActivationSupportsWebURLWithMaxCount
1
+ NSExtensionJavaScriptPreprocessingFile
+ passProcessor
NSExtensionMainStoryboard
MainInterface
diff --git a/passExtension/passProcessor.js b/passExtension/passProcessor.js
index 6db3d04..2cb114e 100644
--- a/passExtension/passProcessor.js
+++ b/passExtension/passProcessor.js
@@ -3,22 +3,32 @@ var PassProcessor = function() {};
PassProcessor.prototype = {
run: function(arguments) {
var url
- var html
var error
try {
- url = document.URL;
- html = document.body.innerHTML
+ url = document.URL
} catch (e) {
error = e
} finally {
- arguments.completionFunction({"url": url, "html": html, "error": error});
+ arguments.completionFunction({"url_string": url, "error": error});
}
},
finalize: function(arguments) {
- var str = "username: " + arguments["username"] + "\r\npassword: " + arguments["password"];
- // alert(str)
- // document.body.innerHTML = arguments["content"];
+ if (arguments["password"]) {
+ var passwordElement = document.querySelector("input[type=password]")
+ if (passwordElement) {
+ passwordElement.setAttribute('value', arguments["password"])
+ passwordElement.value = arguments["password"]
+ }
+ }
+
+ if (arguments["username"]) {
+ var usernameElement = document.querySelector("input[type=email], input[type=text]")
+ if (usernameElement) {
+ usernameElement.setAttribute('value', arguments["username"])
+ usernameElement.value = arguments["username"]
+ }
+ }
}
};