diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7bb13ec3..775cc84c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,10 @@
+## [3.1.3][] (2018-04-29)
+- Ignore un-deserializable tokens in `allPersistentTokens()`. ([#179](https://github.com/mattrubin/OneTimePassword/pull/179))
+
+
## [3.1.2][] (2018-04-23)
- Synthesize Equatable conformance when compiling with Swift 4.1. ([#173](https://github.com/mattrubin/OneTimePassword/pull/173))
- Fix a warning about deprecation of cross-module struct initializers by simplifying test cases for impossible-to-create invalid Generators. ([#174](https://github.com/mattrubin/OneTimePassword/pull/174))
@@ -155,8 +159,9 @@ Changes between prerelease versions of OneTimePassword version 2 can be found be
## [1.0.0][] (2014-07-17)
-[develop]: https://github.com/mattrubin/OneTimePassword/compare/3.1.2...develop
+[develop]: https://github.com/mattrubin/OneTimePassword/compare/3.1.3...develop
+[3.1.3]: https://github.com/mattrubin/OneTimePassword/compare/3.1.2...3.1.3
[3.1.2]: https://github.com/mattrubin/OneTimePassword/compare/3.1.1...3.1.2
[3.1.1]: https://github.com/mattrubin/OneTimePassword/compare/3.1...3.1.1
[3.1]: https://github.com/mattrubin/OneTimePassword/compare/3.0.1...3.1
diff --git a/OneTimePassword.podspec b/OneTimePassword.podspec
index f988c7b4..0d0fc894 100644
--- a/OneTimePassword.podspec
+++ b/OneTimePassword.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "OneTimePassword"
- s.version = "3.1.2"
+ s.version = "3.1.3"
s.summary = "A small library for generating TOTP and HOTP one-time passwords."
s.homepage = "https://github.com/mattrubin/OneTimePassword"
s.license = "MIT"
diff --git a/Sources/Info.plist b/Sources/Info.plist
index ba9f4e86..fa3725f0 100644
--- a/Sources/Info.plist
+++ b/Sources/Info.plist
@@ -15,11 +15,11 @@
CFBundlePackageType
FMWK
CFBundleShortVersionString
- 3.1.2
+ 3.1.3
CFBundleSignature
????
CFBundleVersion
- 3.1.2
+ 3.1.3
NSPrincipalClass
diff --git a/Sources/Keychain.swift b/Sources/Keychain.swift
index e84a1a09..ff1637b8 100644
--- a/Sources/Keychain.swift
+++ b/Sources/Keychain.swift
@@ -47,7 +47,12 @@ public final class Keychain {
///
/// - throws: A `Keychain.Error` if an error occurred.
public func allPersistentTokens() throws -> Set {
- return Set(try allKeychainItems().map(PersistentToken.init(keychainDictionary:)))
+ let allItems = try allKeychainItems()
+ // This code intentionally ignores items which fail deserialization, instead opting to return as many readable
+ // tokens as possible.
+ // TODO: Restore deserialization error handling, in a way that provides info on the failure reason and allows
+ // the caller to choose whether to fail completely or recover some data.
+ return Set(allItems.flatMap({ try? PersistentToken.init(keychainDictionary:$0) }))
}
// MARK: Write
diff --git a/Tests/KeychainTests.swift b/Tests/KeychainTests.swift
index c2068368..5d90daa1 100644
--- a/Tests/KeychainTests.swift
+++ b/Tests/KeychainTests.swift
@@ -231,7 +231,8 @@ class KeychainTests: XCTestCase {
let persistentRef = try addKeychainItem(withAttributes: keychainAttributes)
XCTAssertThrowsError(try keychain.persistentToken(withIdentifier: persistentRef))
- XCTAssertThrowsError(try keychain.allPersistentTokens())
+ // TODO: Restore deserialization error handling in allPersistentTokens()
+// XCTAssertThrowsError(try keychain.allPersistentTokens())
XCTAssertNoThrow(try deleteKeychainItem(forPersistentRef: persistentRef),
"Failed to delete the test token from the keychain. This may cause future test runs to fail.")
@@ -247,7 +248,8 @@ class KeychainTests: XCTestCase {
let persistentRef = try addKeychainItem(withAttributes: keychainAttributes)
XCTAssertThrowsError(try keychain.persistentToken(withIdentifier: persistentRef))
- XCTAssertThrowsError(try keychain.allPersistentTokens())
+ // TODO: Restore deserialization error handling in allPersistentTokens()
+// XCTAssertThrowsError(try keychain.allPersistentTokens())
XCTAssertNoThrow(try deleteKeychainItem(forPersistentRef: persistentRef),
"Failed to delete the test token from the keychain. This may cause future test runs to fail.")
@@ -264,7 +266,8 @@ class KeychainTests: XCTestCase {
let persistentRef = try addKeychainItem(withAttributes: keychainAttributes)
XCTAssertThrowsError(try keychain.persistentToken(withIdentifier: persistentRef))
- XCTAssertThrowsError(try keychain.allPersistentTokens())
+ // TODO: Restore deserialization error handling in allPersistentTokens()
+// XCTAssertThrowsError(try keychain.allPersistentTokens())
XCTAssertNoThrow(try deleteKeychainItem(forPersistentRef: persistentRef),
"Failed to delete the test token from the keychain. This may cause future test runs to fail.")
@@ -281,7 +284,8 @@ class KeychainTests: XCTestCase {
let persistentRef = try addKeychainItem(withAttributes: keychainAttributes)
XCTAssertThrowsError(try keychain.persistentToken(withIdentifier: persistentRef))
- XCTAssertThrowsError(try keychain.allPersistentTokens())
+ // TODO: Restore deserialization error handling in allPersistentTokens()
+// XCTAssertThrowsError(try keychain.allPersistentTokens())
XCTAssertNoThrow(try deleteKeychainItem(forPersistentRef: persistentRef),
"Failed to delete the test token from the keychain. This may cause future test runs to fail.")