/* * Copyright (c) 2016 - 2024 Jonathan Schleifer * * https://fl.nil.im/cryptopassphrase * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ import UIKit import ObjFW import ObjFWBridge class ShowDetailsController: UITableViewController, UITextFieldDelegate { @IBOutlet var nameField: UITextField? @IBOutlet var lengthField: UITextField? @IBOutlet var legacySwitch: UISwitch? @IBOutlet var keyFileField: UITextField? @IBOutlet var passphraseField: UITextField? public var mainViewController: MainViewController? private var name: String = "" private var length: UInt = 0 private var isLegacy: Bool = false private var keyFile: String? = nil override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) guard let mainViewController = self.mainViewController else { return } guard let tableView = mainViewController.tableView else { return } let siteStorage = mainViewController.siteStorage guard let indexPath = tableView.indexPathForSelectedRow else { return } name = mainViewController.sites[indexPath.row] length = siteStorage.length(forSite: name) isLegacy = siteStorage.isLegacy(site: name) keyFile = siteStorage.keyFile(forSite: name) nameField?.text = name lengthField?.text = "\(length)" legacySwitch?.isOn = isLegacy keyFileField?.text = keyFile tableView.deselectRow(at: indexPath, animated: true) } func textFieldShouldReturn(_ textField: UITextField) -> Bool { textField.resignFirstResponder() return false } static private func clearNSMutableString(_ string: NSMutableString) { /* * NSMutableString does not offer a way to zero the string. * This is in the hope that setting a single character at an index just * replaces that character in memory, and thus allows us to zero the * password. */ for i in 0.. () ) { let generator: PasswordGenerator = isLegacy ? LegacyPasswordGenerator() : NewPasswordGenerator() generator.site = name.ofObject generator.length = size_t(length) if let keyFile = keyFile { guard let documentDirectory = NSSearchPathForDirectoriesInDomains( .documentDirectory, .userDomainMask, true).first else { print("Could not get key files: No documents directory") return } let keyFilePath = documentDirectory.ofObject.appendingPathComponent( keyFile.ofObject) generator.keyFile = OFMutableData(contentsOfFile: keyFilePath) } let passphraseText = (passphraseField?.text ?? "") as NSString let passphraseLen = passphraseText.lengthOfBytes( using: String.Encoding.utf8.rawValue) + 1 let passphrase = OFSecureData(count: passphraseLen, allowsSwappableMemory: false) memcpy(passphrase.mutableItems, passphraseText.utf8String!, passphraseLen) generator.passphrase = passphrase let mainStoryboard = UIStoryboard(name: "Main", bundle: nil) let activityController = mainStoryboard.instantiateViewController( withIdentifier: "activityIndicator") navigationController?.view.addSubview(activityController.view) DispatchQueue.global(qos: .default).async { generator.derivePassword() let password = NSMutableString( bytes: generator.output.items!, length: generator.length, encoding: String.Encoding.utf8.rawValue)! DispatchQueue.main.sync { activityController.view.isHidden = true block(password) } } } @IBAction func remove(_ sender: Any?) { let message = "Do you want to remove this site?" let alert = UIAlertController(title: "Remove Site?", message: message, preferredStyle: .alert) alert.addAction( UIAlertAction(title: "No", style: .cancel, handler: nil)) let yesAction = UIAlertAction(title: "Yes", style: .destructive) { (UIAlertAction) in self.mainViewController?.siteStorage.removeSite(self.name) self.mainViewController?.reset() self.navigationController?.popViewController(animated: true) } alert.addAction(yesAction) self.present(alert, animated: true, completion: nil) } }