Compare commits
1 Commits
rocket-link
..
2.0.5
| Author | SHA1 | Date | |
|---|---|---|---|
| a9c1a6022b |
+1
-1
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "Locksmith"
|
||||
s.version = "2.0.8"
|
||||
s.version = "2.0.5"
|
||||
s.summary = "Locksmith is a powerful, protocol-oriented library for working with the keychain in Swift."
|
||||
s.description = <<-DESC
|
||||
Locksmith is a powerful, protocol-oriented library for working with the iOS, Mac OS X, watchOS, and tvOS keychain in Swift. It provides extensive support for a lot of different keychain requests, and extensively uses Swift-native concepts.
|
||||
|
||||
@@ -718,7 +718,6 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
@@ -754,6 +753,7 @@
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_NAME = "";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
@@ -767,7 +767,6 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
@@ -808,13 +807,11 @@
|
||||
FBD0C94E1C1866BE00291F2A /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BITCODE_GENERATION_MODE = bitcode;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_BITCODE = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
INFOPLIST_FILE = Source/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
@@ -831,14 +828,12 @@
|
||||
FBD0C94F1C1866BE00291F2A /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BITCODE_GENERATION_MODE = bitcode;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_BITCODE = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
INFOPLIST_FILE = Source/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
|
||||
@@ -7,14 +7,6 @@ A powerful, protocol-oriented library for working with the keychain in Swift.
|
||||
- [x] ⌚️ watchOS 2
|
||||
- [x] 📺 tvOS
|
||||
|
||||
>
|
||||
>
|
||||
> I make [Rocket](http://matthewpalmer.net/rocket?utm_source=locksmith&utm_medium=readme&utm_campaign=open_source), an app that gives you Slack-style emoji everywhere on your Mac.
|
||||
>
|
||||
>
|
||||
|
||||
## Details
|
||||
|
||||
How is Locksmith different to other keychain wrappers?
|
||||
|
||||
* Locksmith’s API is both super-simple and deeply powerful
|
||||
@@ -40,7 +32,7 @@ Locksmith is available through [CocoaPods](http://cocoapods.org).
|
||||
|
||||
Locksmith is available through [Carthage](https://github.com/Carthage/Carthage).
|
||||
|
||||
github "matthewpalmer/Locksmith"
|
||||
github 'matthewpalmer/Locksmith'
|
||||
|
||||
## Quick start
|
||||
|
||||
|
||||
+8
-35
@@ -39,14 +39,15 @@ public struct Locksmith {
|
||||
}
|
||||
|
||||
public static func updateData(data: [String: AnyObject], forUserAccount userAccount: String, inService service: String = LocksmithDefaultService) throws {
|
||||
struct UpdateRequest: GenericPasswordSecureStorable, CreateableSecureStorable {
|
||||
let service: String
|
||||
let account: String
|
||||
let data: [String: AnyObject]
|
||||
// Delete and then re-save
|
||||
do {
|
||||
try Locksmith.deleteDataForUserAccount(userAccount, inService: service)
|
||||
} catch {
|
||||
// Deletion is likely to fail if the piece of data doesn't exist yet.
|
||||
// This doesn't matter--we only tell the user about errors on the save request.
|
||||
}
|
||||
|
||||
let request = UpdateRequest(service: service, account: userAccount, data: data)
|
||||
try request.updateInSecureStore()
|
||||
|
||||
return try Locksmith.saveData(data, forUserAccount: userAccount, inService: service)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -423,7 +424,6 @@ public protocol CreateableSecureStorable: SecureStorable {
|
||||
var data: [String: AnyObject] { get }
|
||||
var performCreateRequestClosure: PerformRequestClosureType { get }
|
||||
func createInSecureStore() throws
|
||||
func updateInSecureStore() throws
|
||||
}
|
||||
|
||||
// MARK: - ReadableSecureStorable
|
||||
@@ -509,27 +509,6 @@ public protocol DeleteableSecureStorable: SecureStorable {
|
||||
|
||||
// MARK: - Default property dictionaries
|
||||
|
||||
extension CreateableSecureStorable {
|
||||
func updateInSecureStore(query: [String: AnyObject]) throws {
|
||||
var attributesToUpdate = query
|
||||
attributesToUpdate[String(kSecClass)] = nil
|
||||
|
||||
let status = SecItemUpdate(query, attributesToUpdate)
|
||||
|
||||
if let error = LocksmithError(fromStatusCode: Int(status)) {
|
||||
if error == .NotFound || error == .NotAvailable {
|
||||
try self.createInSecureStore()
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
} else {
|
||||
if status != errSecSuccess {
|
||||
throw LocksmithError.Undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public extension CreateableSecureStorable where Self : GenericPasswordSecureStorable {
|
||||
var asCreateableSecureStoragePropertyDictionary: [String: AnyObject] {
|
||||
var old = genericPasswordBaseStoragePropertyDictionary
|
||||
@@ -542,9 +521,6 @@ public extension CreateableSecureStorable where Self : GenericPasswordSecureStor
|
||||
func createInSecureStore() throws {
|
||||
try performSecureStorageAction(performCreateRequestClosure, secureStoragePropertyDictionary: asCreateableSecureStoragePropertyDictionary)
|
||||
}
|
||||
func updateInSecureStore() throws {
|
||||
try self.updateInSecureStore(self.asCreateableSecureStoragePropertyDictionary)
|
||||
}
|
||||
}
|
||||
|
||||
public extension CreateableSecureStorable where Self : InternetPasswordSecureStorable {
|
||||
@@ -567,9 +543,6 @@ public extension CreateableSecureStorable where Self : InternetPasswordSecureSto
|
||||
func createInSecureStore() throws {
|
||||
try performSecureStorageAction(performCreateRequestClosure, secureStoragePropertyDictionary: asCreateableSecureStoragePropertyDictionary)
|
||||
}
|
||||
func updateInSecureStore() throws {
|
||||
try self.updateInSecureStore(self.asCreateableSecureStoragePropertyDictionary)
|
||||
}
|
||||
}
|
||||
|
||||
public extension DeleteableSecureStorable {
|
||||
|
||||
+10
-61
@@ -53,12 +53,6 @@ class LocksmithTests: XCTestCase {
|
||||
let loaded3 = Locksmith.loadDataForUserAccount(userAccount, inService: service)! as! TestingDictionaryType
|
||||
|
||||
XCTAssertEqual(loaded3, updatedData)
|
||||
|
||||
try! Locksmith.deleteDataForUserAccount(userAccount, inService: service)
|
||||
|
||||
try! Locksmith.updateData(["some update": "data"], forUserAccount: userAccount, inService: service)
|
||||
let updateResult = Locksmith.loadDataForUserAccount(userAccount, inService: service)! as! [String: String]
|
||||
XCTAssertEqual(updateResult, ["some update": "data"])
|
||||
}
|
||||
|
||||
func testStaticMethodsForDefaultService() {
|
||||
@@ -100,40 +94,6 @@ class LocksmithTests: XCTestCase {
|
||||
createGenericPasswordWithData(data)
|
||||
}
|
||||
|
||||
func testUpdateCreatesIfNotExists() {
|
||||
let data = ["some": "data"]
|
||||
|
||||
struct CreateGenericPassword: CreateableSecureStorable, GenericPasswordSecureStorable, ReadableSecureStorable {
|
||||
var data: [String: AnyObject]
|
||||
let account: String
|
||||
let service: String
|
||||
}
|
||||
|
||||
let update = CreateGenericPassword(data: data, account: userAccount, service: service)
|
||||
try! update.updateInSecureStore()
|
||||
|
||||
let read = update.readFromSecureStore()!.data as! [String: String]
|
||||
XCTAssertEqual(read, ["some": "data"])
|
||||
}
|
||||
|
||||
func testUpdateForGenericPassword() {
|
||||
let data = ["some": "data"]
|
||||
|
||||
struct CreateGenericPassword: CreateableSecureStorable, GenericPasswordSecureStorable, ReadableSecureStorable {
|
||||
var data: [String: AnyObject]
|
||||
let account: String
|
||||
let service: String
|
||||
}
|
||||
|
||||
var create = CreateGenericPassword(data: data, account: userAccount, service: service)
|
||||
try! create.createInSecureStore() // make sure it doesn't throw
|
||||
create.data = ["other": "data"]
|
||||
try! create.updateInSecureStore()
|
||||
|
||||
let read = create.readFromSecureStore()!.data as! [String: String]
|
||||
XCTAssertEqual(read, ["other": "data"])
|
||||
}
|
||||
|
||||
func testLoadForGenericPassword() {
|
||||
let data = ["one": "two"]
|
||||
createGenericPasswordWithData(data)
|
||||
@@ -279,7 +239,7 @@ class LocksmithTests: XCTestCase {
|
||||
func testInternetPasswordMetaAttributesAreCreatedAndReturned() {
|
||||
struct CreateInternetPassword: CreateableSecureStorable, InternetPasswordSecureStorable {
|
||||
let account: String
|
||||
var data: [String: AnyObject]
|
||||
let data: [String: AnyObject]
|
||||
let server: String
|
||||
let port: Int
|
||||
let internetProtocol: LocksmithInternetProtocol
|
||||
@@ -305,31 +265,20 @@ class LocksmithTests: XCTestCase {
|
||||
let authenticationType: LocksmithInternetAuthenticationType
|
||||
}
|
||||
|
||||
var c = CreateInternetPassword(account: userAccount, data: initialData, server: server, port: port, internetProtocol: internetProtocol, authenticationType: authenticationType, path: path, securityDomain: securityDomain)
|
||||
let c = CreateInternetPassword(account: userAccount, data: initialData, server: server, port: port, internetProtocol: internetProtocol, authenticationType: authenticationType, path: path, securityDomain: securityDomain)
|
||||
try! c.createInSecureStore()
|
||||
|
||||
func assertResultMetadataIsOk(result: InternetPasswordSecureStorableResultType?) {
|
||||
XCTAssertEqual(result?.account, userAccount)
|
||||
XCTAssertEqual(result?.server, server)
|
||||
XCTAssertEqual(result?.port, port)
|
||||
XCTAssertEqual(result?.internetProtocol, internetProtocol)
|
||||
XCTAssertEqual(result?.authenticationType, authenticationType)
|
||||
XCTAssertEqual(result?.securityDomain, securityDomain)
|
||||
XCTAssertEqual(result?.path, path)
|
||||
}
|
||||
|
||||
let r = ReadInternetPassword(account: userAccount, server: server, port: port, internetProtocol: internetProtocol, authenticationType: authenticationType)
|
||||
let result = r.readFromSecureStore()
|
||||
|
||||
XCTAssertEqual(result?.account, userAccount)
|
||||
XCTAssertEqual(result!.data as! [String: String], initialData)
|
||||
assertResultMetadataIsOk(result)
|
||||
|
||||
// Assert that metadata is maintained after an update
|
||||
c.data = ["other internet": "junk"]
|
||||
try! c.updateInSecureStore()
|
||||
|
||||
let result2 = r.readFromSecureStore()
|
||||
XCTAssertEqual(result2!.data as! [String: String], ["other internet": "junk"])
|
||||
assertResultMetadataIsOk(result2)
|
||||
XCTAssertEqual(result?.server, server)
|
||||
XCTAssertEqual(result?.port, port)
|
||||
XCTAssertEqual(result?.internetProtocol, internetProtocol)
|
||||
XCTAssertEqual(result?.authenticationType, authenticationType)
|
||||
XCTAssertEqual(result?.securityDomain, securityDomain)
|
||||
XCTAssertEqual(result?.path, path)
|
||||
}
|
||||
|
||||
func assertStringPairsMatchInDictionary(dictionary: NSDictionary, pairs: [(key: CFString, expectedOutput: String)]) {
|
||||
|
||||
Reference in New Issue
Block a user