diff --git a/pass.xcodeproj/project.pbxproj b/pass.xcodeproj/project.pbxproj index d1e79d3..8ae70df 100644 --- a/pass.xcodeproj/project.pbxproj +++ b/pass.xcodeproj/project.pbxproj @@ -9,7 +9,6 @@ /* Begin PBXBuildFile section */ 116F7CC922E134FA003B3BAC /* Crypto.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 116F7CC822E134FA003B3BAC /* Crypto.framework */; }; 116F7CCA22E134FA003B3BAC /* Crypto.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 116F7CC822E134FA003B3BAC /* Crypto.framework */; }; - 3005F35424B13C3E000519B5 /* ScannedPGPKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3005F35324B13C3E000519B5 /* ScannedPGPKey.swift */; }; 300713C52219D54100F553AC /* AutoCellHeightUITableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 300713C42219D54100F553AC /* AutoCellHeightUITableViewController.swift */; }; 301F6463216162550071A4CE /* AdditionField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 301F6462216162550071A4CE /* AdditionField.swift */; }; 301F6468216165290071A4CE /* ConstantsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 301F6467216165290071A4CE /* ConstantsTest.swift */; }; @@ -54,6 +53,10 @@ 306D970E24091CDD006C0E2E /* SwitchTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 306D970D24091CDD006C0E2E /* SwitchTableViewCell.swift */; }; 306D971224091EE7006C0E2E /* SwitchTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 306D971124091EE7006C0E2E /* SwitchTableViewCell.xib */; }; 3087574F2343E42A00B971A2 /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3087574E2343E42A00B971A2 /* Colors.swift */; }; + 308800C324EDA5F600E87ED3 /* QRKeyScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 308800C224EDA5F600E87ED3 /* QRKeyScanner.swift */; }; + 308800C724EDC08D00E87ED3 /* ScannableKeyType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 308800C624EDC08D00E87ED3 /* ScannableKeyType.swift */; }; + 308800CF24F04E9900E87ED3 /* ScannableKeyTypeTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 308800CE24F04E9900E87ED3 /* ScannableKeyTypeTest.swift */; }; + 308800D124F0596300E87ED3 /* QRKeyScannerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 308800D024F0596300E87ED3 /* QRKeyScannerTest.swift */; }; 308C273A2279F9CB0016D0E2 /* SearchBarScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 302202EE222F14E400555236 /* SearchBarScope.swift */; }; 30A1D29C21AF451E00E2D1F7 /* PasswordGeneratorFlavorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A1D29B21AF451E00E2D1F7 /* PasswordGeneratorFlavorTest.swift */; }; 30A1D2A221B2BC6F00E2D1F7 /* TokenBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A1D2A121B2BC6F00E2D1F7 /* TokenBuilder.swift */; }; @@ -221,6 +224,13 @@ remoteGlobalIDString = A26700231EEC466A00176B8A; remoteInfo = passExtension; }; + DC13B1531E8640810097803F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = DC917BCB1E2E8231000FDF54 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC917BD21E2E8231000FDF54; + remoteInfo = pass; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -254,7 +264,6 @@ 116F7CC822E134FA003B3BAC /* Crypto.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Crypto.framework; path = go/dist/Crypto.framework; sourceTree = ""; }; 134DA5B66070BA56678688CF /* Pods_passKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_passKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 14E955B67C88672AA3A40BA0 /* Pods_passExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_passExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 3005F35324B13C3E000519B5 /* ScannedPGPKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScannedPGPKey.swift; sourceTree = ""; }; 300713C42219D54100F553AC /* AutoCellHeightUITableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoCellHeightUITableViewController.swift; sourceTree = ""; }; 301F6462216162550071A4CE /* AdditionField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdditionField.swift; sourceTree = ""; }; 301F6467216165290071A4CE /* ConstantsTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConstantsTest.swift; sourceTree = ""; }; @@ -300,6 +309,10 @@ 306D970D24091CDD006C0E2E /* SwitchTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwitchTableViewCell.swift; sourceTree = ""; }; 306D971124091EE7006C0E2E /* SwitchTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SwitchTableViewCell.xib; sourceTree = ""; }; 3087574E2343E42A00B971A2 /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = ""; }; + 308800C224EDA5F600E87ED3 /* QRKeyScanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRKeyScanner.swift; sourceTree = ""; }; + 308800C624EDC08D00E87ED3 /* ScannableKeyType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScannableKeyType.swift; sourceTree = ""; }; + 308800CE24F04E9900E87ED3 /* ScannableKeyTypeTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScannableKeyTypeTest.swift; sourceTree = ""; }; + 308800D024F0596300E87ED3 /* QRKeyScannerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRKeyScannerTest.swift; sourceTree = ""; }; 30A1D29B21AF451E00E2D1F7 /* PasswordGeneratorFlavorTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordGeneratorFlavorTest.swift; sourceTree = ""; }; 30A1D2A121B2BC6F00E2D1F7 /* TokenBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TokenBuilder.swift; sourceTree = ""; }; 30A1D2A521B2D46100E2D1F7 /* OTPType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OTPType.swift; sourceTree = ""; }; @@ -395,6 +408,7 @@ DC037CBD1E4ED4E100609409 /* TextViewTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextViewTableViewCell.swift; sourceTree = ""; }; DC037CBE1E4ED4E100609409 /* TextViewTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TextViewTableViewCell.xib; sourceTree = ""; }; DC1208571E35EBE60042942E /* ObjectiveGit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ObjectiveGit.framework; path = Carthage/Build/iOS/ObjectiveGit.framework; sourceTree = ""; }; + DC13B14E1E8640810097803F /* passTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = passTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; DC13B1521E8640810097803F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; DC193FF91E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = AdvancedSettingsTableViewController.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; DC3E64E51E656F11009A83DE /* CommitLogsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommitLogsTableViewController.swift; sourceTree = ""; }; @@ -486,6 +500,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + DC13B14B1E8640810097803F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; DC917BD01E2E8231000FDF54 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -504,7 +525,8 @@ 3005F35224B13BF3000519B5 /* Models */ = { isa = PBXGroup; children = ( - 3005F35324B13C3E000519B5 /* ScannedPGPKey.swift */, + 308800C224EDA5F600E87ED3 /* QRKeyScanner.swift */, + 308800C624EDC08D00E87ED3 /* ScannableKeyType.swift */, ); path = Models; sourceTree = ""; @@ -554,6 +576,15 @@ path = Extensions; sourceTree = ""; }; + 308800CD24F04E6600E87ED3 /* Models */ = { + isa = PBXGroup; + children = ( + 308800D024F0596300E87ED3 /* QRKeyScannerTest.swift */, + 308800CE24F04E9900E87ED3 /* ScannableKeyTypeTest.swift */, + ); + path = Models; + sourceTree = ""; + }; 30A69946240EED5E00B7D967 /* passShortcuts */ = { isa = PBXGroup; children = ( @@ -785,6 +816,7 @@ DC13B14F1E8640810097803F /* passTests */ = { isa = PBXGroup; children = ( + 308800CD24F04E6600E87ED3 /* Models */, DC13B1521E8640810097803F /* Info.plist */, ); path = passTests; @@ -880,6 +912,7 @@ isa = PBXGroup; children = ( DC917BD31E2E8231000FDF54 /* Pass.app */, + DC13B14E1E8640810097803F /* passTests.xctest */, A26700241EEC466A00176B8A /* passExtension.appex */, A26075781EEC6F34005DB03E /* passKit.framework */, A26075801EEC6F34005DB03E /* passKitTests.xctest */, @@ -1039,6 +1072,24 @@ productReference = A26700241EEC466A00176B8A /* passExtension.appex */; productType = "com.apple.product-type.app-extension"; }; + DC13B14D1E8640810097803F /* passTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = DC13B1571E8640810097803F /* Build configuration list for PBXNativeTarget "passTests" */; + buildPhases = ( + DC13B14A1E8640810097803F /* Sources */, + DC13B14B1E8640810097803F /* Frameworks */, + DC13B14C1E8640810097803F /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + DC13B1541E8640810097803F /* PBXTargetDependency */, + ); + name = passTests; + productName = passTests; + productReference = DC13B14E1E8640810097803F /* passTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; DC917BD21E2E8231000FDF54 /* pass */ = { isa = PBXNativeTarget; buildConfigurationList = DC917BE51E2E8231000FDF54 /* Build configuration list for PBXNativeTarget "pass" */; @@ -1121,6 +1172,13 @@ }; }; }; + DC13B14D1E8640810097803F = { + CreatedOnToolsVersion = 8.3; + DevelopmentTeam = 4WDM8E95VU; + LastSwiftMigration = 1020; + ProvisioningStyle = Automatic; + TestTargetID = DC917BD21E2E8231000FDF54; + }; DC917BD21E2E8231000FDF54 = { CreatedOnToolsVersion = 8.2.1; DevelopmentTeam = 4WDM8E95VU; @@ -1155,6 +1213,7 @@ projectRoot = ""; targets = ( DC917BD21E2E8231000FDF54 /* pass */, + DC13B14D1E8640810097803F /* passTests */, A26700231EEC466A00176B8A /* passExtension */, A26075771EEC6F34005DB03E /* passKit */, A260757F1EEC6F34005DB03E /* passKitTests */, @@ -1214,6 +1273,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + DC13B14C1E8640810097803F /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; DC917BD11E2E8231000FDF54 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -1527,6 +1593,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + DC13B14A1E8640810097803F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 308800D124F0596300E87ED3 /* QRKeyScannerTest.swift in Sources */, + 308800CF24F04E9900E87ED3 /* ScannableKeyTypeTest.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; DC917BCF1E2E8231000FDF54 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1545,11 +1620,12 @@ DC4914961E434301007FF592 /* LabelTableViewCell.swift in Sources */, DC5F385B1E56AADB00C69ACA /* PGPKeyArmorImportTableViewController.swift in Sources */, DCAAF7451E2FA66800AB94BC /* SettingsTableViewController.swift in Sources */, - 3005F35424B13C3E000519B5 /* ScannedPGPKey.swift in Sources */, DCFB77A71E502DF9008DE471 /* EditPasswordTableViewController.swift in Sources */, DCA0499A1E335CC800522E8F /* GitRepositorySettingsTableViewController.swift in Sources */, DCDDEAB31E4896BF00F68193 /* PasswordDetailTitleTableViewCell.swift in Sources */, A2A7813F1E97DBD9001311F5 /* QRScannerController.swift in Sources */, + 308800C724EDC08D00E87ED3 /* ScannableKeyType.swift in Sources */, + 308800C324EDA5F600E87ED3 /* QRKeyScanner.swift in Sources */, DC4914991E434600007FF592 /* PasswordDetailTableViewController.swift in Sources */, 30C25DD821F4834D00BB27BB /* UICodeHighlightingLabel.swift in Sources */, DC962CDF1E4B62C10033B5D8 /* AboutTableViewController.swift in Sources */, @@ -1616,6 +1692,11 @@ target = A26700231EEC466A00176B8A /* passExtension */; targetProxy = A267002C1EEC466A00176B8A /* PBXContainerItemProxy */; }; + DC13B1541E8640810097803F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC917BD21E2E8231000FDF54 /* pass */; + targetProxy = DC13B1531E8640810097803F /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -1847,6 +1928,25 @@ }; name = Beta; }; + 9A1EF0AD24C4EB280074FEAC /* Beta */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + DEVELOPMENT_TEAM = 4WDM8E95VU; + FRAMEWORK_SEARCH_PATHS = "$(inherited)"; + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = passTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER).passTests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Pass.app/Pass"; + }; + name = Beta; + }; 9A1EF0AE24C4EB280074FEAC /* Beta */ = { isa = XCBuildConfiguration; baseConfigurationReference = C4C702DBCBA2374D32295603 /* Pods-passExtension.beta.xcconfig */; @@ -2248,6 +2348,44 @@ }; name = Release; }; + DC13B1551E8640810097803F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + DEVELOPMENT_TEAM = 4WDM8E95VU; + FRAMEWORK_SEARCH_PATHS = "$(inherited)"; + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = passTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER).passTests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Pass.app/Pass"; + }; + name = Debug; + }; + DC13B1561E8640810097803F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + DEVELOPMENT_TEAM = 4WDM8E95VU; + FRAMEWORK_SEARCH_PATHS = "$(inherited)"; + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = passTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER).passTests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Pass.app/Pass"; + }; + name = Release; + }; DC917BE31E2E8231000FDF54 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -2508,6 +2646,16 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + DC13B1571E8640810097803F /* Build configuration list for PBXNativeTarget "passTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DC13B1551E8640810097803F /* Debug */, + DC13B1561E8640810097803F /* Release */, + 9A1EF0AD24C4EB280074FEAC /* Beta */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; DC917BCE1E2E8231000FDF54 /* Build configuration list for PBXProject "pass" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/pass/Controllers/PGPKeyArmorImportTableViewController.swift b/pass/Controllers/PGPKeyArmorImportTableViewController.swift index 242db71..8376538 100644 --- a/pass/Controllers/PGPKeyArmorImportTableViewController.swift +++ b/pass/Controllers/PGPKeyArmorImportTableViewController.swift @@ -15,10 +15,10 @@ class PGPKeyArmorImportTableViewController: AutoCellHeightUITableViewController, @IBOutlet var scanPublicKeyCell: UITableViewCell! @IBOutlet var scanPrivateKeyCell: UITableViewCell! - var armorPublicKey: String? - var armorPrivateKey: String? + private var armorPublicKey: String? + private var armorPrivateKey: String? - var scanned = ScannedPGPKey() + private var scanner = QRKeyScanner(keyType: .pgpPublic) override func viewDidLoad() { super.viewDidLoad() @@ -50,9 +50,9 @@ class PGPKeyArmorImportTableViewController: AutoCellHeightUITableViewController, override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let selectedCell = tableView.cellForRow(at: indexPath) if selectedCell == scanPublicKeyCell { - scanned.reset(keytype: ScannedPGPKey.KeyType.publicKey) + scanner = QRKeyScanner(keyType: .pgpPublic) } else if selectedCell == scanPrivateKeyCell { - scanned.reset(keytype: ScannedPGPKey.KeyType.privateKey) + scanner = QRKeyScanner(keyType: .pgpPrivate) } performSegue(withIdentifier: "showPGPScannerSegue", sender: self) tableView.deselectRow(at: indexPath, animated: true) @@ -60,19 +60,21 @@ class PGPKeyArmorImportTableViewController: AutoCellHeightUITableViewController, // MARK: - QRScannerControllerDelegate Methods - func checkScannedOutput(line: String) -> (accept: Bool, message: String) { - return scanned.addSegment(segment: line) + func checkScannedOutput(line: String) -> (accepted: Bool, message: String) { + scanner.add(segment: line).unrolled } // MARK: - QRScannerControllerDelegate Methods func handleScannedOutput(line _: String) { - let key = scanned.segments.joined() - switch scanned.keyType { - case .publicKey: + let key = scanner.scannedKey + switch scanner.keyType { + case .pgpPublic: armorPublicKeyTextView.text += key - case .privateKey: + case .pgpPrivate: armorPrivateKeyTextView.text += key + default: + return } } diff --git a/pass/Controllers/PasswordEditorTableViewController.swift b/pass/Controllers/PasswordEditorTableViewController.swift index 0d2a9b5..842575b 100644 --- a/pass/Controllers/PasswordEditorTableViewController.swift +++ b/pass/Controllers/PasswordEditorTableViewController.swift @@ -416,11 +416,11 @@ extension PasswordEditorTableViewController: PasswordSettingSliderTableViewCellD // MARK: - QRScannerControllerDelegate extension PasswordEditorTableViewController: QRScannerControllerDelegate { - func checkScannedOutput(line: String) -> (accept: Bool, message: String) { + func checkScannedOutput(line: String) -> (accepted: Bool, message: String) { if let url = URL(string: line), Token(url: url) != nil { - return (accept: true, message: "ValidTokenUrl".localize()) + return (true, "ValidTokenUrl".localize()) } - return (accept: false, message: "InvalidTokenUrl".localize()) + return (false, "InvalidTokenUrl".localize()) } func handleScannedOutput(line: String) { diff --git a/pass/Controllers/QRScannerController.swift b/pass/Controllers/QRScannerController.swift index 408ccf0..9e0f05e 100644 --- a/pass/Controllers/QRScannerController.swift +++ b/pass/Controllers/QRScannerController.swift @@ -13,7 +13,7 @@ import SVProgressHUD import UIKit protocol QRScannerControllerDelegate: AnyObject { - func checkScannedOutput(line: String) -> (accept: Bool, message: String) + func checkScannedOutput(line: String) -> (accepted: Bool, message: String) func handleScannedOutput(line: String) } @@ -107,13 +107,13 @@ class QRScannerController: UIViewController, AVCaptureMetadataOutputObjectsDeleg scannerOutput.text = "NoStringValue".localize() return } - guard let (accept, message) = delegate?.checkScannedOutput(line: scanned) else { + guard let (accepted, message) = delegate?.checkScannedOutput(line: scanned) else { // no delegate, show the scanned result scannerOutput.text = scanned return } scannerOutput.text = message - guard accept else { + guard accepted else { return } captureSession?.stopRunning() diff --git a/pass/Controllers/SSHKeyArmorImportTableViewController.swift b/pass/Controllers/SSHKeyArmorImportTableViewController.swift index c702e58..7822b35 100644 --- a/pass/Controllers/SSHKeyArmorImportTableViewController.swift +++ b/pass/Controllers/SSHKeyArmorImportTableViewController.swift @@ -13,42 +13,10 @@ class SSHKeyArmorImportTableViewController: AutoCellHeightUITableViewController, @IBOutlet var armorPrivateKeyTextView: UITextView! @IBOutlet var scanPrivateKeyCell: UITableViewCell! - var gitSSHPrivateKeyPassphrase: String? - var armorPrivateKey: String? + private var gitSSHPrivateKeyPassphrase: String? + private var armorPrivateKey: String? - class ScannedSSHKey { - var segments = [String]() - var message = "" - - func reset() { - segments.removeAll() - message = "LookingForStartingFrame.".localize() - } - - func addSegment(segment: String) -> (accept: Bool, message: String) { - // Skip duplicated segments. - guard segment != segments.last else { - return (accept: false, message: message) - } - - // Check whether we have found the first block. - guard !segments.isEmpty || segment.contains("-----BEGIN") else { - return (accept: false, message: message) - } - - // Update the list of scanned segment and return. - segments.append(segment) - if segment.range(of: "-----END.*KEY-----", options: .regularExpression, range: nil, locale: nil) != nil { - message = "Done".localize() - return (accept: true, message: message) - } else { - message = "ScannedQrCodes(%d)".localize(segments.count) - return (accept: false, message: message) - } - } - } - - var scanned = ScannedSSHKey() + private var scanner = QRKeyScanner(keyType: .sshPrivate) override func viewDidLoad() { super.viewDidLoad() @@ -76,7 +44,7 @@ class SSHKeyArmorImportTableViewController: AutoCellHeightUITableViewController, override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let selectedCell = tableView.cellForRow(at: indexPath) if selectedCell == scanPrivateKeyCell { - scanned.reset() + scanner = QRKeyScanner(keyType: .sshPrivate) performSegue(withIdentifier: "showSSHScannerSegue", sender: self) } tableView.deselectRow(at: indexPath, animated: true) @@ -84,14 +52,14 @@ class SSHKeyArmorImportTableViewController: AutoCellHeightUITableViewController, // MARK: - QRScannerControllerDelegate Methods - func checkScannedOutput(line: String) -> (accept: Bool, message: String) { - return scanned.addSegment(segment: line) + func checkScannedOutput(line: String) -> (accepted: Bool, message: String) { + scanner.add(segment: line).unrolled } // MARK: - QRScannerControllerDelegate Methods func handleScannedOutput(line _: String) { - armorPrivateKeyTextView.text = scanned.segments.joined() + armorPrivateKeyTextView.text = scanner.scannedKey } override func prepare(for segue: UIStoryboardSegue, sender _: Any?) { diff --git a/pass/Models/QRKeyScanner.swift b/pass/Models/QRKeyScanner.swift new file mode 100644 index 0000000..fbb74b2 --- /dev/null +++ b/pass/Models/QRKeyScanner.swift @@ -0,0 +1,73 @@ +// +// QRKeyScanner.swift +// pass +// +// Created by Danny Moesch on 19.08.20. +// Copyright © 2020 Bob Sun. All rights reserved. +// + +struct QRKeyScanner { + enum Result: Equatable { + case lookingForStart + case wrongKeyType(ScannableKeyType) + case completed + case scanned(Int) + + var message: String { + switch self { + case .lookingForStart: + return "LookingForStartingFrame.".localize() + case let .wrongKeyType(keyType): + return "Scan\(keyType.visibility)Key.".localize() + case .completed: + return "Done".localize() + case let .scanned(count): + return "ScannedQrCodes(%d)".localize(count) + } + } + + var unrolled: (accepted: Bool, message: String) { + if self == .completed { + return (true, message) + } + return (false, message) + } + } + + private var segments = [String]() + private var previousResult = Result.lookingForStart + + let keyType: ScannableKeyType + + init(keyType: ScannableKeyType) { + self.keyType = keyType + } + + var scannedKey: String { + segments.joined() + } + + mutating func add(segment: String) -> Result { + // Skip duplicated segments. + guard segment != segments.last else { + return previousResult + } + + // Check whether we have found the first block. + guard !segments.isEmpty || segment.contains(keyType.headerStart) else { + // Check whether we are scanning the wrong key type. + if let counterKeyType = keyType.counterType, segment.contains(counterKeyType.headerStart) { + previousResult = .wrongKeyType(counterKeyType) + } + return previousResult + } + + // Update the list of scanned segments and return. + segments.append(segment) + if segment.starts(with: keyType.footerStart), segment.hasSuffix(keyType.footerEnd) { + return .completed + } + previousResult = .scanned(segments.count) + return previousResult + } +} diff --git a/pass/Models/ScannableKeyType.swift b/pass/Models/ScannableKeyType.swift new file mode 100644 index 0000000..9009e9c --- /dev/null +++ b/pass/Models/ScannableKeyType.swift @@ -0,0 +1,60 @@ +// +// ScannableKeyType.swift +// pass +// +// Created by Danny Moesch on 19.08.20. +// Copyright © 2020 Bob Sun. All rights reserved. +// + +enum ScannableKeyType { + case pgpPublic + case pgpPrivate + case sshPrivate + + var visibility: String { + switch self { + case .pgpPublic: + return "Public" + case .pgpPrivate, .sshPrivate: + return "Private" + } + } + + var headerStart: String { + switch self { + case .pgpPublic, .pgpPrivate: + return "-----BEGIN PGP \(visibility.uppercased()) KEY BLOCK-----" + case .sshPrivate: + return "-----BEGIN" + } + } + + var footerStart: String { + switch self { + case .pgpPublic, .pgpPrivate: + return "-----END PGP \(visibility.uppercased())" + case .sshPrivate: + return "-----END" + } + } + + var footerEnd: String { + switch self { + case .pgpPublic, .pgpPrivate: + return "KEY BLOCK-----" + case .sshPrivate: + return "KEY-----" + } + } + + var counterType: Self? { + switch self { + case .pgpPublic: + return .pgpPrivate + case .pgpPrivate: + return .pgpPublic + case .sshPrivate: + return nil + } + } +} diff --git a/pass/Models/ScannedPGPKey.swift b/pass/Models/ScannedPGPKey.swift deleted file mode 100644 index d0d7ccf..0000000 --- a/pass/Models/ScannedPGPKey.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// ScannedPGPKey.swift -// pass -// -// Created by Danny Moesch on 05.07.20. -// Copyright © 2020 Bob Sun. All rights reserved. -// - -class ScannedPGPKey { - enum KeyType { - case publicKey, privateKey - } - - var keyType = KeyType.publicKey - var segments = [String]() - var message = "" - - func reset(keytype: KeyType) { - keyType = keytype - segments.removeAll() - message = "LookingForStartingFrame.".localize() - } - - func addSegment(segment: String) -> (accept: Bool, message: String) { - let keyTypeStr = keyType == .publicKey ? "Public" : "Private" - let theOtherKeyTypeStr = keyType == .publicKey ? "Private" : "Public" - - // Skip duplicated segments. - guard segment != segments.last else { - return (accept: false, message: message) - } - - // Check whether we have found the first block. - guard !segments.isEmpty || segment.contains("-----BEGIN PGP \(keyTypeStr.uppercased()) KEY BLOCK-----") else { - // Check whether we are scanning the wrong key type. - if segment.contains("-----BEGIN PGP \(theOtherKeyTypeStr.uppercased()) KEY BLOCK-----") { - message = "Scan\(keyTypeStr)Key.".localize() - } - return (accept: false, message: message) - } - - // Update the list of scanned segment and return. - segments.append(segment) - if segment.contains("-----END PGP \(keyTypeStr.uppercased()) KEY BLOCK-----") { - message = "Done".localize() - return (accept: true, message: message) - } else { - message = "ScannedQrCodes(%d)".localize(segments.count) - return (accept: false, message: message) - } - } -} diff --git a/passTests/Models/QRKeyScannerTest.swift b/passTests/Models/QRKeyScannerTest.swift new file mode 100644 index 0000000..a497799 --- /dev/null +++ b/passTests/Models/QRKeyScannerTest.swift @@ -0,0 +1,51 @@ +// +// QRKeyScannerTest.swift +// passTests +// +// Created by Danny Moesch on 21.08.20. +// Copyright © 2020 Bob Sun. All rights reserved. +// + +import XCTest + +@testable import Pass + +class QRKeyScannerTest: XCTestCase { + let header = "-----BEGIN PGP PUBLIC KEY BLOCK-----" + let body = "key body" + let footer = "-----END PGP PUBLIC KEY BLOCK-----" + let privateHeader = "-----BEGIN PGP PRIVATE KEY BLOCK-----" + + var scanner = QRKeyScanner(keyType: .pgpPublic) + + func testAddHeaderTwice() { + XCTAssertEqual(scanner.add(segment: header), .scanned(1)) + XCTAssertEqual(scanner.add(segment: header), .scanned(1)) + XCTAssertEqual(scanner.scannedKey, header) + } + + func testAddBodyTwice() { + XCTAssertEqual(scanner.add(segment: header), .scanned(1)) + XCTAssertEqual(scanner.add(segment: body), .scanned(2)) + XCTAssertEqual(scanner.add(segment: body), .scanned(2)) + XCTAssertEqual(scanner.scannedKey, header + body) + } + + func testAddCompleteBlock() { + XCTAssertEqual(scanner.add(segment: header), .scanned(1)) + XCTAssertEqual(scanner.add(segment: footer), .completed) + XCTAssertEqual(scanner.scannedKey, header + footer) + } + + func testCounterKeyType() { + XCTAssertEqual(scanner.add(segment: privateHeader), .wrongKeyType(.pgpPrivate)) + XCTAssertEqual(scanner.add(segment: privateHeader), .wrongKeyType(.pgpPrivate)) + XCTAssertTrue(scanner.scannedKey.isEmpty) + } + + func testUnknownKeyType() { + XCTAssertEqual(scanner.add(segment: body), .lookingForStart) + XCTAssertEqual(scanner.add(segment: body), .lookingForStart) + XCTAssertTrue(scanner.scannedKey.isEmpty) + } +} diff --git a/passTests/Models/ScannableKeyTypeTest.swift b/passTests/Models/ScannableKeyTypeTest.swift new file mode 100644 index 0000000..e53c8a6 --- /dev/null +++ b/passTests/Models/ScannableKeyTypeTest.swift @@ -0,0 +1,43 @@ +// +// ScannableKeyTypeTest.swift +// passTests +// +// Created by Danny Moesch on 21.08.20. +// Copyright © 2020 Bob Sun. All rights reserved. +// + +import XCTest + +@testable import Pass + +class ScannableKeyTypeTest: XCTestCase { + func testPGPPublicKey() { + let type = ScannableKeyType.pgpPublic + + XCTAssertEqual(type.visibility, "Public") + XCTAssertEqual(type.headerStart, "-----BEGIN PGP PUBLIC KEY BLOCK-----") + XCTAssertEqual(type.footerStart, "-----END PGP PUBLIC") + XCTAssertEqual(type.footerEnd, "KEY BLOCK-----") + XCTAssertEqual(type.counterType, .pgpPrivate) + } + + func testPGPPrivateKey() { + let type = ScannableKeyType.pgpPrivate + + XCTAssertEqual(type.visibility, "Private") + XCTAssertEqual(type.headerStart, "-----BEGIN PGP PRIVATE KEY BLOCK-----") + XCTAssertEqual(type.footerStart, "-----END PGP PRIVATE") + XCTAssertEqual(type.footerEnd, "KEY BLOCK-----") + XCTAssertEqual(type.counterType, .pgpPublic) + } + + func testSSHPrivateKey() { + let type = ScannableKeyType.sshPrivate + + XCTAssertEqual(type.visibility, "Private") + XCTAssertEqual(type.headerStart, "-----BEGIN") + XCTAssertEqual(type.footerStart, "-----END") + XCTAssertEqual(type.footerEnd, "KEY-----") + XCTAssertNil(type.counterType) + } +}