diff --git a/pass.xcodeproj/project.pbxproj b/pass.xcodeproj/project.pbxproj index 7b82025..8821919 100644 --- a/pass.xcodeproj/project.pbxproj +++ b/pass.xcodeproj/project.pbxproj @@ -1339,6 +1339,7 @@ SKIP_INSTALL = YES; SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; @@ -1372,6 +1373,7 @@ SKIP_INSTALL = YES; SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; @@ -1550,7 +1552,7 @@ OTHER_LDFLAGS = "${inherited}"; PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER)"; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = "6bb836f2-68a1-44cc-8c45-f6b6e53ba64a"; + PROVISIONING_PROFILE = "3c4f599a-ce77-4184-b4c4-edebf09cba3b"; PROVISIONING_PROFILE_SPECIFIER = "match Development me.mssun.passforios"; SWIFT_OBJC_BRIDGING_HEADER = "pass/Helpers/Objective-CBridgingHeader.h"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; diff --git a/pass/Views/LabelTableViewCell.swift b/pass/Views/LabelTableViewCell.swift index b1d8def..c49d5c2 100644 --- a/pass/Views/LabelTableViewCell.swift +++ b/pass/Views/LabelTableViewCell.swift @@ -39,8 +39,7 @@ class LabelTableViewCell: UITableViewCell { return } titleLabel.text = title - switch title.lowercased() { - case "password": + if title.caseInsensitiveCompare("password") == .orderedSame { type = .password if isReveal { contentLabel.attributedText = Utils.attributedPassword(plainPassword: content) @@ -52,7 +51,7 @@ class LabelTableViewCell: UITableViewCell { } } contentLabel.font = Globals.passwordFont - case "hmac-based": + } else if title.caseInsensitiveCompare("hmac-based") == .orderedSame { type = .HOTP if isReveal { contentLabel.text = content @@ -60,11 +59,12 @@ class LabelTableViewCell: UITableViewCell { contentLabel.text = Globals.oneTimePasswordDots } contentLabel.font = Globals.passwordFont - case "url": + } else if title.lowercased().range(of: "url") != nil || verifyUrl(content) { type = .URL contentLabel.text = content contentLabel.font = UIFont.systemFont(ofSize: contentLabel.font.pointSize) - default: + } else { + // default type = .other contentLabel.text = content contentLabel.font = UIFont.systemFont(ofSize: contentLabel.font.pointSize) @@ -198,4 +198,12 @@ class LabelTableViewCell: UITableViewCell { } self.accessoryView = buttons } + + private func verifyUrl(_ urlString: String?) -> Bool { + guard let urlString = urlString, + let _ = URL(string: urlString) else { + return false + } + return true + } } diff --git a/passKit/Helpers/AppError.swift b/passKit/Helpers/AppError.swift index 5386ee1..515c18a 100644 --- a/passKit/Helpers/AppError.swift +++ b/passKit/Helpers/AppError.swift @@ -16,6 +16,7 @@ public enum AppError: Error { case GitResetError case PGPPublicKeyNotExistError case WrongPasswordFilename + case YamlLoadError case UnknownError } @@ -36,6 +37,8 @@ extension AppError: LocalizedError { return "PGP public key doesn't exist." case .WrongPasswordFilename: return "Cannot write to the password file." + case .YamlLoadError: + return "Cannot be parsed as a YAML file." case .UnknownError: return "Unknown error." } diff --git a/passKit/Models/Password.swift b/passKit/Models/Password.swift index d610e84..ce9eff9 100644 --- a/passKit/Models/Password.swift +++ b/passKit/Models/Password.swift @@ -87,15 +87,15 @@ public class Password { additions.removeAll() // split the plain text - let plainTextSplit = self.plainText.split(omittingEmptySubsequences: true) { + let plainTextSplit = self.plainText.split(omittingEmptySubsequences: false) { $0 == "\n" || $0 == "\r\n" }.map(String.init) // get password password = plainTextSplit.first ?? "" - // get remaining lines - let additionalLines = plainTextSplit[1...] + // get remaining lines (filter out empty lines) + let additionalLines = plainTextSplit[1...].filter { !$0.isEmpty } // separate normal lines (no otp tokens) let normalAdditionalLines = additionalLines.filter { @@ -126,10 +126,32 @@ public class Password { // construct the otp token self.updateOtpToken() } + + // check whether the file has lines with duplicated field names + private func checkDuplicatedFields(lines: String) -> Bool { + var keys = Set() + var hasDuplicatedFields = false + lines.enumerateLines { (line, stop) -> () in + let (key, _) = Password.getKeyValuePair(from: line) + if let key = key { + if keys.contains(key) { + hasDuplicatedFields = true + stop = true + } + keys.insert(key) + } + } + return hasDuplicatedFields + } private func getAdditionalFields(fromYaml: String) throws { guard !fromYaml.isEmpty else { return } - let yamlFile = try Yams.load(yaml: fromYaml) as! [String: Any] + if checkDuplicatedFields(lines: fromYaml) { + throw AppError.YamlLoadError + } + guard let yamlFile = try Yams.load(yaml: fromYaml) as? [String: Any] else { + throw AppError.YamlLoadError + } additions.append(contentsOf: yamlFile.map { ($0, String(describing: $1)) }) }