diff --git a/pass/Base.lproj/Main.storyboard b/pass/Base.lproj/Main.storyboard index 84b3c31..e9819db 100644 --- a/pass/Base.lproj/Main.storyboard +++ b/pass/Base.lproj/Main.storyboard @@ -1,5 +1,5 @@ - + @@ -31,18 +31,18 @@ - + diff --git a/pass/Controllers/PGPKeyArmorSettingTableViewController.swift b/pass/Controllers/PGPKeyArmorSettingTableViewController.swift index 16b7fd0..28f00d8 100644 --- a/pass/Controllers/PGPKeyArmorSettingTableViewController.swift +++ b/pass/Controllers/PGPKeyArmorSettingTableViewController.swift @@ -9,19 +9,102 @@ import UIKit import SwiftyUserDefaults -class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDelegate { +class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDelegate, QRScannerControllerDelegate { @IBOutlet weak var armorPublicKeyTextView: UITextView! @IBOutlet weak var armorPrivateKeyTextView: UITextView! + @IBOutlet weak var scanPublicKeyCell: UITableViewCell! + @IBOutlet weak var scanPrivateKeyCell: UITableViewCell! + var pgpPassphrase: String? let passwordStore = PasswordStore.shared private var recentPastedText = "" + class ScannedPGPKey { + static let maxNumberOfGif = 100 + enum KeyType { + case publicKey, privateKey + } + var keyType = KeyType.publicKey + var numberOfSegments = 0 + var previousSegment = "" + var key = "" + var message = "" + var hasStarted = false + var isDone = false + + func reset(keytype: KeyType) { + self.keyType = keytype + numberOfSegments = 0 + previousSegment = "" + key = "" + message = "Looking for the starting frame." + hasStarted = false + isDone = false + } + + func addSegment(segment: String) { + // skip duplicated segments + guard segment != previousSegment else { + return + } + previousSegment = segment + + // check whether we have found the first block + if hasStarted == false { + let findPublic = segment.contains("-----BEGIN PGP PUBLIC KEY BLOCK-----") + let findPrivate = segment.contains("-----BEGIN PGP PRIVATE KEY BLOCK-----") + switch keyType { + case .publicKey: + if findPrivate { + message = "Please scan public key." + } + hasStarted = findPublic + case .privateKey: + if findPublic { + message = "Please scan private key." + } + hasStarted = findPrivate + } + } + guard hasStarted == true else { + return + } + + // check the number of segments + numberOfSegments = numberOfSegments + 1 + guard numberOfSegments <= ScannedPGPKey.maxNumberOfGif else { + key = "Too many QR codes" + return + } + + // update full text and check whether we are done + key.append(segment) + if key.contains("-----END PGP PUBLIC KEY BLOCK-----") || key.contains("-----END PGP PRIVATE KEY BLOCK-----") { + isDone = true + } + + // update message + message = "\(numberOfSegments) scanned QR codes." + } + } + var scanned = ScannedPGPKey() + override func viewDidLoad() { super.viewDidLoad() armorPublicKeyTextView.text = Defaults[.pgpPublicKeyArmor] armorPrivateKeyTextView.text = Defaults[.pgpPrivateKeyArmor] pgpPassphrase = passwordStore.pgpKeyPassphrase + + scanPublicKeyCell?.textLabel?.text = "Scan Public Key QR Codes" + scanPublicKeyCell?.textLabel?.textColor = Globals.blue + scanPublicKeyCell?.selectionStyle = .default + scanPublicKeyCell?.accessoryType = .disclosureIndicator + + scanPrivateKeyCell?.textLabel?.text = "Scan Private Key QR Codes" + scanPrivateKeyCell?.textLabel?.textColor = Globals.blue + scanPrivateKeyCell?.selectionStyle = .default + scanPrivateKeyCell?.accessoryType = .disclosureIndicator } private func createSavePassphraseAndSegueAlert() -> UIAlertController { @@ -79,4 +162,53 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe } return true } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let selectedCell = tableView.cellForRow(at: indexPath) + if selectedCell == scanPublicKeyCell { + scanned.reset(keytype: ScannedPGPKey.KeyType.publicKey) + self.performSegue(withIdentifier: "showPGPScannerSegue", sender: self) + } else if selectedCell == scanPrivateKeyCell { + scanned.reset(keytype: ScannedPGPKey.KeyType.privateKey) + self.performSegue(withIdentifier: "showPGPScannerSegue", sender: self) + } + tableView.deselectRow(at: indexPath, animated: true) + } + + // MARK: - QRScannerControllerDelegate Methods + func checkScannedOutput(line: String) -> (accept: Bool, message: String) { + scanned.addSegment(segment: line) + if scanned.isDone { + return (accept: true, message: "Done") + } else { + return (accept: false, message: scanned.message) + } + } + + // MARK: - QRScannerControllerDelegate Methods + func handleScannedOutput(line: String) { + switch scanned.keyType { + case .publicKey: + armorPublicKeyTextView.text = scanned.key + case .privateKey: + armorPrivateKeyTextView.text = scanned.key + } + } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + if segue.identifier == "showPGPScannerSegue" { + if let navController = segue.destination as? UINavigationController { + if let viewController = navController.topViewController as? QRScannerController { + viewController.delegate = self + } + } else if let viewController = segue.destination as? QRScannerController { + viewController.delegate = self + } + } + } + + @IBAction private func cancelPGPScanner(segue: UIStoryboardSegue) { + + } + }