diff --git a/passKit/Models/Password.swift b/passKit/Models/Password.swift index a85af37..a4b0527 100644 --- a/passKit/Models/Password.swift +++ b/passKit/Models/Password.swift @@ -156,24 +156,18 @@ public class Password { .build() } - // return the description and the password strings + /// Get the OTP description and the current password. public func getOtpStrings() -> (description: String, otp: String)? { - guard let token = self.otpToken else { + guard otpToken != nil else { return nil } - var description : String - switch token.generator.factor { - case .counter: - // htop - description = "HMAC-based" - case .timer(let period): - // totp + var description = otpType.description + if case let .timer(period)? = otpToken?.generator.factor { let timeSinceEpoch = Date().timeIntervalSince1970 let validTime = Int(period - timeSinceEpoch.truncatingRemainder(dividingBy: period)) - description = "time-based (expiring in \(validTime)s)" + description += " (expires in \(validTime)s)" } - let otp = self.otpToken?.currentPassword ?? "error" - return (description, otp) + return (description, otpToken!.currentPassword ?? "error") } // return the password strings diff --git a/passKit/Parser/OtpType.swift b/passKit/Parser/OtpType.swift index 79d6c9c..3ae97e0 100644 --- a/passKit/Parser/OtpType.swift +++ b/passKit/Parser/OtpType.swift @@ -8,9 +8,15 @@ import OneTimePassword -public enum OtpType { - case totp, hotp, none +public enum OtpType: String { + case totp = "time-based" + case hotp = "HMAC-based" + case none + var description: String { + return rawValue + } + init(token: Token?) { switch token?.generator.factor { case .some(.counter): diff --git a/passKitTests/Models/PasswordTest.swift b/passKitTests/Models/PasswordTest.swift index 1181ad8..d9457c6 100644 --- a/passKitTests/Models/PasswordTest.swift +++ b/passKitTests/Models/PasswordTest.swift @@ -298,6 +298,29 @@ class PasswordTest: XCTestCase { XCTAssertEqual(password.changed, 3) } + func testOtpStringsNoOtpToken() { + let password = getPasswordObjectWith(content: "") + let otpStrings = password.getOtpStrings() + + XCTAssertNil(otpStrings) + } + + func testOtpStringsTotpToken() { + let password = getPasswordObjectWith(content: TOTP_URL) + let otpStrings = password.getOtpStrings() + + XCTAssertNotNil(otpStrings) + XCTAssertTrue(otpStrings!.description.hasPrefix("time-based (expires in")) + } + + func testOtpStringsHotpToken() { + let password = getPasswordObjectWith(content: HOTP_URL) + let otpStrings = password.getOtpStrings() + + XCTAssertNotNil(otpStrings) + XCTAssertEqual(otpStrings!.description, "HMAC-based") + } + private func getPasswordObjectWith(content: String, url: URL? = nil) -> Password { return Password(name: "password", url: url ?? PASSWORD_URL, plainText: content) } diff --git a/passKitTests/Parser/OtpTypeTest.swift b/passKitTests/Parser/OtpTypeTest.swift index 329de42..50a4aee 100644 --- a/passKitTests/Parser/OtpTypeTest.swift +++ b/passKitTests/Parser/OtpTypeTest.swift @@ -36,4 +36,10 @@ class OtpTypeTest: XCTestCase { XCTAssertEqual(OtpType(name: ""), .none) XCTAssertEqual(OtpType(name: "something"), .none) } + + func testDescription() { + XCTAssertEqual(OtpType(name: "totp").description, "time-based") + XCTAssertEqual(OtpType(name: "hotp").description, "HMAC-based") + XCTAssertEqual(OtpType(name: nil).description, "none") + } }