Merge pull request #358 from SimplyDanny/some-polishing

Some polishing
This commit is contained in:
Yishi Lin 2020-02-23 21:39:42 +08:00 committed by GitHub
commit 6b3ce819db
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 130 additions and 102 deletions

View file

@ -50,7 +50,7 @@
30697C5F21F674800064FCAC /* String+UtilitiesTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30697C5E21F674800064FCAC /* String+UtilitiesTest.swift */; };
3087574F2343E42A00B971A2 /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3087574E2343E42A00B971A2 /* Colors.swift */; };
308C273A2279F9CB0016D0E2 /* SearchBarScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 302202EE222F14E400555236 /* SearchBarScope.swift */; };
30A1D29C21AF451E00E2D1F7 /* PasswordGeneratorFlavourTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A1D29B21AF451E00E2D1F7 /* PasswordGeneratorFlavourTest.swift */; };
30A1D29C21AF451E00E2D1F7 /* PasswordGeneratorFlavorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A1D29B21AF451E00E2D1F7 /* PasswordGeneratorFlavorTest.swift */; };
30A1D2A221B2BC6F00E2D1F7 /* TokenBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A1D2A121B2BC6F00E2D1F7 /* TokenBuilder.swift */; };
30A1D2A621B2D46100E2D1F7 /* OtpType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A1D2A521B2D46100E2D1F7 /* OtpType.swift */; };
30A1D2A821B2D53200E2D1F7 /* PasswordChange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A1D2A721B2D53200E2D1F7 /* PasswordChange.swift */; };
@ -274,7 +274,7 @@
30697C5221F63E0B0064FCAC /* CredentialProviderViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CredentialProviderViewController.swift; sourceTree = "<group>"; };
30697C5E21F674800064FCAC /* String+UtilitiesTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+UtilitiesTest.swift"; sourceTree = "<group>"; };
3087574E2343E42A00B971A2 /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = "<group>"; };
30A1D29B21AF451E00E2D1F7 /* PasswordGeneratorFlavourTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordGeneratorFlavourTest.swift; sourceTree = "<group>"; };
30A1D29B21AF451E00E2D1F7 /* PasswordGeneratorFlavorTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordGeneratorFlavorTest.swift; sourceTree = "<group>"; };
30A1D2A121B2BC6F00E2D1F7 /* TokenBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TokenBuilder.swift; sourceTree = "<group>"; };
30A1D2A521B2D46100E2D1F7 /* OtpType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OtpType.swift; sourceTree = "<group>"; };
30A1D2A721B2D53200E2D1F7 /* PasswordChange.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasswordChange.swift; sourceTree = "<group>"; };
@ -460,7 +460,7 @@
301F6464216164670071A4CE /* Helpers */ = {
isa = PBXGroup;
children = (
30A1D29B21AF451E00E2D1F7 /* PasswordGeneratorFlavourTest.swift */,
30A1D29B21AF451E00E2D1F7 /* PasswordGeneratorFlavorTest.swift */,
3032328922C9FBA2009EBD9C /* KeyFileManagerTest.swift */,
);
path = Helpers;
@ -1362,7 +1362,7 @@
30BAC8C722E3BAAF00438475 /* TestPGPKeys.swift in Sources */,
30A1D2AA21B32A0100E2D1F7 /* OtpTypeTest.swift in Sources */,
301F6468216165290071A4CE /* ConstantsTest.swift in Sources */,
30A1D29C21AF451E00E2D1F7 /* PasswordGeneratorFlavourTest.swift in Sources */,
30A1D29C21AF451E00E2D1F7 /* PasswordGeneratorFlavorTest.swift in Sources */,
A26075881EEC6F34005DB03E /* passKitTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View file

@ -19,11 +19,9 @@ enum PasswordEditorCellKey {
case type, title, content, placeholders
}
class PasswordEditorTableViewController: UITableViewController, FillPasswordTableViewCellDelegate, PasswordSettingSliderTableViewCellDelegate, QRScannerControllerDelegate, UITextFieldDelegate, UITextViewDelegate, SFSafariViewControllerDelegate {
class PasswordEditorTableViewController: UITableViewController {
var tableData = [
[Dictionary<PasswordEditorCellKey, Any>]
]()
var tableData = [[Dictionary<PasswordEditorCellKey, Any>]]()
var password: Password?
private var navigationItemTitle: String?
@ -90,20 +88,26 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 48
self.tableView.sectionFooterHeight = UITableView.automaticDimension
self.tableView.estimatedSectionFooterHeight = 0
tableView.sectionFooterHeight = UITableView.automaticDimension
tableView.estimatedSectionFooterHeight = 0
tableData = [
[[.type: PasswordEditorCellType.nameCell, .title: "Name".localize(), .content: password?.namePath ?? ""]],
[
[.type: PasswordEditorCellType.fillPasswordCell, .title: "Password".localize(), .content: password?.password ?? ""]],
[[.type: PasswordEditorCellType.additionsCell, .title: "Additions".localize(), .content: password?.additionsPlainText ?? ""]],
[[.type: PasswordEditorCellType.scanQRCodeCell],
[.type: PasswordEditorCellType.deletePasswordCell]]
[.type: PasswordEditorCellType.nameCell, .title: "Name".localize(), .content: password?.namePath ?? ""],
],
[
[.type: PasswordEditorCellType.fillPasswordCell, .title: "Password".localize(), .content: password?.password ?? ""],
[.type: PasswordEditorCellType.passwordLengthCell, .title: "passwordlength"],
[.type: PasswordEditorCellType.passwordFlavorCell],
],
[
[.type: PasswordEditorCellType.additionsCell, .title: "Additions".localize(), .content: password?.additionsPlainText ?? ""],
],
[
[.type: PasswordEditorCellType.scanQRCodeCell],
[.type: PasswordEditorCellType.deletePasswordCell],
]
]
tableData[1].append([.type: PasswordEditorCellType.passwordLengthCell, .title: "passwordlength"])
tableData[1].append([.type: PasswordEditorCellType.passwordFlavorCell])
}
override func viewDidLayoutSubviews() {
@ -203,7 +207,7 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
}
}
func showPasswordGeneratorFlavorActionSheet(sourceCell: UITableViewCell, tableView: UITableView) {
private func showPasswordGeneratorFlavorActionSheet(sourceCell: UITableViewCell, tableView: UITableView) {
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
PasswordGeneratorFlavor.allCases.forEach { flavor in
@ -226,23 +230,8 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
self.present(optionMenu, animated: true, completion: nil)
}
// generate password, copy to pasteboard, and set the cell
// check whether the current password looks like an OTP field
func generateAndCopyPassword() {
if let currentPassword = fillPasswordCell?.getContent(), Constants.isOtpRelated(line: currentPassword) {
let alert = UIAlertController(title: "Overwrite?".localize(), message: "OverwriteOtpConfiguration?".localize(), preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "Yes".localize(), style: UIAlertAction.Style.destructive, handler: {_ in
self.generateAndCopyPasswordNoOtpCheck()
}))
alert.addAction(UIAlertAction(title: "Cancel".localize(), style: UIAlertAction.Style.cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
} else {
self.generateAndCopyPasswordNoOtpCheck()
}
}
// generate the password, don't care whether the original line is otp
func generateAndCopyPasswordNoOtpCheck() {
private func generateAndCopyPasswordNoOtpCheck() {
// show password settings (e.g., the length slider)
showPasswordSettings()
@ -257,20 +246,14 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
}
// show password settings (e.g., the length slider)
func showPasswordSettings() {
private func showPasswordSettings() {
if hidePasswordSettings == true {
hidePasswordSettings = false
tableView.reloadSections([passwordSection], with: .fade)
}
}
// show/hide password settings (e.g., the length slider)
func showHidePasswordSettings() {
hidePasswordSettings = !hidePasswordSettings
tableView.reloadSections([passwordSection], with: .fade)
}
func insertScannedOTPFields(_ otpauth: String) {
private func insertScannedOTPFields(_ otpauth: String) {
// update tableData
var additionsString = ""
if let additionsPlainText = (tableData[additionsSection][0][PasswordEditorCellKey.content] as? String)?.trimmed, additionsPlainText != "" {
@ -284,20 +267,6 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
additionsCell?.setContent(content: additionsString)
}
// MARK: - QRScannerControllerDelegate Methods
func checkScannedOutput(line: String) -> (accept: Bool, message: String) {
if let url = URL(string: line), let _ = Token(url: url) {
return (accept: true, message: "ValidTokenUrl".localize())
} else {
return (accept: false, message: "InvalidTokenUrl".localize())
}
}
// MARK: - QRScannerControllerDelegate Methods
func handleScannedOutput(line: String) {
insertScannedOTPFields(line)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showQRScannerSegue" {
if let navController = segue.destination as? UINavigationController {
@ -310,31 +279,6 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
}
}
// update tableData so to make sure reloadData() works correctly
func textFieldDidEndEditing(_ textField: UITextField) {
if textField == nameCell?.contentTextField {
tableData[nameSection][0][PasswordEditorCellKey.content] = nameCell?.getContent()
} else if textField == fillPasswordCell?.contentTextField {
if let plainPassword = fillPasswordCell?.getContent() {
tableData[passwordSection][0][PasswordEditorCellKey.content] = plainPassword
}
}
}
// update tableData so to make sure reloadData() works correctly
func textViewDidEndEditing(_ textView: UITextView) {
if textView == additionsCell?.contentTextView {
tableData[additionsSection][0][PasswordEditorCellKey.content] = additionsCell?.getContent()
}
}
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField == fillPasswordCell?.contentTextField {
// show password generation settings automatically
showPasswordSettings()
}
}
func getNameURL() -> (String, URL) {
let encodedName = (nameCell?.getContent()?.stringByAddingPercentEncodingForRFC3986())!
let name = URL(string: encodedName)!.lastPathComponent
@ -375,6 +319,54 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
return true
}
}
// MARK: - FillPasswordTableViewCellDelegate
extension PasswordEditorTableViewController: FillPasswordTableViewCellDelegate {
// generate password, copy to pasteboard, and set the cell
// check whether the current password looks like an OTP field
func generateAndCopyPassword() {
if let currentPassword = fillPasswordCell?.getContent(), Constants.isOtpRelated(line: currentPassword) {
let alert = UIAlertController(title: "Overwrite?".localize(), message: "OverwriteOtpConfiguration?".localize(), preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "Yes".localize(), style: UIAlertAction.Style.destructive, handler: {_ in
self.generateAndCopyPasswordNoOtpCheck()
}))
alert.addAction(UIAlertAction(title: "Cancel".localize(), style: UIAlertAction.Style.cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
} else {
self.generateAndCopyPasswordNoOtpCheck()
}
}
// show/hide password settings (e.g., the length slider)
func showHidePasswordSettings() {
hidePasswordSettings = !hidePasswordSettings
tableView.reloadSections([passwordSection], with: .fade)
}
}
// MARK: - PasswordSettingSliderTableViewCellDelegate
extension PasswordEditorTableViewController: PasswordSettingSliderTableViewCellDelegate {}
// MARK: - QRScannerControllerDelegate
extension PasswordEditorTableViewController: QRScannerControllerDelegate {
func checkScannedOutput(line: String) -> (accept: Bool, message: String) {
if let url = URL(string: line), let _ = Token(url: url) {
return (accept: true, message: "ValidTokenUrl".localize())
} else {
return (accept: false, message: "InvalidTokenUrl".localize())
}
}
func handleScannedOutput(line: String) {
insertScannedOTPFields(line)
}
}
// MARK: - SFSafariViewControllerDelegate
extension PasswordEditorTableViewController: SFSafariViewControllerDelegate {
func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
let copiedLinesSplit = UIPasteboard.general.string?.components(separatedBy: CharacterSet.whitespacesAndNewlines).filter({ !$0.isEmpty })
@ -395,3 +387,36 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
}
}
}
// MARK: - UITextFieldDelegate
extension PasswordEditorTableViewController: UITextFieldDelegate {
// update tableData so to make sure reloadData() works correctly
func textFieldDidEndEditing(_ textField: UITextField) {
if textField == nameCell?.contentTextField {
tableData[nameSection][0][PasswordEditorCellKey.content] = nameCell?.getContent()
} else if textField == fillPasswordCell?.contentTextField {
if let plainPassword = fillPasswordCell?.getContent() {
tableData[passwordSection][0][PasswordEditorCellKey.content] = plainPassword
}
}
}
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField == fillPasswordCell?.contentTextField {
// show password generation settings automatically
showPasswordSettings()
}
}
}
// MARK: - UITextViewDelegate
extension PasswordEditorTableViewController: UITextViewDelegate {
// update tableData so to make sure reloadData() works correctly
func textViewDidEndEditing(_ textView: UITextView) {
if textView == additionsCell?.contentTextView {
tableData[additionsSection][0][PasswordEditorCellKey.content] = additionsCell?.getContent()
}
}
}

View file

@ -51,6 +51,8 @@
"Random" = "Zufällig";
"RandomString" = "Zufällige Zeichenkette";
"ApplesKeychainStyle" = "Apples Keychain-Style";
"XKCD" = "XKCD";
"XKCDStyle" = "XKCD-Style";
// Git
"FailedToFetchPasswords" = "Abrufen von Passwörtern fehlgeschlagen";

View file

@ -19,6 +19,7 @@ public enum GitAuthenticationMethod: String, DefaultsSerializable {
case password, key
}
extension SearchBarScope: DefaultsSerializable {}
extension PasswordGeneratorFlavor: DefaultsSerializable {}
public extension DefaultsKeys {

View file

@ -1,5 +1,5 @@
//
// PasswordGeneratorFlavour.swift
// PasswordGeneratorFlavor.swift
// passKit
//
// Created by Danny Moesch on 28.11.18.
@ -13,6 +13,20 @@ public enum PasswordGeneratorFlavor: String {
case random = "Random"
case xkcd = "XKCD"
private static let words: [String] = {
let bundle = Bundle(identifier: Globals.passKitBundleIdentifier)!
return ["eff_long_wordlist", "eff_short_wordlist"]
.map { name -> String in
guard let asset = NSDataAsset(name: name, bundle: bundle),
let data = String(data: asset.data, encoding: .utf8) else {
return ""
}
return data
}
.joined(separator: "\n")
.splitByNewline()
}()
public var localized: String {
return rawValue.localize()
}
@ -44,9 +58,9 @@ public enum PasswordGeneratorFlavor: String {
case .apple:
return Keychain.generatePassword()
case .random:
return PasswordGeneratorFlavor.generateRandom(length: length)
return Self.generateRandom(length: length)
case .xkcd:
return PasswordGeneratorFlavor.generateXKCD(length: length)
return Self.generateXKCD(length: length)
}
}
@ -56,22 +70,6 @@ public enum PasswordGeneratorFlavor: String {
}
private static func generateXKCD(length: Int) -> String {
// Get the word list
let bundle = Bundle(identifier: Globals.passKitBundleIdentifier)!
let wordlistNames = [
"eff_long_wordlist",
"eff_short_wordlist"
]
let data = wordlistNames.map{ name -> String in
guard let asset = NSDataAsset(name: name, bundle: bundle),
let data = String(data: asset.data, encoding: .utf8) else {
return ""
}
return data
}
let words = data.joined(separator: "\n").splitByNewline()
// Generate a password
let delimiters = "0123456789!@#$%^&*_+-="
var password = ""
(0..<length).forEach { _ in

View file

@ -8,7 +8,7 @@
import SwiftyUserDefaults
public enum SearchBarScope: Int, CaseIterable, DefaultsSerializable {
public enum SearchBarScope: Int {
case current
case all
@ -21,3 +21,5 @@ public enum SearchBarScope: Int, CaseIterable, DefaultsSerializable {
}
}
}
extension SearchBarScope: CaseIterable {}