Support Safari/Chrome auto fill
This commit is contained in:
parent
5710f496fc
commit
5d71f99711
4 changed files with 92 additions and 58 deletions
|
|
@ -1294,7 +1294,7 @@
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
||||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||||
OTHER_CFLAGS = "$(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)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE = "9feb619f-73bb-429c-a2a8-856ddcbb9e33";
|
PROVISIONING_PROFILE = "9feb619f-73bb-429c-a2a8-856ddcbb9e33";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "match Development me.mssun.passforios.extension";
|
PROVISIONING_PROFILE_SPECIFIER = "match Development me.mssun.passforios.extension";
|
||||||
|
|
@ -1326,7 +1326,7 @@
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
||||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||||
OTHER_CFLAGS = "$(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)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE = "9b4419c3-a959-4af8-8810-8af134008ec5";
|
PROVISIONING_PROFILE = "9b4419c3-a959-4af8-8810-8af134008ec5";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "match AppStore me.mssun.passforios.extension";
|
PROVISIONING_PROFILE_SPECIFIER = "match AppStore me.mssun.passforios.extension";
|
||||||
|
|
|
||||||
|
|
@ -67,16 +67,13 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
initPasswordsTableEntries()
|
initPasswordsTableEntries()
|
||||||
|
|
||||||
// get the provider
|
// get the provider
|
||||||
let item = extensionContext?.inputItems.first as! NSExtensionItem
|
guard let extensionItems = extensionContext?.inputItems as? [NSExtensionItem] else {
|
||||||
let provider: NSItemProvider
|
return
|
||||||
if item.attachments?.count == 1 {
|
|
||||||
// Safari
|
|
||||||
provider = item.attachments?.first as! NSItemProvider
|
|
||||||
} else {
|
|
||||||
// e.g., Chrome, apps
|
|
||||||
provider = item.attachments?[1] as! NSItemProvider
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for extensionItem in extensionItems {
|
||||||
|
if let itemProviders = extensionItem.attachments as? [NSItemProvider] {
|
||||||
|
for provider in itemProviders {
|
||||||
// search using the extensionContext inputs
|
// search using the extensionContext inputs
|
||||||
if provider.hasItemConformingToTypeIdentifier(OnePasswordExtensionActions.findLogin) {
|
if provider.hasItemConformingToTypeIdentifier(OnePasswordExtensionActions.findLogin) {
|
||||||
provider.loadItem(forTypeIdentifier: OnePasswordExtensionActions.findLogin, options: nil, completionHandler: { (item, error) -> Void in
|
provider.loadItem(forTypeIdentifier: OnePasswordExtensionActions.findLogin, options: nil, completionHandler: { (item, error) -> Void in
|
||||||
|
|
@ -96,6 +93,26 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
self?.searchBarSearchButtonClicked((self?.searchBar)!)
|
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) {
|
} else if provider.hasItemConformingToTypeIdentifier(kUTTypeURL as String) {
|
||||||
provider.loadItem(forTypeIdentifier: kUTTypeURL as String, options: nil, completionHandler: { (item, error) -> Void in
|
provider.loadItem(forTypeIdentifier: kUTTypeURL as String, options: nil, completionHandler: { (item, error) -> Void in
|
||||||
let url = (item as? NSURL)!.host
|
let url = (item as? NSURL)!.host
|
||||||
|
|
@ -109,6 +126,9 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// define cell contents, and set long press action
|
// define cell contents, and set long press action
|
||||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||||
|
|
@ -140,28 +160,28 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
var decryptedPassword: Password?
|
var decryptedPassword: Password?
|
||||||
do {
|
do {
|
||||||
decryptedPassword = try self.passwordStore.decrypt(passwordEntity: passwordEntity, requestPGPKeyPassphrase: self.requestPGPKeyPassphrase)
|
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 {
|
switch self.extensionAction {
|
||||||
case .findLogin:
|
case .findLogin:
|
||||||
// prepare a dictionary to return
|
|
||||||
let extensionItem = NSExtensionItem()
|
let extensionItem = NSExtensionItem()
|
||||||
var returnDictionary = [OnePasswordExtensionKey.usernameKey: decryptedPassword?.getUsername() ?? "",
|
var returnDictionary = [OnePasswordExtensionKey.usernameKey: username,
|
||||||
OnePasswordExtensionKey.passwordKey: decryptedPassword?.password ?? ""]
|
OnePasswordExtensionKey.passwordKey: password]
|
||||||
if let totpPassword = decryptedPassword?.getOtp() {
|
if let totpPassword = decryptedPassword?.getOtp() {
|
||||||
returnDictionary[OnePasswordExtensionKey.totpKey] = totpPassword
|
returnDictionary[OnePasswordExtensionKey.totpKey] = totpPassword
|
||||||
}
|
}
|
||||||
extensionItem.attachments = [NSItemProvider(item: returnDictionary as NSSecureCoding, typeIdentifier: String(kUTTypePropertyList))]
|
extensionItem.attachments = [NSItemProvider(item: returnDictionary as NSSecureCoding, typeIdentifier: String(kUTTypePropertyList))]
|
||||||
self.extensionContext!.completeRequest(returningItems: [extensionItem], completionHandler: nil)
|
self.extensionContext!.completeRequest(returningItems: [extensionItem], completionHandler: nil)
|
||||||
default:
|
case .fillBrowser:
|
||||||
// copy the password to the clipboard
|
|
||||||
Utils.copyToPasteboard(textToCopy: decryptedPassword?.password)
|
Utils.copyToPasteboard(textToCopy: decryptedPassword?.password)
|
||||||
let title = "Password Copied"
|
// return a dictionary for JavaScript for best-effor fill in
|
||||||
let message = "Usename: " + (decryptedPassword?.getUsername() ?? "Unknown") + "\r\n(Remember to clear the clipboard.)"
|
let extensionItem = NSExtensionItem()
|
||||||
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
|
let returnDictionary = [NSExtensionJavaScriptFinalizeArgumentKey : ["username": username, "password": password]]
|
||||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
|
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)
|
self.extensionContext!.completeRequest(returningItems: nil, completionHandler: nil)
|
||||||
}))
|
|
||||||
self.present(alert, animated: true, completion: nil)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,13 @@
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSExtensionActivationSupportsText</key>
|
<key>NSExtensionActivationSupportsText</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>NSExtensionActivationSupportsWebPageWithMaxCount</key>
|
||||||
|
<string>1</string>
|
||||||
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
|
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
|
||||||
<integer>1</integer>
|
<integer>1</integer>
|
||||||
</dict>
|
</dict>
|
||||||
|
<key>NSExtensionJavaScriptPreprocessingFile</key>
|
||||||
|
<string>passProcessor</string>
|
||||||
</dict>
|
</dict>
|
||||||
<key>NSExtensionMainStoryboard</key>
|
<key>NSExtensionMainStoryboard</key>
|
||||||
<string>MainInterface</string>
|
<string>MainInterface</string>
|
||||||
|
|
|
||||||
|
|
@ -3,22 +3,32 @@ var PassProcessor = function() {};
|
||||||
PassProcessor.prototype = {
|
PassProcessor.prototype = {
|
||||||
run: function(arguments) {
|
run: function(arguments) {
|
||||||
var url
|
var url
|
||||||
var html
|
|
||||||
var error
|
var error
|
||||||
try {
|
try {
|
||||||
url = document.URL;
|
url = document.URL
|
||||||
html = document.body.innerHTML
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
error = e
|
error = e
|
||||||
} finally {
|
} finally {
|
||||||
arguments.completionFunction({"url": url, "html": html, "error": error});
|
arguments.completionFunction({"url_string": url, "error": error});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
finalize: function(arguments) {
|
finalize: function(arguments) {
|
||||||
var str = "username: " + arguments["username"] + "\r\npassword: " + arguments["password"];
|
if (arguments["password"]) {
|
||||||
// alert(str)
|
var passwordElement = document.querySelector("input[type=password]")
|
||||||
// document.body.innerHTML = arguments["content"];
|
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"]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue