Rewrite AutoFill extension
This commit is contained in:
parent
7e034d9c99
commit
40ac070232
13 changed files with 609 additions and 216 deletions
|
|
@ -101,8 +101,15 @@
|
||||||
556EC3DA22335D3400934F9C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 30C25DBF21F3599E00BB27BB /* InfoPlist.strings */; };
|
556EC3DA22335D3400934F9C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 30C25DBF21F3599E00BB27BB /* InfoPlist.strings */; };
|
||||||
556EC3DB22335D3D00934F9C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 30C25DBF21F3599E00BB27BB /* InfoPlist.strings */; };
|
556EC3DB22335D3D00934F9C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 30C25DBF21F3599E00BB27BB /* InfoPlist.strings */; };
|
||||||
8BA607EB4C9C8258741AC18C /* Pods_passExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14E955B67C88672AA3A40BA0 /* Pods_passExtension.framework */; };
|
8BA607EB4C9C8258741AC18C /* Pods_passExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14E955B67C88672AA3A40BA0 /* Pods_passExtension.framework */; };
|
||||||
|
9A55C158259E785600FA8FD9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DC917BDD1E2E8231000FDF54 /* Assets.xcassets */; };
|
||||||
|
9A55C15F259E785700FA8FD9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DC917BDD1E2E8231000FDF54 /* Assets.xcassets */; };
|
||||||
|
9A55C185259E8C5600FA8FD9 /* PasswordsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A55C184259E8C5600FA8FD9 /* PasswordsViewController.swift */; };
|
||||||
9A652414244BB33300DA0A41 /* UIAlertActionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A652413244BB33300DA0A41 /* UIAlertActionExtension.swift */; };
|
9A652414244BB33300DA0A41 /* UIAlertActionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A652413244BB33300DA0A41 /* UIAlertActionExtension.swift */; };
|
||||||
9A8A8387402FCCCECB1232A4 /* Pods_passKitTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B2B2F844061EFA534FE9506 /* Pods_passKitTests.framework */; };
|
9A8A8387402FCCCECB1232A4 /* Pods_passKitTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B2B2F844061EFA534FE9506 /* Pods_passKitTests.framework */; };
|
||||||
|
9A8F9EBD259EA4C50027CE15 /* PasswordsTableDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A8F9EBC259EA4C50027CE15 /* PasswordsTableDataSource.swift */; };
|
||||||
|
9A8F9ECC259ECB410027CE15 /* PasswordSelectionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A8F9ECB259ECB410027CE15 /* PasswordSelectionDelegate.swift */; };
|
||||||
|
9A8F9EE2259EDD520027CE15 /* PasswordTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A8F9EE1259EDD520027CE15 /* PasswordTableViewCell.swift */; };
|
||||||
|
9A8F9EF0259EE01A0027CE15 /* PasswordDecryptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A8F9EEF259EE01A0027CE15 /* PasswordDecryptor.swift */; };
|
||||||
9ADC954124418A5F0005402E /* PasswordStoreTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9ADC954024418A5F0005402E /* PasswordStoreTest.swift */; };
|
9ADC954124418A5F0005402E /* PasswordStoreTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9ADC954024418A5F0005402E /* PasswordStoreTest.swift */; };
|
||||||
A20691F41F2A3D0E0096483D /* SecurePasteboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = A20691F31F2A3D0E0096483D /* SecurePasteboard.swift */; };
|
A20691F41F2A3D0E0096483D /* SecurePasteboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = A20691F31F2A3D0E0096483D /* SecurePasteboard.swift */; };
|
||||||
A217ACE41E9BBBBD00A1A6CF /* GitConfigSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A217ACE31E9BBBBD00A1A6CF /* GitConfigSettingsTableViewController.swift */; };
|
A217ACE41E9BBBBD00A1A6CF /* GitConfigSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A217ACE31E9BBBBD00A1A6CF /* GitConfigSettingsTableViewController.swift */; };
|
||||||
|
|
@ -363,7 +370,12 @@
|
||||||
9A1EF0B424C50E780074FEAC /* passBetaAutoFillExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = passBetaAutoFillExtension.entitlements; sourceTree = "<group>"; };
|
9A1EF0B424C50E780074FEAC /* passBetaAutoFillExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = passBetaAutoFillExtension.entitlements; sourceTree = "<group>"; };
|
||||||
9A1EF0B524C50EE00074FEAC /* passBetaExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = passBetaExtension.entitlements; sourceTree = "<group>"; };
|
9A1EF0B524C50EE00074FEAC /* passBetaExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = passBetaExtension.entitlements; sourceTree = "<group>"; };
|
||||||
9A1EF0B624C50FEA0074FEAC /* passBetaShortcuts.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = passBetaShortcuts.entitlements; sourceTree = "<group>"; };
|
9A1EF0B624C50FEA0074FEAC /* passBetaShortcuts.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = passBetaShortcuts.entitlements; sourceTree = "<group>"; };
|
||||||
|
9A55C184259E8C5600FA8FD9 /* PasswordsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordsViewController.swift; sourceTree = "<group>"; };
|
||||||
9A652413244BB33300DA0A41 /* UIAlertActionExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIAlertActionExtension.swift; sourceTree = "<group>"; };
|
9A652413244BB33300DA0A41 /* UIAlertActionExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIAlertActionExtension.swift; sourceTree = "<group>"; };
|
||||||
|
9A8F9EBC259EA4C50027CE15 /* PasswordsTableDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordsTableDataSource.swift; sourceTree = "<group>"; };
|
||||||
|
9A8F9ECB259ECB410027CE15 /* PasswordSelectionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordSelectionDelegate.swift; sourceTree = "<group>"; };
|
||||||
|
9A8F9EE1259EDD520027CE15 /* PasswordTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordTableViewCell.swift; sourceTree = "<group>"; };
|
||||||
|
9A8F9EEF259EE01A0027CE15 /* PasswordDecryptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordDecryptor.swift; sourceTree = "<group>"; };
|
||||||
9ADC954024418A5F0005402E /* PasswordStoreTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordStoreTest.swift; sourceTree = "<group>"; };
|
9ADC954024418A5F0005402E /* PasswordStoreTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordStoreTest.swift; sourceTree = "<group>"; };
|
||||||
A20691F31F2A3D0E0096483D /* SecurePasteboard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecurePasteboard.swift; sourceTree = "<group>"; };
|
A20691F31F2A3D0E0096483D /* SecurePasteboard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecurePasteboard.swift; sourceTree = "<group>"; };
|
||||||
A217ACE31E9BBBBD00A1A6CF /* GitConfigSettingsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = GitConfigSettingsTableViewController.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
|
A217ACE31E9BBBBD00A1A6CF /* GitConfigSettingsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = GitConfigSettingsTableViewController.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
|
||||||
|
|
@ -689,6 +701,31 @@
|
||||||
path = Crypto;
|
path = Crypto;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
9A8F9EBB259EA4A80027CE15 /* Services */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
9A8F9EBC259EA4C50027CE15 /* PasswordsTableDataSource.swift */,
|
||||||
|
9A8F9EEF259EE01A0027CE15 /* PasswordDecryptor.swift */,
|
||||||
|
);
|
||||||
|
path = Services;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
9A8F9ECA259ECAFC0027CE15 /* Protocols */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
9A8F9ECB259ECB410027CE15 /* PasswordSelectionDelegate.swift */,
|
||||||
|
);
|
||||||
|
path = Protocols;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
9A8F9EE0259EDD390027CE15 /* Views */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
9A8F9EE1259EDD520027CE15 /* PasswordTableViewCell.swift */,
|
||||||
|
);
|
||||||
|
path = Views;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
A2168A801EFD431A005EA873 /* Controllers */ = {
|
A2168A801EFD431A005EA873 /* Controllers */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
|
@ -709,6 +746,9 @@
|
||||||
A239F5972158C08C00576CBF /* passAutoFillExtension */ = {
|
A239F5972158C08C00576CBF /* passAutoFillExtension */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
9A8F9EE0259EDD390027CE15 /* Views */,
|
||||||
|
9A8F9ECA259ECAFC0027CE15 /* Protocols */,
|
||||||
|
9A8F9EBB259EA4A80027CE15 /* Services */,
|
||||||
A239F5A921591E3700576CBF /* Controllers */,
|
A239F5A921591E3700576CBF /* Controllers */,
|
||||||
A239F59E2158C08C00576CBF /* passAutoFillExtension.entitlements */,
|
A239F59E2158C08C00576CBF /* passAutoFillExtension.entitlements */,
|
||||||
9A1EF0B424C50E780074FEAC /* passBetaAutoFillExtension.entitlements */,
|
9A1EF0B424C50E780074FEAC /* passBetaAutoFillExtension.entitlements */,
|
||||||
|
|
@ -722,6 +762,7 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
30697C5221F63E0B0064FCAC /* CredentialProviderViewController.swift */,
|
30697C5221F63E0B0064FCAC /* CredentialProviderViewController.swift */,
|
||||||
|
9A55C184259E8C5600FA8FD9 /* PasswordsViewController.swift */,
|
||||||
30697C5121F63E0B0064FCAC /* PasscodeExtensionDisplay.swift */,
|
30697C5121F63E0B0064FCAC /* PasscodeExtensionDisplay.swift */,
|
||||||
);
|
);
|
||||||
path = Controllers;
|
path = Controllers;
|
||||||
|
|
@ -1231,6 +1272,7 @@
|
||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
9A55C15F259E785700FA8FD9 /* Assets.xcassets in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|
@ -1242,6 +1284,7 @@
|
||||||
556EC3D322335C5F00934F9C /* Localizable.strings in Resources */,
|
556EC3D322335C5F00934F9C /* Localizable.strings in Resources */,
|
||||||
556EC3D422335C5F00934F9C /* Localizable.stringsdict in Resources */,
|
556EC3D422335C5F00934F9C /* Localizable.stringsdict in Resources */,
|
||||||
A239F59C2158C08C00576CBF /* MainInterface.storyboard in Resources */,
|
A239F59C2158C08C00576CBF /* MainInterface.storyboard in Resources */,
|
||||||
|
9A55C158259E785600FA8FD9 /* Assets.xcassets in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|
@ -1508,8 +1551,13 @@
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
9A8F9EE2259EDD520027CE15 /* PasswordTableViewCell.swift in Sources */,
|
||||||
|
9A8F9ECC259ECB410027CE15 /* PasswordSelectionDelegate.swift in Sources */,
|
||||||
30697C5421F63E0B0064FCAC /* CredentialProviderViewController.swift in Sources */,
|
30697C5421F63E0B0064FCAC /* CredentialProviderViewController.swift in Sources */,
|
||||||
|
9A55C185259E8C5600FA8FD9 /* PasswordsViewController.swift in Sources */,
|
||||||
|
9A8F9EBD259EA4C50027CE15 /* PasswordsTableDataSource.swift in Sources */,
|
||||||
30697C5321F63E0B0064FCAC /* PasscodeExtensionDisplay.swift in Sources */,
|
30697C5321F63E0B0064FCAC /* PasscodeExtensionDisplay.swift in Sources */,
|
||||||
|
9A8F9EF0259EE01A0027CE15 /* PasswordDecryptor.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|
@ -1886,7 +1934,7 @@
|
||||||
"$(SDKROOT)/usr/include/libxml2",
|
"$(SDKROOT)/usr/include/libxml2",
|
||||||
"$(SRCROOT)/Carthage/Build/iOS/ObjectiveGit.framework/Headers/",
|
"$(SRCROOT)/Carthage/Build/iOS/ObjectiveGit.framework/Headers/",
|
||||||
);
|
);
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
|
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
OTHER_SWIFT_FLAGS = "-D BETA";
|
OTHER_SWIFT_FLAGS = "-D BETA";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforiosbeta;
|
PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforiosbeta;
|
||||||
|
|
@ -2459,7 +2507,7 @@
|
||||||
"$(SDKROOT)/usr/include/libxml2",
|
"$(SDKROOT)/usr/include/libxml2",
|
||||||
"$(SRCROOT)/Carthage/Build/iOS/ObjectiveGit.framework/Headers/",
|
"$(SRCROOT)/Carthage/Build/iOS/ObjectiveGit.framework/Headers/",
|
||||||
);
|
);
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
|
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforios;
|
PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforios;
|
||||||
|
|
@ -2524,7 +2572,7 @@
|
||||||
"$(SDKROOT)/usr/include/libxml2",
|
"$(SDKROOT)/usr/include/libxml2",
|
||||||
"$(SRCROOT)/Carthage/Build/iOS/ObjectiveGit.framework/Headers/",
|
"$(SRCROOT)/Carthage/Build/iOS/ObjectiveGit.framework/Headers/",
|
||||||
);
|
);
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
|
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforios;
|
PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforios;
|
||||||
PRODUCT_NAME = Pass;
|
PRODUCT_NAME = Pass;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "1230"
|
||||||
|
wasCreatedForAppExtension = "YES"
|
||||||
|
version = "2.0">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "A239F5942158C08B00576CBF"
|
||||||
|
BuildableName = "passAutoFillExtension.appex"
|
||||||
|
BlueprintName = "passAutoFillExtension"
|
||||||
|
ReferencedContainer = "container:pass.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "DC917BD21E2E8231000FDF54"
|
||||||
|
BuildableName = "Pass.app"
|
||||||
|
BlueprintName = "pass"
|
||||||
|
ReferencedContainer = "container:pass.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
|
<Testables>
|
||||||
|
</Testables>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = ""
|
||||||
|
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
|
||||||
|
launchStyle = "0"
|
||||||
|
askForAppToLaunch = "Yes"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "DC917BD21E2E8231000FDF54"
|
||||||
|
BuildableName = "Pass.app"
|
||||||
|
BlueprintName = "pass"
|
||||||
|
ReferencedContainer = "container:pass.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "DC917BD21E2E8231000FDF54"
|
||||||
|
BuildableName = "Pass.app"
|
||||||
|
BlueprintName = "pass"
|
||||||
|
ReferencedContainer = "container:pass.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
100
pass.xcodeproj/xcshareddata/xcschemes/passExtension.xcscheme
Normal file
100
pass.xcodeproj/xcshareddata/xcschemes/passExtension.xcscheme
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "1230"
|
||||||
|
wasCreatedForAppExtension = "YES"
|
||||||
|
version = "2.0">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "A26700231EEC466A00176B8A"
|
||||||
|
BuildableName = "passExtension.appex"
|
||||||
|
BlueprintName = "passExtension"
|
||||||
|
ReferencedContainer = "container:pass.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "DC917BD21E2E8231000FDF54"
|
||||||
|
BuildableName = "Pass.app"
|
||||||
|
BlueprintName = "pass"
|
||||||
|
ReferencedContainer = "container:pass.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
|
<Testables>
|
||||||
|
</Testables>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = ""
|
||||||
|
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
|
||||||
|
launchStyle = "0"
|
||||||
|
askForAppToLaunch = "Yes"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
|
<RemoteRunnable
|
||||||
|
runnableDebuggingMode = "1"
|
||||||
|
BundleIdentifier = "com.apple.mobilesafari"
|
||||||
|
RemotePath = "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/Applications/MobileSafari.app">
|
||||||
|
</RemoteRunnable>
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "DC917BD21E2E8231000FDF54"
|
||||||
|
BuildableName = "Pass.app"
|
||||||
|
BlueprintName = "pass"
|
||||||
|
ReferencedContainer = "container:pass.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "DC917BD21E2E8231000FDF54"
|
||||||
|
BuildableName = "Pass.app"
|
||||||
|
BlueprintName = "pass"
|
||||||
|
ReferencedContainer = "container:pass.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
96
pass.xcodeproj/xcshareddata/xcschemes/passShortcuts.xcscheme
Normal file
96
pass.xcodeproj/xcshareddata/xcschemes/passShortcuts.xcscheme
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "1230"
|
||||||
|
wasCreatedForAppExtension = "YES"
|
||||||
|
version = "2.0">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "30A69944240EED5E00B7D967"
|
||||||
|
BuildableName = "passShortcuts.appex"
|
||||||
|
BlueprintName = "passShortcuts"
|
||||||
|
ReferencedContainer = "container:pass.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "DC917BD21E2E8231000FDF54"
|
||||||
|
BuildableName = "Pass.app"
|
||||||
|
BlueprintName = "pass"
|
||||||
|
ReferencedContainer = "container:pass.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
|
<Testables>
|
||||||
|
</Testables>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = ""
|
||||||
|
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
|
||||||
|
launchStyle = "0"
|
||||||
|
askForAppToLaunch = "Yes"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "DC917BD21E2E8231000FDF54"
|
||||||
|
BuildableName = "Pass.app"
|
||||||
|
BlueprintName = "pass"
|
||||||
|
ReferencedContainer = "container:pass.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "DC917BD21E2E8231000FDF54"
|
||||||
|
BuildableName = "Pass.app"
|
||||||
|
BlueprintName = "pass"
|
||||||
|
ReferencedContainer = "container:pass.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>PreviewsEnabled</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
|
@ -1,31 +1,29 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Aeb-0C-dDR">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="7M4-H6-S4B">
|
||||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
|
||||||
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
|
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<scenes>
|
<scenes>
|
||||||
<!--Password Store-->
|
<!--Password Store-->
|
||||||
<scene sceneID="Uma-9u-xWV">
|
<scene sceneID="Uma-9u-xWV">
|
||||||
<objects>
|
<objects>
|
||||||
<viewController id="Xki-Si-B7m" customClass="CredentialProviderViewController" customModule="passAutoFillExtension" customModuleProvider="target" sceneMemberID="viewController">
|
<viewController id="Xki-Si-B7m" customClass="PasswordsViewController" customModule="passAutoFillExtension" sceneMemberID="viewController">
|
||||||
<view key="view" contentMode="scaleToFill" id="BuU-Ak-iZz">
|
<view key="view" contentMode="scaleToFill" id="BuU-Ak-iZz">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="XmI-l4-SgT">
|
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="XmI-l4-SgT">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
<searchBar key="tableHeaderView" contentMode="redraw" text="" id="MmN-WX-sur">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="375" height="56"/>
|
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
|
||||||
<textInputTraits key="textInputTraits" autocorrectionType="no"/>
|
|
||||||
</searchBar>
|
|
||||||
<prototypes>
|
<prototypes>
|
||||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="passwordTableViewCell" textLabel="U0x-8f-AET" detailTextLabel="kY1-Ac-C3d" style="IBUITableViewCellStyleValue1" id="fXA-SG-IOe" customClass="PasswordDetailTitleTableViewCell" customModule="pass">
|
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="passwordTableViewCell" textLabel="U0x-8f-AET" detailTextLabel="kY1-Ac-C3d" style="IBUITableViewCellStyleValue1" id="fXA-SG-IOe" customClass="PasswordTableViewCell" customModule="passAutoFillExtension" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="84" width="375" height="43.5"/>
|
<rect key="frame" x="0.0" y="28" width="375" height="43.5"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="fXA-SG-IOe" id="KPa-Az-i6V">
|
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="fXA-SG-IOe" id="KPa-Az-i6V">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
|
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
|
||||||
|
|
@ -52,34 +50,52 @@
|
||||||
</tableView>
|
</tableView>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
<constraints>
|
|
||||||
<constraint firstAttribute="bottom" secondItem="XmI-l4-SgT" secondAttribute="bottom" id="5FB-pZ-UB8"/>
|
|
||||||
<constraint firstAttribute="trailing" secondItem="XmI-l4-SgT" secondAttribute="trailing" id="UU8-e6-4iA"/>
|
|
||||||
<constraint firstItem="XmI-l4-SgT" firstAttribute="top" secondItem="BuU-Ak-iZz" secondAttribute="top" id="cXC-1s-cMI"/>
|
|
||||||
<constraint firstItem="XmI-l4-SgT" firstAttribute="leading" secondItem="BuU-Ak-iZz" secondAttribute="leading" id="nvS-L5-BHk"/>
|
|
||||||
</constraints>
|
|
||||||
</view>
|
</view>
|
||||||
<navigationItem key="navigationItem" title="Password Store" id="apM-bN-eca">
|
<navigationItem key="navigationItem" title="Password Store" prompt="url" id="apM-bN-eca">
|
||||||
<barButtonItem key="leftBarButtonItem" style="plain" systemItem="cancel" id="zCC-lm-1xr">
|
<barButtonItem key="leftBarButtonItem" style="plain" systemItem="cancel" id="zCC-lm-1xr">
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="cancel:" destination="Xki-Si-B7m" id="3tK-C9-LKo"/>
|
<action selector="cancel:" destination="Xki-Si-B7m" id="CgJ-49-QwT"/>
|
||||||
</connections>
|
</connections>
|
||||||
</barButtonItem>
|
</barButtonItem>
|
||||||
</navigationItem>
|
</navigationItem>
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="searchBar" destination="MmN-WX-sur" id="KZk-g3-9Ox"/>
|
<outlet property="tableView" destination="XmI-l4-SgT" id="9k1-t7-Xnc"/>
|
||||||
<outlet property="tableView" destination="XmI-l4-SgT" id="2yd-Uj-96H"/>
|
|
||||||
</connections>
|
</connections>
|
||||||
</viewController>
|
</viewController>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="RwB-HB-TSk" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="RwB-HB-TSk" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="992.79999999999995" y="26.53673163418291"/>
|
<point key="canvasLocation" x="992.79999999999995" y="26.53673163418291"/>
|
||||||
</scene>
|
</scene>
|
||||||
|
<!--Credential Provider View Controller-->
|
||||||
|
<scene sceneID="Ebu-3J-rOU">
|
||||||
|
<objects>
|
||||||
|
<viewController id="7M4-H6-S4B" customClass="CredentialProviderViewController" customModule="passAutoFillExtension" customModuleProvider="target" sceneMemberID="viewController">
|
||||||
|
<view key="view" contentMode="scaleToFill" id="12l-99-QNG">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<containerView opaque="NO" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="jMU-nF-QHX">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<connections>
|
||||||
|
<segue destination="Aeb-0C-dDR" kind="embed" id="9kf-tv-qXf"/>
|
||||||
|
</connections>
|
||||||
|
</containerView>
|
||||||
|
</subviews>
|
||||||
|
<viewLayoutGuide key="safeArea" id="e5d-UG-xz5"/>
|
||||||
|
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||||
|
</view>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="9jE-qW-0uN" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="-946.39999999999998" y="26.53673163418291"/>
|
||||||
|
</scene>
|
||||||
<!--Navigation Controller-->
|
<!--Navigation Controller-->
|
||||||
<scene sceneID="mg9-JA-x9T">
|
<scene sceneID="mg9-JA-x9T">
|
||||||
<objects>
|
<objects>
|
||||||
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="Aeb-0C-dDR" sceneMemberID="viewController">
|
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="Aeb-0C-dDR" sceneMemberID="viewController">
|
||||||
<toolbarItems/>
|
<toolbarItems/>
|
||||||
|
<navigationItem key="navigationItem" id="d0b-i7-rXf"/>
|
||||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="RMW-As-go6">
|
<navigationBar key="navigationBar" contentMode="scaleToFill" id="RMW-As-go6">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
|
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
|
@ -94,4 +110,9 @@
|
||||||
<point key="canvasLocation" x="53.600000000000001" y="26.53673163418291"/>
|
<point key="canvasLocation" x="53.600000000000001" y="26.53673163418291"/>
|
||||||
</scene>
|
</scene>
|
||||||
</scenes>
|
</scenes>
|
||||||
|
<resources>
|
||||||
|
<systemColor name="systemBackgroundColor">
|
||||||
|
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
|
</systemColor>
|
||||||
|
</resources>
|
||||||
</document>
|
</document>
|
||||||
|
|
|
||||||
|
|
@ -9,208 +9,44 @@
|
||||||
import AuthenticationServices
|
import AuthenticationServices
|
||||||
import passKit
|
import passKit
|
||||||
|
|
||||||
class CredentialProviderViewController: ASCredentialProviderViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate {
|
class CredentialProviderViewController: ASCredentialProviderViewController {
|
||||||
@IBOutlet var searchBar: UISearchBar!
|
var passcodelock: PasscodeExtensionDisplay {
|
||||||
@IBOutlet var tableView: UITableView!
|
PasscodeExtensionDisplay(extensionContext: self.extensionContext)
|
||||||
|
|
||||||
private let passwordStore = PasswordStore.shared
|
|
||||||
private let keychain = AppKeychain.shared
|
|
||||||
|
|
||||||
private var searchActive = false
|
|
||||||
private var passwordsTableEntries: [PasswordTableEntry] = []
|
|
||||||
private var filteredPasswordsTableEntries: [PasswordTableEntry] = []
|
|
||||||
|
|
||||||
private lazy var passcodelock: PasscodeExtensionDisplay = {
|
|
||||||
let passcodelock = PasscodeExtensionDisplay(extensionContext: self.extensionContext)
|
|
||||||
return passcodelock
|
|
||||||
}()
|
|
||||||
|
|
||||||
/*
|
|
||||||
Prepare your UI to list available credentials for the user to choose from. The items in
|
|
||||||
'serviceIdentifiers' describe the service the user is logging in to, so your extension can
|
|
||||||
prioritize the most relevant credentials in the list.
|
|
||||||
*/
|
|
||||||
override func prepareCredentialList(for serviceIdentifiers: [ASCredentialServiceIdentifier]) {
|
|
||||||
// clean up the search bar
|
|
||||||
guard !serviceIdentifiers.isEmpty else {
|
|
||||||
searchBar.text = ""
|
|
||||||
searchBar.becomeFirstResponder()
|
|
||||||
searchBarSearchButtonClicked(searchBar)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the domain
|
var embeddedNavigationController: UINavigationController {
|
||||||
var identifier = serviceIdentifiers[0].identifier
|
children.first as! UINavigationController
|
||||||
if !identifier.hasPrefix("http://"), !identifier.hasPrefix("https://") {
|
|
||||||
identifier = "http://" + identifier
|
|
||||||
}
|
|
||||||
let url = URL(string: identifier)?.host ?? ""
|
|
||||||
|
|
||||||
// "click" search
|
|
||||||
searchBar.text = url
|
|
||||||
searchBar.becomeFirstResponder()
|
|
||||||
searchBarSearchButtonClicked(searchBar)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
var passwordsViewController: PasswordsViewController {
|
||||||
Implement this method if your extension support
|
embeddedNavigationController.viewControllers.first as! PasswordsViewController
|
||||||
s showing credentials in the QuickType bar.
|
|
||||||
When the user selects a credential from your app, this method will be called with the
|
|
||||||
ASPasswordCredentialIdentity your app has previously saved to the ASCredentialIdentityStore.
|
|
||||||
Provide the password by completing the extension request with the associated ASPasswordCredential.
|
|
||||||
If using the credential would require showing custom UI for authenticating the user, cancel
|
|
||||||
the request with error code ASExtensionError.userInteractionRequired.
|
|
||||||
|
|
||||||
override func provideCredentialWithoutUserInteraction(for credentialIdentity: ASPasswordCredentialIdentity) {
|
|
||||||
let databaseIsUnlocked = true
|
|
||||||
if (databaseIsUnlocked) {
|
|
||||||
let passwordCredential = ASPasswordCredential(user: "j_appleseed", password: "apple1234")
|
|
||||||
self.extensionContext.completeRequest(withSelectedCredential: passwordCredential, completionHandler: nil)
|
|
||||||
} else {
|
|
||||||
self.extensionContext.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain, code:ASExtensionError.userInteractionRequired.rawValue))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Implement this method if provideCredentialWithoutUserInteraction(for:) can fail with
|
|
||||||
ASExtensionError.userInteractionRequired. In this case, the system may present your extension's
|
|
||||||
UI and call this method. Show appropriate UI for authenticating the user then provide the password
|
|
||||||
by completing the extension request with the associated ASPasswordCredential.
|
|
||||||
|
|
||||||
override func prepareInterfaceToProvideCredential(for credentialIdentity: ASPasswordCredentialIdentity) {
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
@IBAction
|
|
||||||
private func cancel(_: AnyObject?) {
|
|
||||||
extensionContext.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain, code: ASExtensionError.userCanceled.rawValue))
|
|
||||||
self.dismiss(animated: true)
|
|
||||||
}
|
|
||||||
|
|
||||||
override func viewWillAppear(_ animated: Bool) {
|
|
||||||
super.viewWillAppear(animated)
|
|
||||||
passcodelock.presentPasscodeLockIfNeeded(self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
passcodelock.presentPasscodeLockIfNeeded(self)
|
||||||
|
|
||||||
// prepare
|
let passwordsTableEntries = PasswordStore.shared.fetchPasswordEntityCoreData(withDir: false).compactMap { PasswordTableEntry($0) }
|
||||||
searchBar.delegate = self
|
let dataSource = PasswordsTableDataSource(entries: passwordsTableEntries)
|
||||||
tableView.delegate = self
|
passwordsViewController.dataSource = dataSource
|
||||||
tableView.dataSource = self
|
passwordsViewController.selectionDelegate = self
|
||||||
tableView.register(UINib(nibName: "PasswordWithFolderTableViewCell", bundle: nil), forCellReuseIdentifier: "passwordWithFolderTableViewCell")
|
|
||||||
|
|
||||||
// initialize table entries
|
|
||||||
initPasswordsTableEntries()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func initPasswordsTableEntries() {
|
override func prepareCredentialList(for serviceIdentifiers: [ASCredentialServiceIdentifier]) {
|
||||||
filteredPasswordsTableEntries.removeAll()
|
let url = serviceIdentifiers.first.flatMap { URL(string: $0.identifier) }
|
||||||
|
passwordsViewController.navigationItem.prompt = url?.host
|
||||||
let passwordEntities = passwordStore.fetchPasswordEntityCoreData(withDir: false)
|
|
||||||
passwordsTableEntries = passwordEntities.compactMap {
|
|
||||||
PasswordTableEntry($0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// define cell contents
|
extension CredentialProviderViewController: PasswordSelectionDelegate {
|
||||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
func selected(password: PasswordTableEntry) {
|
||||||
let cell = tableView.dequeueReusableCell(withIdentifier: "passwordTableViewCell", for: indexPath)
|
let passwordEntity = password.passwordEntity
|
||||||
let entry = getPasswordEntry(by: indexPath)
|
|
||||||
if entry.passwordEntity.synced {
|
|
||||||
cell.textLabel?.text = entry.title
|
|
||||||
} else {
|
|
||||||
cell.textLabel?.text = "↻ \(entry.title)"
|
|
||||||
}
|
|
||||||
cell.accessoryType = .none
|
|
||||||
cell.detailTextLabel?.font = UIFont.preferredFont(forTextStyle: .footnote)
|
|
||||||
cell.detailTextLabel?.text = entry.categoryText
|
|
||||||
return cell
|
|
||||||
}
|
|
||||||
|
|
||||||
// select row -> extension returns (with username and password)
|
decryptPassword(in: self, with: passwordEntity) { password in
|
||||||
func tableView(_: UITableView, didSelectRowAt indexPath: IndexPath) {
|
let username = password.getUsernameForCompletion()
|
||||||
let entry = getPasswordEntry(by: indexPath)
|
let password = password.password
|
||||||
|
|
||||||
guard PGPAgent.shared.isPrepared else {
|
|
||||||
Utils.alert(title: "CannotCopyPassword".localize(), message: "PgpKeyNotSet.".localize(), controller: self, completion: nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let passwordEntity = entry.passwordEntity
|
|
||||||
UIImpactFeedbackGenerator(style: .medium).impactOccurred()
|
|
||||||
decryptPassword(passwordEntity: passwordEntity)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func decryptPassword(passwordEntity: PasswordEntity, keyID: String? = nil) {
|
|
||||||
DispatchQueue.global(qos: .userInteractive).async {
|
|
||||||
do {
|
|
||||||
let requestPGPKeyPassphrase = Utils.createRequestPGPKeyPassphraseHandler(controller: self)
|
|
||||||
let decryptedPassword = try self.passwordStore.decrypt(passwordEntity: passwordEntity, keyID: keyID, requestPGPKeyPassphrase: requestPGPKeyPassphrase)
|
|
||||||
|
|
||||||
let username = decryptedPassword.getUsernameForCompletion()
|
|
||||||
let password = decryptedPassword.password
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
let passwordCredential = ASPasswordCredential(user: username, password: password)
|
let passwordCredential = ASPasswordCredential(user: username, password: password)
|
||||||
self.extensionContext.completeRequest(withSelectedCredential: passwordCredential)
|
self.extensionContext.completeRequest(withSelectedCredential: passwordCredential)
|
||||||
}
|
}
|
||||||
} catch let AppError.pgpPrivateKeyNotFound(keyID: key) {
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.pgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
|
||||||
alert.addAction(UIAlertAction.cancelAndPopView(controller: self))
|
|
||||||
let selectKey = UIAlertAction.selectKey(controller: self) { action in
|
|
||||||
self.decryptPassword(passwordEntity: passwordEntity, keyID: action.title)
|
|
||||||
}
|
|
||||||
alert.addAction(selectKey)
|
|
||||||
|
|
||||||
self.present(alert, animated: true)
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
Utils.alert(title: "CannotCopyPassword".localize(), message: error.localizedDescription, controller: self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func numberOfSectionsInTableView(tableView _: UITableView) -> Int {
|
|
||||||
1
|
|
||||||
}
|
|
||||||
|
|
||||||
func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int {
|
|
||||||
if searchActive {
|
|
||||||
return filteredPasswordsTableEntries.count
|
|
||||||
}
|
|
||||||
return passwordsTableEntries.count
|
|
||||||
}
|
|
||||||
|
|
||||||
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
|
|
||||||
searchBar.text = ""
|
|
||||||
searchActive = false
|
|
||||||
tableView.reloadData()
|
|
||||||
}
|
|
||||||
|
|
||||||
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
|
|
||||||
if let searchText = searchBar.text, searchText.isEmpty == false {
|
|
||||||
filteredPasswordsTableEntries = passwordsTableEntries.filter { $0.match(searchText) }
|
|
||||||
searchActive = true
|
|
||||||
} else {
|
|
||||||
searchActive = false
|
|
||||||
}
|
|
||||||
tableView.reloadData()
|
|
||||||
}
|
|
||||||
|
|
||||||
func searchBar(_ searchBar: UISearchBar, textDidChange _: String) {
|
|
||||||
searchBarSearchButtonClicked(searchBar)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func getPasswordEntry(by indexPath: IndexPath) -> PasswordTableEntry {
|
|
||||||
if searchActive {
|
|
||||||
return filteredPasswordsTableEntries[indexPath.row]
|
|
||||||
} else {
|
|
||||||
return passwordsTableEntries[indexPath.row]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,11 @@ import passKit
|
||||||
|
|
||||||
// cancel means cancel the extension
|
// cancel means cancel the extension
|
||||||
class PasscodeLockViewControllerForExtension: PasscodeLockViewController {
|
class PasscodeLockViewControllerForExtension: PasscodeLockViewController {
|
||||||
var originalExtensionContest: ASCredentialProviderExtensionContext?
|
var originalExtensionContext: ASCredentialProviderExtensionContext!
|
||||||
|
|
||||||
convenience init(extensionContext: ASCredentialProviderExtensionContext?) {
|
convenience init(extensionContext: ASCredentialProviderExtensionContext) {
|
||||||
self.init()
|
self.init()
|
||||||
self.originalExtensionContest = extensionContext
|
self.originalExtensionContext = extensionContext
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
|
|
@ -27,7 +27,7 @@ class PasscodeLockViewControllerForExtension: PasscodeLockViewController {
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
func cancelExtension() {
|
func cancelExtension() {
|
||||||
originalExtensionContest?.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain, code: ASExtensionError.userCanceled.rawValue))
|
originalExtensionContext.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain, code: ASExtensionError.userCanceled.rawValue))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -36,7 +36,7 @@ class PasscodeExtensionDisplay {
|
||||||
private let passcodeLockVC: PasscodeLockViewControllerForExtension
|
private let passcodeLockVC: PasscodeLockViewControllerForExtension
|
||||||
private let extensionContext: ASCredentialProviderExtensionContext?
|
private let extensionContext: ASCredentialProviderExtensionContext?
|
||||||
|
|
||||||
init(extensionContext: ASCredentialProviderExtensionContext?) {
|
init(extensionContext: ASCredentialProviderExtensionContext) {
|
||||||
self.extensionContext = extensionContext
|
self.extensionContext = extensionContext
|
||||||
self.passcodeLockVC = PasscodeLockViewControllerForExtension(extensionContext: extensionContext)
|
self.passcodeLockVC = PasscodeLockViewControllerForExtension(extensionContext: extensionContext)
|
||||||
passcodeLockVC.dismissCompletionCallback = { [weak self] in
|
passcodeLockVC.dismissCompletionCallback = { [weak self] in
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
//
|
||||||
|
// PasswordsViewController.swift
|
||||||
|
// passAutoFillExtension
|
||||||
|
//
|
||||||
|
// Created by Sun, Mingshen on 12/31/20.
|
||||||
|
// Copyright © 2020 Bob Sun. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import AuthenticationServices
|
||||||
|
import passKit
|
||||||
|
|
||||||
|
class PasswordsViewController: UIViewController {
|
||||||
|
@IBOutlet var tableView: UITableView!
|
||||||
|
|
||||||
|
var dataSource: PasswordsTableDataSource!
|
||||||
|
weak var selectionDelegate: PasswordSelectionDelegate?
|
||||||
|
|
||||||
|
var searchController: UISearchController {
|
||||||
|
let uiSearchController = UISearchController(searchResultsController: nil)
|
||||||
|
uiSearchController.searchBar.isTranslucent = true
|
||||||
|
uiSearchController.obscuresBackgroundDuringPresentation = false
|
||||||
|
uiSearchController.searchBar.sizeToFit()
|
||||||
|
if #available(iOS 13.0, *) {
|
||||||
|
uiSearchController.searchBar.searchTextField.clearButtonMode = .whileEditing
|
||||||
|
}
|
||||||
|
return uiSearchController
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
navigationItem.searchController = searchController
|
||||||
|
navigationItem.hidesSearchBarWhenScrolling = false
|
||||||
|
|
||||||
|
searchController.searchBar.delegate = self
|
||||||
|
|
||||||
|
tableView.delegate = self
|
||||||
|
tableView.dataSource = dataSource
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction
|
||||||
|
private func cancel(_: AnyObject?) {
|
||||||
|
self.extensionContext?.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain, code: ASExtensionError.userCanceled.rawValue))
|
||||||
|
self.dismiss(animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension PasswordsViewController: UISearchBarDelegate {
|
||||||
|
func searchBar(_: UISearchBar, textDidChange searchText: String) {
|
||||||
|
dataSource.showTableEntries(matching: searchText)
|
||||||
|
tableView.reloadData()
|
||||||
|
}
|
||||||
|
|
||||||
|
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
|
||||||
|
searchBar.resignFirstResponder()
|
||||||
|
}
|
||||||
|
|
||||||
|
func searchBarCancelButtonClicked(_: UISearchBar) {
|
||||||
|
dataSource.showTableEntries(matching: "")
|
||||||
|
tableView.reloadData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension PasswordsViewController: UITableViewDelegate {
|
||||||
|
func tableView(_: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||||
|
tableView.deselectRow(at: indexPath, animated: true)
|
||||||
|
let entry = dataSource.filteredPasswordsTableEntries[indexPath.row]
|
||||||
|
|
||||||
|
UIImpactFeedbackGenerator(style: .medium).impactOccurred()
|
||||||
|
self.selectionDelegate?.selected(password: entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
//
|
||||||
|
// PasswordSelectionDelegate.swift
|
||||||
|
// passAutoFillExtension
|
||||||
|
//
|
||||||
|
// Created by Sun, Mingshen on 12/31/20.
|
||||||
|
// Copyright © 2020 Bob Sun. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import passKit
|
||||||
|
|
||||||
|
protocol PasswordSelectionDelegate: AnyObject {
|
||||||
|
func selected(password: PasswordTableEntry)
|
||||||
|
}
|
||||||
38
passAutoFillExtension/Services/PasswordDecryptor.swift
Normal file
38
passAutoFillExtension/Services/PasswordDecryptor.swift
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
//
|
||||||
|
// PasswordDecryptor.swift
|
||||||
|
// passAutoFillExtension
|
||||||
|
//
|
||||||
|
// Created by Sun, Mingshen on 12/31/20.
|
||||||
|
// Copyright © 2020 Bob Sun. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import passKit
|
||||||
|
|
||||||
|
func decryptPassword(in controller: UIViewController, with passwordEntity: PasswordEntity, using keyID: String? = nil, completion: @escaping ((Password) -> Void)) {
|
||||||
|
DispatchQueue.global(qos: .userInteractive).async {
|
||||||
|
do {
|
||||||
|
let requestPGPKeyPassphrase = Utils.createRequestPGPKeyPassphraseHandler(controller: controller)
|
||||||
|
let decryptedPassword = try PasswordStore.shared.decrypt(passwordEntity: passwordEntity, keyID: keyID, requestPGPKeyPassphrase: requestPGPKeyPassphrase)
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
completion(decryptedPassword)
|
||||||
|
}
|
||||||
|
} catch let AppError.pgpPrivateKeyNotFound(keyID: key) {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.pgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
||||||
|
alert.addAction(UIAlertAction.cancelAndPopView(controller: controller))
|
||||||
|
let selectKey = UIAlertAction.selectKey(controller: controller) { action in
|
||||||
|
decryptPassword(in: controller, with: passwordEntity, using: action.title, completion: completion)
|
||||||
|
}
|
||||||
|
alert.addAction(selectKey)
|
||||||
|
|
||||||
|
controller.present(alert, animated: true)
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
Utils.alert(title: "CannotCopyPassword".localize(), message: error.localizedDescription, controller: controller)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
//
|
||||||
|
// PasswordsTableDataSource.swift
|
||||||
|
// passAutoFillExtension
|
||||||
|
//
|
||||||
|
// Created by Sun, Mingshen on 12/31/20.
|
||||||
|
// Copyright © 2020 Bob Sun. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import passKit
|
||||||
|
|
||||||
|
class PasswordsTableDataSource: NSObject, UITableViewDataSource {
|
||||||
|
var passwordTableEntries: [PasswordTableEntry]
|
||||||
|
var filteredPasswordsTableEntries: [PasswordTableEntry]
|
||||||
|
|
||||||
|
init(entries: [PasswordTableEntry] = []) {
|
||||||
|
passwordTableEntries = entries
|
||||||
|
filteredPasswordsTableEntries = passwordTableEntries
|
||||||
|
}
|
||||||
|
|
||||||
|
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||||
|
filteredPasswordsTableEntries.count
|
||||||
|
}
|
||||||
|
|
||||||
|
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||||
|
let cell = tableView.dequeueReusableCell(withIdentifier: "passwordTableViewCell", for: indexPath) as! PasswordTableViewCell
|
||||||
|
|
||||||
|
let entry = filteredPasswordsTableEntries[indexPath.row]
|
||||||
|
cell.configure(with: entry)
|
||||||
|
|
||||||
|
return cell
|
||||||
|
}
|
||||||
|
|
||||||
|
func showTableEntries(matching text: String) {
|
||||||
|
guard !text.isEmpty else {
|
||||||
|
filteredPasswordsTableEntries = passwordTableEntries
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
filteredPasswordsTableEntries = passwordTableEntries.filter { $0.match(text) }
|
||||||
|
}
|
||||||
|
}
|
||||||
22
passAutoFillExtension/Views/PasswordTableViewCell.swift
Normal file
22
passAutoFillExtension/Views/PasswordTableViewCell.swift
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
//
|
||||||
|
// PasswordCell.swift
|
||||||
|
// passAutoFillExtension
|
||||||
|
//
|
||||||
|
// Created by Sun, Mingshen on 12/31/20.
|
||||||
|
// Copyright © 2020 Bob Sun. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import passKit
|
||||||
|
|
||||||
|
class PasswordTableViewCell: UITableViewCell {
|
||||||
|
func configure(with entry: PasswordTableEntry) {
|
||||||
|
if entry.passwordEntity.synced {
|
||||||
|
textLabel?.text = entry.title
|
||||||
|
} else {
|
||||||
|
textLabel?.text = "↻ \(entry.title)"
|
||||||
|
}
|
||||||
|
accessoryType = .none
|
||||||
|
detailTextLabel?.font = UIFont.preferredFont(forTextStyle: .footnote)
|
||||||
|
detailTextLabel?.text = entry.categoryText
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue