Merge branch 'release/0.2.8'

This commit is contained in:
Bob Sun 2017-07-16 21:29:49 -07:00
commit d223fc2345
22 changed files with 453 additions and 233 deletions

View file

@ -1,3 +1,5 @@
platform :ios, '10.2'
def generate_modulemap(name, path)
f = File.new(File.join("#{path}/module.modulemap"), "w+")
module_name = "#{name}"

View file

@ -18,11 +18,12 @@ Testflight, drop an email to `developer@passforios.mssun.me`. Thank you.
## Features
- Try to be compatible with the Password Store command line tool
- Support to view, copy, add, and edit password entries
- View, copy, add, and edit password entries
- Encrypt and decrypt password entries by PGP keys
- Synchronize with your password Git repository
- User-friendly interface: search, long press to copy, copy and open link, etc.
- Support one-time password (OTP) tokens (QR code and otpauth URI)
- Support one-time password tokens (two-factor authentication codes)
- Autofill in Safari/Chrome and [supported apps](https://github.com/agilebits/onepassword-app-extension)
- Written in Swift
- No need to jailbreak your devices
@ -38,8 +39,8 @@ Testflight, drop an email to `developer@passforios.mssun.me`. Thank you.
## Usages
- Setup your password-store ([official `Pass` introduction](https://www.passwordstore.org/))
- Get Pass for iOS from the App Store or build one by yourself
- Start to use Pass for iOS on your iPhone/iPad ([quick-start guide](https://github.com/mssun/passforios/wiki#quick-start-guide-for-pass-for-ios))
- Get Pass for iOS from the App Store or [build by yourself](https://github.com/mssun/passforios/wiki/Building-Pass-for-iOS)
- Setup Pass for iOS ([quick-start guide](https://github.com/mssun/passforios/wiki#quick-start-guide-for-pass-for-ios))
For more, please read the [wiki page](https://github.com/mssun/pass-ios/wiki).

View file

@ -55,7 +55,7 @@ platform :ios do
)
match(
type: "appstore",
app_identifier: "me.mssun.passforios.extension",
app_identifier: "me.mssun.passforios.find-login-action-extension",
keychain_name: ENV["MATCH_KEYCHAIN_NAME"],
keychain_password: ENV["MATCH_KEYCHAIN_PASSWORD"],
readonly: true

View file

@ -12,6 +12,7 @@
2C58F31EECC494C7A7F00A98 /* libPods-passKitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FB6C63FA1652F925B5C9F0B5 /* libPods-passKitTests.a */; };
398A8F69C2230A8117820BB7 /* libPods-passKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 45BAA15189E80AA544EAF7AD /* libPods-passKit.a */; };
6930A9D26085DE7CA1A7AACC /* libPods-passExtension.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1B240CA444AC9172F3053651 /* libPods-passExtension.a */; };
A2168A7F1EFD40D5005EA873 /* OnePasswordExtensionConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2168A7E1EFD40D5005EA873 /* OnePasswordExtensionConstants.swift */; };
A217ACE21E9AB17C00A1A6CF /* OTPScannerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A217ACE11E9AB17C00A1A6CF /* OTPScannerController.swift */; };
A217ACE41E9BBBBD00A1A6CF /* GitConfigSettingTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A217ACE31E9BBBBD00A1A6CF /* GitConfigSettingTableViewController.swift */; };
A2367B9B1EEFE1B300C8FE8B /* UtilsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2367B9A1EEFE1B300C8FE8B /* UtilsExtension.swift */; };
@ -80,6 +81,7 @@
DCC408C71E307DBB00F29B0E /* SVProgressHUD.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCC408C61E307DBB00F29B0E /* SVProgressHUD.framework */; };
DCC441521E8F6C06008A90C4 /* RawPasswordViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC441511E8F6C06008A90C4 /* RawPasswordViewController.swift */; };
DCC441541E916382008A90C4 /* GitSSHKeyArmorSettingTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC441531E916382008A90C4 /* GitSSHKeyArmorSettingTableViewController.swift */; };
DCD3C65E1EFB9BB400CBE842 /* SettingsSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCD3C65D1EFB9BB400CBE842 /* SettingsSplitViewController.swift */; };
DCDDEAB01E4639F300F68193 /* LabelTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DCDDEAAF1E4639F300F68193 /* LabelTableViewCell.xib */; };
DCDDEAB31E4896BF00F68193 /* PasswordDetailTitleTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCDDEAB11E4896BF00F68193 /* PasswordDetailTitleTableViewCell.swift */; };
DCFB779A1E4F3BCF008DE471 /* TitleTextFieldTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCFB77981E4F3BCF008DE471 /* TitleTextFieldTableViewCell.swift */; };
@ -165,6 +167,7 @@
7592A214C22CEBBEF4596CC1 /* libPods-pass.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-pass.a"; sourceTree = BUILT_PRODUCTS_DIR; };
7E088A9255B6CB576EF757C1 /* Pods-passKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-passKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-passKit/Pods-passKit.debug.xcconfig"; sourceTree = "<group>"; };
A02ACA4077630047EA669D05 /* Pods-pass.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-pass.debug.xcconfig"; path = "Pods/Target Support Files/Pods-pass/Pods-pass.debug.xcconfig"; sourceTree = "<group>"; };
A2168A7E1EFD40D5005EA873 /* OnePasswordExtensionConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnePasswordExtensionConstants.swift; sourceTree = "<group>"; };
A217ACE11E9AB17C00A1A6CF /* OTPScannerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OTPScannerController.swift; sourceTree = "<group>"; };
A217ACE31E9BBBBD00A1A6CF /* GitConfigSettingTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = GitConfigSettingTableViewController.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
A2227D4C1EEE5E25002A69A9 /* libObjectivePGP.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libObjectivePGP.a; path = "Pods/../build/Debug-iphoneos/ObjectivePGP/libObjectivePGP.a"; sourceTree = "<group>"; };
@ -253,6 +256,7 @@
DCC408C61E307DBB00F29B0E /* SVProgressHUD.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SVProgressHUD.framework; path = Carthage/Build/iOS/SVProgressHUD.framework; sourceTree = "<group>"; };
DCC441511E8F6C06008A90C4 /* RawPasswordViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RawPasswordViewController.swift; sourceTree = "<group>"; };
DCC441531E916382008A90C4 /* GitSSHKeyArmorSettingTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GitSSHKeyArmorSettingTableViewController.swift; sourceTree = "<group>"; };
DCD3C65D1EFB9BB400CBE842 /* SettingsSplitViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsSplitViewController.swift; sourceTree = "<group>"; };
DCDDEAAF1E4639F300F68193 /* LabelTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LabelTableViewCell.xib; sourceTree = "<group>"; };
DCDDEAB11E4896BF00F68193 /* PasswordDetailTitleTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasswordDetailTitleTableViewCell.swift; sourceTree = "<group>"; };
DCFB77981E4F3BCF008DE471 /* TitleTextFieldTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TitleTextFieldTableViewCell.swift; sourceTree = "<group>"; };
@ -324,6 +328,24 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
A2168A801EFD431A005EA873 /* Controllers */ = {
isa = PBXGroup;
children = (
A2A61C2B1EEFDF3300CFE063 /* ExtensionViewController.swift */,
A28C66671EF10EC900A398A1 /* PasscodeExtensionDisplay.swift */,
);
name = Controllers;
sourceTree = "<group>";
};
A2168A811EFD4322005EA873 /* Helpers */ = {
isa = PBXGroup;
children = (
A2367B9A1EEFE1B300C8FE8B /* UtilsExtension.swift */,
A2168A7E1EFD40D5005EA873 /* OnePasswordExtensionConstants.swift */,
);
name = Helpers;
sourceTree = "<group>";
};
A26075791EEC6F34005DB03E /* passKit */ = {
isa = PBXGroup;
children = (
@ -348,14 +370,13 @@
A26700251EEC466A00176B8A /* passExtension */ = {
isa = PBXGroup;
children = (
A26700331EEC46C900176B8A /* passExtension.entitlements */,
A267002B1EEC466A00176B8A /* Info.plist */,
A2168A801EFD431A005EA873 /* Controllers */,
A2168A811EFD4322005EA873 /* Helpers */,
A2367B9F1EF0387000C8FE8B /* Assets.xcassets */,
A26700351EEC475600176B8A /* passProcessor.js */,
A26700331EEC46C900176B8A /* passExtension.entitlements */,
A26700281EEC466A00176B8A /* MainInterface.storyboard */,
A267002B1EEC466A00176B8A /* Info.plist */,
A2A61C2B1EEFDF3300CFE063 /* ExtensionViewController.swift */,
A2367B9A1EEFE1B300C8FE8B /* UtilsExtension.swift */,
A28C66671EF10EC900A398A1 /* PasscodeExtensionDisplay.swift */,
);
path = passExtension;
sourceTree = "<group>";
@ -415,6 +436,7 @@
DC19400C1E4B39400077E0A3 /* Controllers */ = {
isa = PBXGroup;
children = (
DCD3C65D1EFB9BB400CBE842 /* SettingsSplitViewController.swift */,
DC3E64E51E656F11009A83DE /* CommitLogsTableViewController.swift */,
DC5F385A1E56AADB00C69ACA /* PGPKeyArmorSettingTableViewController.swift */,
DC037CB11E4CAB1700609409 /* AboutRepositoryTableViewController.swift */,
@ -1007,6 +1029,7 @@
buildActionMask = 2147483647;
files = (
A2A61C2C1EEFDF3300CFE063 /* ExtensionViewController.swift in Sources */,
A2168A7F1EFD40D5005EA873 /* OnePasswordExtensionConstants.swift in Sources */,
A28C66681EF10EC900A398A1 /* PasscodeExtensionDisplay.swift in Sources */,
A2367B9B1EEFE1B300C8FE8B /* UtilsExtension.swift in Sources */,
);
@ -1042,6 +1065,7 @@
DC4914991E434600007FF592 /* PasswordDetailTableViewController.swift in Sources */,
DC962CDF1E4B62C10033B5D8 /* AboutTableViewController.swift in Sources */,
DC5734AE1E439AD400D09270 /* PasswordsViewController.swift in Sources */,
DCD3C65E1EFB9BB400CBE842 /* SettingsSplitViewController.swift in Sources */,
DC3E64E61E656F11009A83DE /* CommitLogsTableViewController.swift in Sources */,
DC037CAA1E4B8EAE00609409 /* SpecialThanksTableViewController.swift in Sources */,
DC037CA61E4B883900609409 /* OpenSourceComponentsTableViewController.swift in Sources */,
@ -1143,13 +1167,12 @@
);
INFOPLIST_FILE = passKit/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited)";
LIBRARY_SEARCH_PATHS = "$(inherited)";
MODULEMAP_FILE = "";
OTHER_CFLAGS = "$(inherited)";
OTHER_LDFLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforios.passKit;
PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER).passKit";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
@ -1188,13 +1211,12 @@
);
INFOPLIST_FILE = passKit/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited)";
LIBRARY_SEARCH_PATHS = "$(inherited)";
MODULEMAP_FILE = "";
OTHER_CFLAGS = "$(inherited)";
OTHER_LDFLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforios.passKit;
PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER).passKit";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
@ -1220,7 +1242,7 @@
INFOPLIST_FILE = passKitTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforios.passKitTests;
PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER).passKitTests";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/pass.app/pass";
@ -1240,7 +1262,7 @@
INFOPLIST_FILE = passKitTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforios.passKitTests;
PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER).passKitTests";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/pass.app/pass";
@ -1266,14 +1288,13 @@
"$(SRCROOT)/Carthage/Build/iOS/ObjectiveGit.framework/Headers/",
);
INFOPLIST_FILE = passExtension/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
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 = "$(PRODUCT_BUNDLE_IDENTIFIER).find-login-action-extension";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "9feb619f-73bb-429c-a2a8-856ddcbb9e33";
PROVISIONING_PROFILE_SPECIFIER = "match Development me.mssun.passforios.extension";
PROVISIONING_PROFILE_SPECIFIER = "match Development me.mssun.passforios.find-login-action-extension";
SKIP_INSTALL = YES;
SWIFT_VERSION = 3.0;
};
@ -1298,14 +1319,13 @@
"$(SRCROOT)/Carthage/Build/iOS/ObjectiveGit.framework/Headers/",
);
INFOPLIST_FILE = passExtension/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
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 = "$(PRODUCT_BUNDLE_IDENTIFIER).find-login-action-extension";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "9b4419c3-a959-4af8-8810-8af134008ec5";
PROVISIONING_PROFILE_SPECIFIER = "match AppStore me.mssun.passforios.extension";
PROVISIONING_PROFILE_SPECIFIER = "match AppStore me.mssun.passforios.find-login-action-extension";
SKIP_INSTALL = YES;
SWIFT_VERSION = 3.0;
};
@ -1320,7 +1340,7 @@
INFOPLIST_FILE = passTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passTests;
PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER).passTests";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/pass.app/pass";
@ -1336,7 +1356,7 @@
INFOPLIST_FILE = passTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passTests;
PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER).passTests";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/pass.app/pass";
@ -1386,6 +1406,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforios;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@ -1428,6 +1449,7 @@
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforios;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
VALIDATE_PRODUCT = YES;
@ -1459,7 +1481,7 @@
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_CFLAGS = "$(inherited)";
OTHER_LDFLAGS = "${inherited}";
PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforios;
PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER)";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "893c10b3-79b1-46f7-914a-e625bf10d665";
PROVISIONING_PROFILE_SPECIFIER = "match Development me.mssun.passforios";
@ -1495,7 +1517,7 @@
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_CFLAGS = "$(inherited)";
OTHER_LDFLAGS = "${inherited}";
PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforios;
PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER)";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "aefeea85-1194-4db2-9ce4-fb9995e2fdff";
PROVISIONING_PROFILE_SPECIFIER = "match AppStore me.mssun.passforios";

View file

@ -38,6 +38,16 @@
ReferencedContainer = "container:pass.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A260757F1EEC6F34005DB03E"
BuildableName = "passKitTests.xctest"
BlueprintName = "passKitTests"
ReferencedContainer = "container:pass.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference

View file

@ -38,6 +38,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
return true
}
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if let _ = window?.rootViewController as? PasscodeLockViewController {
window?.frame = UIScreen.main.bounds
}
return .all
}
func postSearchNotification() {
NotificationCenter.default.post(name: .passwordSearch, object: nil)
}

View file

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12120" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="YoR-iB-XAd">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="17A264c" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="YoR-iB-XAd">
<device id="retina5_5" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12088"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@ -102,7 +102,7 @@
</subviews>
</tableViewCellContentView>
<connections>
<segue destination="ljx-el-KZL" kind="show" id="Jhf-o6-vIP"/>
<segue destination="Jzw-qC-crz" kind="showDetail" id="iCM-Fy-hkk"/>
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" textLabel="gWn-ib-STb" detailTextLabel="Myq-fV-riz" style="IBUITableViewCellStyleValue1" id="2rc-ZW-XKd">
@ -129,7 +129,7 @@
</subviews>
</tableViewCellContentView>
<connections>
<segue destination="K0b-qZ-UOk" kind="show" identifier="showGitServerSettingSegue" id="gbo-er-kAn"/>
<segue destination="K0b-qZ-UOk" kind="showDetail" identifier="showGitServerSettingSegue" id="ov1-DN-cwJ"/>
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="pgpKeyTableViewCell" textLabel="RR9-xr-9ko" detailTextLabel="7lc-Vh-G9W" style="IBUITableViewCellStyleValue1" id="1ze-MS-Xbj">
@ -222,7 +222,7 @@
</subviews>
</tableViewCellContentView>
<connections>
<segue destination="Rqu-AW-ZNQ" kind="show" id="Wpt-vk-aK8"/>
<segue destination="uoO-MF-fIN" kind="showDetail" id="mZM-Tb-Uny"/>
</connections>
</tableViewCell>
</cells>
@ -250,7 +250,7 @@
</subviews>
</tableViewCellContentView>
<connections>
<segue destination="ZcQ-fs-QEW" kind="show" id="PJC-pk-YRH"/>
<segue destination="0bw-Ed-Xsf" kind="showDetail" id="ffK-27-JkM"/>
</connections>
</tableViewCell>
</cells>
@ -267,8 +267,8 @@
<outlet property="passwordRepositoryTableViewCell" destination="2rc-ZW-XKd" id="aFq-K7-eIj"/>
<outlet property="pgpKeyTableViewCell" destination="1ze-MS-Xbj" id="hXe-eD-0R4"/>
<outlet property="touchIDTableViewCell" destination="wB7-Km-Oel" id="0fi-Sb-qMa"/>
<segue destination="ZUt-x1-TJu" kind="show" identifier="setPGPKeyByURLSegue" id="i0b-Yz-K9q"/>
<segue destination="ffY-rC-jhq" kind="show" identifier="setPGPKeyByASCIISegue" id="cEU-6E-1aQ"/>
<segue destination="ZUt-x1-TJu" kind="showDetail" identifier="setPGPKeyByURLSegue" id="qRF-S1-bqF"/>
<segue destination="ffY-rC-jhq" kind="showDetail" identifier="setPGPKeyByASCIISegue" id="mgi-Oe-i2X"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="leR-cc-QPW" userLabel="First Responder" sceneMemberID="firstResponder"/>
@ -288,7 +288,7 @@
<rect key="frame" x="0.0" y="28" width="414" height="54"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" tableViewCell="OfB-1N-1Am" id="fh0-au-C6q">
<rect key="frame" x="0.0" y="0.0" width="414" height="54"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="53.666666666666664"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" tag="201" contentMode="left" verticalHuggingPriority="251" preservesSuperviewLayoutMargins="YES" text="2017/04/04" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GLC-qL-55P">
@ -334,7 +334,7 @@
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dk5-pb-UNe" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="6082.608695652174" y="1495.9239130434785"/>
<point key="canvasLocation" x="6989.8550724637689" y="1495.9239130434785"/>
</scene>
<!--Git Server-->
<scene sceneID="Obl-ql-ILG">
@ -348,10 +348,10 @@
<tableViewSection headerTitle="Git Repository URL" id="pbe-W6-w4V">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" reuseIdentifier="gitRepositoryURLTabelViewCell" rowHeight="52" id="FRr-pf-aPO">
<rect key="frame" x="0.0" y="55" width="414" height="52"/>
<rect key="frame" x="0.0" y="55.333333333333336" width="414" height="52"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" tableViewCell="FRr-pf-aPO" id="60A-PS-qGe">
<rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="51.666666666666664"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Git Repository URL" textAlignment="natural" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="EVT-VU-sCi">
@ -378,10 +378,10 @@
<tableViewSection headerTitle="Username" id="fRu-A2-SCk">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" reuseIdentifier="usernameTableVIewCell" rowHeight="52" id="tnj-5U-kMB">
<rect key="frame" x="0.0" y="163" width="414" height="52"/>
<rect key="frame" x="0.0" y="163.33333333333334" width="414" height="52"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" tableViewCell="tnj-5U-kMB" id="f0c-pI-MSJ">
<rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="51.666666666666664"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Username" textAlignment="natural" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="TMg-Gk-7nG">
@ -407,10 +407,10 @@
<tableViewSection headerTitle="Authentication Method" id="h0N-tI-shZ">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="2" indentationWidth="0.0" shouldIndentWhileEditing="NO" id="KrP-nb-haa">
<rect key="frame" x="0.0" y="271" width="414" height="44"/>
<rect key="frame" x="0.0" y="271.33333333333337" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KrP-nb-haa" id="1uB-oE-kfI">
<rect key="frame" x="0.0" y="0.0" width="414" height="43"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="43.666666666666664"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Password" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="LfQ-Af-j2O">
@ -438,10 +438,10 @@
<inset key="separatorInset" minX="62" minY="0.0" maxX="0.0" maxY="0.0"/>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" accessoryType="detailButton" hidesAccessoryWhenEditing="NO" indentationLevel="2" indentationWidth="0.0" shouldIndentWhileEditing="NO" id="Qmt-bo-CuJ">
<rect key="frame" x="0.0" y="315" width="414" height="44"/>
<rect key="frame" x="0.0" y="315.33333333333337" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Qmt-bo-CuJ" id="p3u-8b-h3U">
<rect key="frame" x="0.0" y="0.0" width="367" height="43"/>
<rect key="frame" x="0.0" y="0.0" width="367" height="43.666666666666664"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="SSH Key" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ezz-76-a53">
@ -477,11 +477,6 @@
</tableView>
<toolbarItems/>
<navigationItem key="navigationItem" title="Git Server" id="gXX-yl-9oj">
<barButtonItem key="leftBarButtonItem" systemItem="cancel" id="LuU-Np-eBg">
<connections>
<segue destination="7K9-cE-9qq" kind="unwind" unwindAction="cancelGitServerSettingWithSegue:" id="SGr-tc-vDL"/>
</connections>
</barButtonItem>
<barButtonItem key="rightBarButtonItem" title="Clone" style="done" id="sgQ-zB-rxv">
<connections>
<action selector="save:" destination="ynQ-64-MfA" id="HNL-Da-fXT"/>
@ -519,7 +514,7 @@
<rect key="frame" x="0.0" y="35" width="414" height="52"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="BYZ-9g-xZy" id="Zfn-rK-sN1">
<rect key="frame" x="0.0" y="0.0" width="414" height="52"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="51.666666666666664"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Public Key URL" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dWi-eh-7Eq">
@ -553,7 +548,7 @@
<rect key="frame" x="0.0" y="87" width="414" height="52"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="vpk-J8-j7t" id="1td-qT-6ts">
<rect key="frame" x="0.0" y="0.0" width="414" height="52"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="51.666666666666664"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Private Key URL" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Qht-RC-Yeg">
@ -591,11 +586,6 @@
</connections>
</tableView>
<navigationItem key="navigationItem" title="PGP Key" id="eK3-bb-419">
<barButtonItem key="leftBarButtonItem" systemItem="cancel" id="LOw-J5-SOn">
<connections>
<segue destination="jjl-Xi-fkn" kind="unwind" unwindAction="cancelPGPKeyWithSegue:" id="Fgp-6V-y1S"/>
</connections>
</barButtonItem>
<barButtonItem key="rightBarButtonItem" systemItem="save" id="TNt-ne-l7W">
<connections>
<action selector="save:" destination="3WR-HY-zYj" id="uLA-oz-lPI"/>
@ -748,7 +738,7 @@
</tabBar>
<connections>
<segue destination="5ZN-vm-3gw" kind="relationship" relationship="viewControllers" id="VZu-vG-Fum"/>
<segue destination="ZmJ-0Z-N04" kind="relationship" relationship="viewControllers" id="6Yh-qG-26e"/>
<segue destination="r3B-u1-VNM" kind="relationship" relationship="viewControllers" id="b8U-9T-jof"/>
</connections>
</tabBarController>
<placeholder placeholderIdentifier="IBFirstResponder" id="h18-hY-pkk" userLabel="First Responder" sceneMemberID="firstResponder"/>
@ -756,6 +746,20 @@
<point key="canvasLocation" x="443" y="2096"/>
</scene>
<!--Settings-->
<scene sceneID="Wij-1K-1HM">
<objects>
<splitViewController id="r3B-u1-VNM" customClass="SettingsSplitViewController" customModule="pass" customModuleProvider="target" sceneMemberID="viewController">
<tabBarItem key="tabBarItem" title="Settings" image="Settings" selectedImage="Settings" id="YLZ-cr-akY"/>
<connections>
<segue destination="ZmJ-0Z-N04" kind="relationship" relationship="masterViewController" id="6BE-lA-jgG"/>
<segue destination="Jzw-qC-crz" kind="relationship" relationship="detailViewController" id="WfV-6d-ZUj"/>
</connections>
</splitViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="8r6-2t-h35" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="442" y="3143"/>
</scene>
<!--Settings-->
<scene sceneID="sdr-gl-b19">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="ZmJ-0Z-N04" sceneMemberID="viewController">
@ -881,7 +885,7 @@ Phone Support PIN #: 84719</string>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="2jy-oC-WQa" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="4954" y="1496"/>
<point key="canvasLocation" x="5860.8695652173919" y="1495.9239130434785"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="yn4-1A-RA2">
@ -916,7 +920,7 @@ Phone Support PIN #: 84719</string>
<rect key="frame" x="0.0" y="35" width="414" height="52"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="MA5-lE-8dT" id="pTv-Wj-psC">
<rect key="frame" x="0.0" y="0.0" width="414" height="52"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="51.666666666666664"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Private Key URL" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="C2w-dd-roS">
@ -989,7 +993,7 @@ Phone Support PIN #: 84719</string>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="j75-mg-v75" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3845" y="1496"/>
<point key="canvasLocation" x="4752.1739130434789" y="1495.9239130434785"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="GfH-IU-wIW">
@ -1021,7 +1025,7 @@ Phone Support PIN #: 84719</string>
<tableViewSection headerTitle="GPG Configuration" id="ugP-R2-9M7">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" textLabel="Jwg-mt-woS" style="IBUITableViewCellStyleDefault" id="tHt-Ro-0HF" userLabel="Encrypt in ASCII-Armored">
<rect key="frame" x="0.0" y="55" width="414" height="44"/>
<rect key="frame" x="0.0" y="55.333333333333336" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="tHt-Ro-0HF" id="Epj-ei-NtS">
<rect key="frame" x="0.0" y="0.0" width="414" height="43.666666666666664"/>
@ -1042,7 +1046,7 @@ Phone Support PIN #: 84719</string>
<tableViewSection headerTitle="Git Configuration" id="ihT-OG-HTv">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="87a-xY-AbR" detailTextLabel="2qr-d7-0SK" style="IBUITableViewCellStyleValue1" id="SVj-jD-qPT" userLabel="Git Signature">
<rect key="frame" x="0.0" y="155" width="414" height="44"/>
<rect key="frame" x="0.0" y="155.33333333333334" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="SVj-jD-qPT" id="HaO-5w-qZt">
<rect key="frame" x="0.0" y="0.0" width="381" height="43.666666666666664"/>
@ -1065,7 +1069,7 @@ Phone Support PIN #: 84719</string>
</subviews>
</tableViewCellContentView>
<connections>
<segue destination="RHo-mb-ayc" kind="show" id="YZO-oX-Umt"/>
<segue destination="zDo-XK-ymp" kind="show" id="Bt5-Sl-jWW"/>
</connections>
</tableViewCell>
</cells>
@ -1073,7 +1077,7 @@ Phone Support PIN #: 84719</string>
<tableViewSection headerTitle="PasswordStore Data" id="aVR-FE-jMg">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" textLabel="zrl-v3-fxg" style="IBUITableViewCellStyleDefault" id="Jm8-B5-wKx" userLabel="Discard Changes Table View Cell">
<rect key="frame" x="0.0" y="255" width="414" height="44"/>
<rect key="frame" x="0.0" y="255.33333333333334" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Jm8-B5-wKx" id="tjS-Q6-y2M">
<rect key="frame" x="0.0" y="0.0" width="414" height="43.666666666666664"/>
@ -1090,7 +1094,7 @@ Phone Support PIN #: 84719</string>
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" textLabel="K2K-Bx-g7Z" style="IBUITableViewCellStyleDefault" id="NI1-Kd-hyH">
<rect key="frame" x="0.0" y="299" width="414" height="44"/>
<rect key="frame" x="0.0" y="299.33333333333337" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="NI1-Kd-hyH" id="yLe-T2-TWF">
<rect key="frame" x="0.0" y="0.0" width="414" height="43.666666666666664"/>
@ -1124,7 +1128,7 @@ Phone Support PIN #: 84719</string>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="adh-5o-YYB" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3845" y="5332"/>
<point key="canvasLocation" x="4752.1739130434789" y="5331.521739130435"/>
</scene>
<!--About-->
<scene sceneID="f2e-C6-oxy">
@ -1148,7 +1152,7 @@ Phone Support PIN #: 84719</string>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="FCD-7i-hMu" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3845" y="6500"/>
<point key="canvasLocation" x="4752.1739130434789" y="6499.7282608695659"/>
</scene>
<!--Open Source Components-->
<scene sceneID="UFV-eK-lKM">
@ -1168,7 +1172,7 @@ Phone Support PIN #: 84719</string>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="AWL-FF-UWb" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="4954" y="6188"/>
<point key="canvasLocation" x="5860.8695652173919" y="6187.5000000000009"/>
</scene>
<!--Special Thanks-->
<scene sceneID="FNS-LJ-tzc">
@ -1188,7 +1192,7 @@ Phone Support PIN #: 84719</string>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Z6I-8E-8pB" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="4954" y="7022"/>
<point key="canvasLocation" x="5860.8695652173919" y="7021.467391304348"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="zfZ-pX-bff">
@ -1305,7 +1309,7 @@ Cgo
<rect key="frame" x="0.0" y="244" width="414" height="160"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Lom-iT-l16" id="eya-Tv-r0q">
<rect key="frame" x="0.0" y="0.0" width="414" height="160"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="159.66666666666666"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="oyB-oI-1fS">
@ -1331,7 +1335,7 @@ Cgo
<rect key="frame" x="0.0" y="404" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="F0i-XE-PGt" id="xO8-yL-W9a">
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="43.666666666666664"/>
<autoresizingMask key="autoresizingMask"/>
</tableViewCellContentView>
</tableViewCell>
@ -1343,7 +1347,7 @@ Cgo
<rect key="frame" x="0.0" y="487" width="414" height="160"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="J8U-ev-FRQ" id="eb0-vb-Fcc">
<rect key="frame" x="0.0" y="0.0" width="414" height="160"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="159.66666666666666"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lrQ-Ln-ZOv">
@ -1369,7 +1373,7 @@ Cgo
<rect key="frame" x="0.0" y="647" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="b0Z-rW-sAE" id="UZX-pP-UWB">
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="43.666666666666664"/>
<autoresizingMask key="autoresizingMask"/>
</tableViewCellContentView>
</tableViewCell>
@ -1382,11 +1386,6 @@ Cgo
</connections>
</tableView>
<navigationItem key="navigationItem" title="PGP Key" id="V4w-cf-d9g">
<barButtonItem key="leftBarButtonItem" systemItem="cancel" id="TCQ-S8-kCi">
<connections>
<segue destination="Ul9-vk-jhw" kind="unwind" unwindAction="cancelPGPKeyWithSegue:" id="JRZ-Sx-ovq"/>
</connections>
</barButtonItem>
<barButtonItem key="rightBarButtonItem" systemItem="save" id="lVZ-mz-KGt">
<connections>
<action selector="save:" destination="1gA-jh-frD" id="dfU-DP-Eth"/>
@ -1503,7 +1502,7 @@ Cgo
<rect key="frame" x="0.0" y="244" width="414" height="160"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="nmc-vy-Ab5" id="TQD-GC-YOY">
<rect key="frame" x="0.0" y="0.0" width="414" height="160"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="159.66666666666666"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="23o-MP-wQY">
@ -1526,7 +1525,7 @@ Cgo
<rect key="frame" x="0.0" y="404" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="jXO-n0-Mvx" id="AIL-mq-u7n">
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="43.666666666666664"/>
<autoresizingMask key="autoresizingMask"/>
</tableViewCellContentView>
</tableViewCell>
@ -1570,7 +1569,7 @@ Cgo
<rect key="frame" x="0.0" y="35" width="414" height="52"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="4Bh-1D-w5T" id="mIL-ig-tbp">
<rect key="frame" x="0.0" y="0.0" width="414" height="52"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="51.666666666666664"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Hlb-Zh-ega">
@ -1603,7 +1602,7 @@ Cgo
<rect key="frame" x="0.0" y="87" width="414" height="52"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="JRY-pY-XtS" id="KrQ-Ih-dk8">
<rect key="frame" x="0.0" y="0.0" width="414" height="52"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="51.666666666666664"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Email" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="m25-Qy-XwU">
@ -1641,11 +1640,6 @@ Cgo
</connections>
</tableView>
<navigationItem key="navigationItem" title="Git Signature" id="pPi-jd-x5U">
<barButtonItem key="leftBarButtonItem" systemItem="cancel" id="fQD-Bc-Mcd">
<connections>
<segue destination="M5P-Ab-cIc" kind="unwind" identifier="cancelGitConfigSettingSegue" unwindAction="cancelGitConfigSettingWithSegue:" id="Z2N-nJ-04S"/>
</connections>
</barButtonItem>
<barButtonItem key="rightBarButtonItem" systemItem="save" id="kMD-4J-wBb">
<connections>
<segue destination="M5P-Ab-cIc" kind="unwind" identifier="saveGitConfigSettingSegue" unwindAction="saveGitConfigSettingWithSegue:" id="RGN-ff-tuP"/>
@ -1660,25 +1654,7 @@ Cgo
<placeholder placeholderIdentifier="IBFirstResponder" id="FmV-2I-aov" userLabel="First Responder" sceneMemberID="firstResponder"/>
<exit id="M5P-Ab-cIc" userLabel="Exit" sceneMemberID="exit"/>
</objects>
<point key="canvasLocation" x="6109" y="5333"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="9zM-kx-OZU">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="RHo-mb-ayc" sceneMemberID="viewController">
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="ch6-Ko-kuU">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="zDo-XK-ymp" kind="relationship" relationship="rootViewController" id="vT1-I7-q3N"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="6nC-pe-hyF" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="4967" y="5333"/>
<point key="canvasLocation" x="5861" y="5332"/>
</scene>
<!--Scan PGP Keys-->
<scene sceneID="7j1-Qg-pUZ">
@ -1693,7 +1669,7 @@ Cgo
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="scanner output" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="U8O-Md-w8e">
<rect key="frame" x="50" y="562" width="314" height="45"/>
<rect key="frame" x="50" y="611" width="314" height="45"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="0.5" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" constant="45" id="q3X-BT-aK8"/>
@ -1710,21 +1686,14 @@ Cgo
<constraint firstItem="53A-gx-tky" firstAttribute="top" secondItem="U8O-Md-w8e" secondAttribute="bottom" constant="80" id="tzL-K0-lE7"/>
</constraints>
</view>
<navigationItem key="navigationItem" title="Scan PGP Keys" id="JIs-3z-Tmr">
<barButtonItem key="leftBarButtonItem" systemItem="cancel" id="yma-o8-xRu">
<connections>
<segue destination="0F8-Zv-c2C" kind="unwind" unwindAction="cancelPGPScannerWithSegue:" id="q14-fu-3N4"/>
</connections>
</barButtonItem>
</navigationItem>
<navigationItem key="navigationItem" title="Scan PGP Keys" id="JIs-3z-Tmr"/>
<connections>
<outlet property="scannerOutput" destination="U8O-Md-w8e" id="JTW-9y-mr6"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="I2W-rx-CxX" userLabel="First Responder" sceneMemberID="firstResponder"/>
<exit id="0F8-Zv-c2C" userLabel="Exit" sceneMemberID="exit"/>
</objects>
<point key="canvasLocation" x="6122" y="4302"/>
<point key="canvasLocation" x="5861" y="4304"/>
</scene>
<!--Scan SSH Keys-->
<scene sceneID="kmR-CX-Yi7">
@ -1756,28 +1725,76 @@ Cgo
<constraint firstAttribute="trailingMargin" secondItem="fsL-pq-A5q" secondAttribute="trailing" constant="30" id="ymC-G4-bdA"/>
</constraints>
</view>
<navigationItem key="navigationItem" title="Scan SSH Keys" id="bov-FI-Hkg">
<barButtonItem key="leftBarButtonItem" systemItem="cancel" id="JhH-TO-YkO">
<connections>
<segue destination="J2S-Mr-s10" kind="unwind" unwindAction="cancelSSHScannerWithSegue:" id="Thj-zj-TEX"/>
</connections>
</barButtonItem>
</navigationItem>
<navigationItem key="navigationItem" title="Scan SSH Keys" id="bov-FI-Hkg"/>
<connections>
<outlet property="scannerOutput" destination="fsL-pq-A5q" id="lSv-2S-qVd"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="s1p-jn-4PV" userLabel="First Responder" sceneMemberID="firstResponder"/>
<exit id="J2S-Mr-s10" userLabel="Exit" sceneMemberID="exit"/>
</objects>
<point key="canvasLocation" x="7133" y="2895"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="Hf2-tj-DSK">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="Jzw-qC-crz" sceneMemberID="viewController">
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="YCA-VS-Qu8">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="ljx-el-KZL" kind="relationship" relationship="rootViewController" id="yqd-o3-osr"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="5oJ-VM-g5J" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3844.9275362318845" y="1495.9239130434785"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="FT9-BJ-SVt">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="0bw-Ed-Xsf" sceneMemberID="viewController">
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="D0D-LP-K9m">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="ZcQ-fs-QEW" kind="relationship" relationship="rootViewController" id="azd-nb-7xK"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="0BT-Bk-j2Q" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3844.9275362318845" y="6499.7282608695659"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="adg-bw-dTz">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="uoO-MF-fIN" sceneMemberID="viewController">
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="HdT-LG-aSd">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="Rqu-AW-ZNQ" kind="relationship" relationship="rootViewController" id="YG1-74-4mb"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="TAd-pc-0Ta" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3844.9275362318845" y="5331.521739130435"/>
</scene>
</scenes>
<resources>
<image name="Lock" width="25" height="25"/>
<image name="Settings" width="25" height="25"/>
</resources>
<inferredMetricsTieBreakers>
<segue reference="iCM-Fy-hkk"/>
<segue reference="yyD-4H-pLE"/>
</inferredMetricsTieBreakers>
</document>

View file

@ -88,9 +88,6 @@ class AdvancedSettingsTableViewController: UITableViewController {
SharedDefaults[.encryptInArmored] = encryptInASCIIArmoredSwitch.isOn
}
@IBAction func cancelGitConfigSetting(segue: UIStoryboardSegue) {
}
@IBAction func saveGitConfigSetting(segue: UIStoryboardSegue) {
if let controller = segue.source as? GitConfigSettingTableViewController {
if let gitSignatureName = controller.nameTextField.text,

View file

@ -204,9 +204,4 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe
}
}
}
@IBAction private func cancelPGPScanner(segue: UIStoryboardSegue) {
}
}

View file

@ -261,6 +261,9 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
if let username = password.getUsername() {
section.item.append(TableCell(title: "username", content: username))
}
if let login = password.getLogin() {
section.item.append(TableCell(title: "login", content: login))
}
section.item.append(TableCell(title: "password", content: password.password))
tableData.append(section)
@ -278,17 +281,12 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
}
// show additional information
let filteredAdditionKeys = password.additionKeys.filter {
$0.lowercased() != "username" &&
$0.lowercased() != "password" &&
(!$0.hasPrefix("unknown") || !SharedDefaults[.isHideUnknownOn]) &&
(!Password.otpKeywords.contains($0) || !SharedDefaults[.isHideOTPOn]) }
let filteredAdditionKeys = password.getFilteredAdditions()
if filteredAdditionKeys.count > 0 {
section = TableSection(type: .addition, header: "additions")
for additionKey in filteredAdditionKeys {
section.item.append(TableCell(title: additionKey, content: password.additions[additionKey]!))
}
filteredAdditionKeys.forEach({ (key: String, value: String) in
section.item.append(TableCell(title: key, content: value))
})
tableData.append(section)
}

View file

@ -88,6 +88,7 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
case .fillPasswordCell:
fillPasswordCell = tableView.dequeueReusableCell(withIdentifier: "fillPasswordCell", for: indexPath) as? FillPasswordTableViewCell
fillPasswordCell?.delegate = self
fillPasswordCell?.contentTextField.delegate = self
fillPasswordCell?.setContent(content: cellData[PasswordEditorCellKey.content] as? String)
if tableData[passwordSection].count == 1 {
fillPasswordCell?.settingButton.isHidden = true
@ -97,10 +98,18 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
passwordLengthCell = tableView.dequeueReusableCell(withIdentifier: "passwordLengthCell", for: indexPath) as? SliderTableViewCell
let lengthSetting = Globals.passwordDefaultLength[SharedDefaults[.passwordGeneratorFlavor]] ??
Globals.passwordDefaultLength["Random"]
let minimumLength = lengthSetting?.min ?? 0
let maximumLength = lengthSetting?.max ?? 0
var defaultLength = lengthSetting?.def ?? 0
if let currentPasswordLength = (tableData[passwordSection][0][PasswordEditorCellKey.content] as? String)?.characters.count,
currentPasswordLength >= minimumLength,
currentPasswordLength <= maximumLength {
defaultLength = currentPasswordLength
}
passwordLengthCell?.reset(title: "Length",
minimumValue: lengthSetting?.min ?? 0,
maximumValue: lengthSetting?.max ?? 0,
defaultValue: lengthSetting?.def ?? 0)
minimumValue: minimumLength,
maximumValue: maximumLength,
defaultValue: defaultLength)
passwordLengthCell?.delegate = self
return passwordLengthCell!
case .additionsCell:
@ -234,18 +243,16 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
}
}
@IBAction private func cancelOTPScanner(segue: UIStoryboardSegue) {
}
// update the data table after editing
// update tableData so to make sure reloadData() works correctly
func textFieldDidEndEditing(_ textField: UITextField) {
if textField == nameCell?.contentTextField {
tableData[nameSection][0][PasswordEditorCellKey.content] = nameCell?.getContent()
} else if textField == fillPasswordCell?.contentTextField {
tableData[passwordSection][0][PasswordEditorCellKey.content] = fillPasswordCell?.getContent()
}
}
// update the data table after editing
// update tableData so to make sure reloadData() works correctly
func textViewDidEndEditing(_ textView: UITextView) {
if textView == additionsCell?.contentTextView {
tableData[additionsSection][0][PasswordEditorCellKey.content] = additionsCell?.getContent()

View file

@ -456,7 +456,8 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
switch scope {
case "All":
filteredPasswordsTableEntries = passwordsTableAllEntries.filter { entry in
return entry.title.lowercased().contains(searchText.lowercased())
let name = entry.passwordEntity?.nameWithCategory ?? entry.title
return name.localizedCaseInsensitiveContains(searchText)
}
if searchController.isActive && searchController.searchBar.text != "" {
reloadTableView(data: filteredPasswordsTableEntries)

View file

@ -0,0 +1,24 @@
//
// SettingsSplitViewController.swift
// pass
//
// Created by Mingshen Sun on 6/21/17.
// Copyright © 2017 Bob Sun. All rights reserved.
//
import UIKit
class SettingsSplitViewController: UISplitViewController, UISplitViewControllerDelegate {
override func viewDidLoad() {
self.delegate = self
self.preferredDisplayMode = .allVisible
}
func splitViewController(
_ splitViewController: UISplitViewController,
collapseSecondary secondaryViewController: UIViewController,
onto primaryViewController: UIViewController) -> Bool {
// Return true to prevent UIKit from applying its default behavior
return true
}
}

View file

@ -28,9 +28,6 @@ class SettingsTableViewController: UITableViewController {
@IBOutlet weak var passwordRepositoryTableViewCell: UITableViewCell!
let passwordStore = PasswordStore.shared
var passcodeLockConfig = PasscodeLockConfiguration.shared
@IBAction func cancelPGPKey(segue: UIStoryboardSegue) {
}
@IBAction func savePGPKey(segue: UIStoryboardSegue) {
if let controller = segue.source as? PGPKeySettingTableViewController {
@ -117,9 +114,6 @@ class SettingsTableViewController: UITableViewController {
}
}
@IBAction func cancelGitServerSetting(segue: UIStoryboardSegue) {
}
@IBAction func saveGitServerSetting(segue: UIStoryboardSegue) {
self.passwordRepositoryTableViewCell.detailTextLabel?.text = SharedDefaults[.gitURL]?.host
}

View file

@ -17,7 +17,16 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.2.7</string>
<string>0.2.8</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>org-appextension-feature-password-management</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>1</string>
<key>ITSAppUsesNonExemptEncryption</key>

View file

@ -26,13 +26,15 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV
private let passwordStore = PasswordStore.shared
private var searchActive = false
// the URL passed to the extension
private var extensionURL: String?
private var passwordsTableEntries: [PasswordsTableEntry] = []
private var filteredPasswordsTableEntries: [PasswordsTableEntry] = []
enum Action {
case findLogin, fillBrowser, unknown
}
private var extensionAction = Action.unknown
private lazy var passcodelock: PasscodeExtensionDisplay = {
let passcodelock = PasscodeExtensionDisplay(extensionContext: self.extensionContext)
return passcodelock
@ -64,24 +66,67 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV
// initialize table entries
initPasswordsTableEntries()
// search using the extensionContext inputs
let item = extensionContext?.inputItems.first as! NSExtensionItem
let provider = item.attachments?.first as! NSItemProvider
let propertyList = String(kUTTypePropertyList)
if provider.hasItemConformingToTypeIdentifier(propertyList) {
provider.loadItem(forTypeIdentifier: propertyList, options: nil, completionHandler: { (item, error) -> Void in
let dictionary = item as! NSDictionary
let results = dictionary[NSExtensionJavaScriptPreprocessingResultsKey] as! NSDictionary
let url = URL(string: (results["url"] as? String)!)?.host
DispatchQueue.main.async { [weak self] in
// force search (set text, set active, force search)
self?.searchBar.text = url
self?.searchBar.becomeFirstResponder()
self?.searchBarSearchButtonClicked((self?.searchBar)!)
// get the provider
guard let extensionItems = extensionContext?.inputItems as? [NSExtensionItem] else {
return
}
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)!)
}
})
}
}
})
} else {
print("error")
}
}
}
@ -115,19 +160,29 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV
var decryptedPassword: Password?
do {
decryptedPassword = try self.passwordStore.decrypt(passwordEntity: passwordEntity, requestPGPKeyPassphrase: self.requestPGPKeyPassphrase)
DispatchQueue.main.async {
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
// return a dictionary for JavaScript for best-effor fill in
let username = decryptedPassword?.getUsername() ?? decryptedPassword?.getLogin() ?? ""
let password = decryptedPassword?.password ?? ""
DispatchQueue.main.async {// prepare a dictionary to return
switch self.extensionAction {
case .findLogin:
let extensionItem = NSExtensionItem()
let returnDictionary = [ NSExtensionJavaScriptFinalizeArgumentKey : ["username": decryptedPassword?.getUsername() ?? "", "password": 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)
}))
self.present(alert, animated: true, completion: nil)
case .fillBrowser:
Utils.copyToPasteboard(textToCopy: decryptedPassword?.password)
// 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 {
print(error)

View file

@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>0.2.7</string>
<string>0.2.8</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSExtension</key>
@ -29,7 +29,9 @@
<key>NSExtensionActivationSupportsText</key>
<true/>
<key>NSExtensionActivationSupportsWebPageWithMaxCount</key>
<integer>100</integer>
<integer>1</integer>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>1</integer>
</dict>
<key>NSExtensionJavaScriptPreprocessingFile</key>
<string>passProcessor</string>

View file

@ -0,0 +1,51 @@
//
// OnePasswordExtensionConstants.swift
// pass
//
// Created by Yishi Lin on 2017/6/23.
// Copyright © 2017 Bob Sun. All rights reserved.
//
// This file contains constants from https://github.com/agilebits/onepassword-app-extension/
class OnePasswordExtensionActions {
static let findLogin = "org.appextension.find-login-action"
static let saveLogin = "org.appextension.save-login-action"
static let changePassword = "org.appextension.change-password-action"
static let fillWebView = "org.appextension.fill-webview-action"
static let fillBrowser = "org.appextension.fill-browser-action"
}
class OnePasswordExtensionKey {
// Login Dictionary keys - Used to get or set the properties of a 1Password Login
static let URLStringKey = "url_string"
static let usernameKey = "username"
static let passwordKey = "password"
static let totpKey = "totp"
static let titleKey = "login_title"
static let notesKey = "notes"
static let sectionTitleKey = "section_title"
static let fieldsKey = "fields"
static let returnedFieldsKey = "returned_fields"
static let oldPasswordKey = "old_password"
static let passwordGeneratorOptionsKey = "password_generator_options"
// Password Generator options - Used to set the 1Password Password Generator options when saving a new Login or when changing the password for for an existing Login
static let generatedPasswordMinLengthKey = "password_min_length"
static let generatedPasswordMaxLengthKey = "password_max_length"
static let generatedPasswordRequireDigitsKey = "password_require_digits"
static let generatedPasswordRequireSymbolsKey = "password_require_symbols"
static let generatedPasswordForbiddenCharactersKey = "password_forbidden_characters"
}
// Errors codes
class OnePasswordExtensionError {
static let errorDomain = "OnePasswordExtension"
static let errorCodeCancelledByUser = 0
static let errorCodeAPINotAvailable = 1
static let errorCodeFailedToContactExtension = 2
static let errorCodeFailedToLoadItemProviderData = 3
static let errorCodeCollectFieldsScriptFailed = 4
static let errorCodeFillFieldsScriptFailed = 5
static let errorCodeUnexpectedData = 6
static let errorCodeFailedToObtainURLStringFromWebView = 7
}

View file

@ -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"]
}
}
}
};

View file

@ -111,11 +111,13 @@ public class Utils {
// draw all digits in the password into red
// draw all punctuation characters in the password into blue
for (index, element) in plainPassword.unicodeScalars.enumerated() {
var charColor = UIColor.darkText
if NSCharacterSet.decimalDigits.contains(element) {
attributedPassword.addAttribute(NSForegroundColorAttributeName, value: Globals.red, range: NSRange(location: index, length: 1))
charColor = Globals.red
} else if !NSCharacterSet.letters.contains(element) {
attributedPassword.addAttribute(NSForegroundColorAttributeName, value: Globals.blue, range: NSRange(location: index, length: 1))
charColor = Globals.blue
}
attributedPassword.addAttribute(NSForegroundColorAttributeName, value: charColor, range: NSRange(location: index, length: 1))
}
return attributedPassword
}

View file

@ -36,11 +36,10 @@ public class Password {
}
}
public var password = ""
public var additions = [String: String]()
public var additionKeys = [String]()
public var changed: Int = 0
public var plainText = ""
private var additions = [String: String]()
private var firstLineIsOTPField = false
private var otpToken: Token?
@ -82,16 +81,29 @@ public class Password {
self.name = name
self.url = url
self.plainText = plainText
self.additions.removeAll()
self.additionKeys.removeAll()
additions.removeAll()
// get password and additional fields
// split the plain text
let plainTextSplit = plainText.characters.split(maxSplits: 1, omittingEmptySubsequences: false) {
$0 == "\n" || $0 == "\r\n"
}.map(String.init)
self.password = plainTextSplit.first ?? ""
// get password
password = plainTextSplit.first ?? ""
// get additonal fields
if plainTextSplit.count == 2 {
(self.additions, self.additionKeys) = Password.getAdditionFields(from: plainTextSplit[1])
var unknownIndex = 0
plainTextSplit[1].enumerateLines() { line, _ in
if !line.isEmpty {
var (key, value) = Password.getKeyValuePair(from: line)
if key == nil {
unknownIndex += 1
key = "unknown \(unknownIndex)"
}
self.additions[key!] = value
}
}
}
// check whether the first line of the plainText looks like an otp entry
@ -99,7 +111,6 @@ public class Password {
if Password.otpKeywords.contains(key ?? "") {
firstLineIsOTPField = true
self.additions[key!] = value
self.additionKeys.insert(key!, at: 0)
} else {
firstLineIsOTPField = false
}
@ -108,12 +119,28 @@ public class Password {
self.updateOtpToken()
}
public func getFilteredAdditions() -> [String: String] {
var filteredAdditions = [String: String]()
additions.forEach { (key: String, value: String) in
if key.lowercased() != "username" && key.lowercased() != "login" && key.lowercased() != "password" &&
(!key.hasPrefix("unknown") || !SharedDefaults[.isHideUnknownOn]) &&
(!Password.otpKeywords.contains(key) || !SharedDefaults[.isHideOTPOn]) {
filteredAdditions[key] = value
}
}
return filteredAdditions
}
public func getUsername() -> String? {
return getAdditionValue(withKey: "Username") ?? getAdditionValue(withKey: "username")
return getAdditionValue(withKey: "username", caseSensitive: false)
}
public func getLogin() -> String? {
return getAdditionValue(withKey: "login", caseSensitive: false)
}
public func getURLString() -> String? {
return getAdditionValue(withKey: "URL") ?? getAdditionValue(withKey: "url") ?? getAdditionValue(withKey: "Url")
return getAdditionValue(withKey: "url", caseSensitive: false)
}
// return a key-value pair from the line
@ -138,27 +165,6 @@ public class Password {
return (key, value)
}
private static func getAdditionFields(from additionFieldsPlainText: String) -> ([String: String], [String]){
var additions = [String: String]()
var additionKeys = [String]()
var unknownIndex = 0
additionFieldsPlainText.enumerateLines() { line, _ in
if line == "" {
return
}
var (key, value) = getKeyValuePair(from: line)
if key == nil {
unknownIndex += 1
key = "unknown \(unknownIndex)"
}
additions[key!] = value
additionKeys.append(key!)
}
return (additions, additionKeys)
}
public func getAdditionsPlainText() -> String {
// lines starting from the second
let plainTextSplit = plainText.characters.split(maxSplits: 1, omittingEmptySubsequences: false) {
@ -179,8 +185,18 @@ public class Password {
return getPlainText().data(using: .utf8)!
}
private func getAdditionValue(withKey key: String) -> String? {
return self.additions[key]
private func getAdditionValue(withKey key: String, caseSensitive: Bool = true) -> String? {
if caseSensitive {
return additions[key]
} else {
let searchKey = key.lowercased()
for k in additions.keys {
if searchKey == k.lowercased() {
return additions[k]
}
}
return nil
}
}
/*