mirror of
https://bitbucket.org/vendoo/vendoo_v1.0.git
synced 2025-12-25 03:37:39 +00:00
630 lines
23 KiB
Swift
630 lines
23 KiB
Swift
import Foundation
|
|
|
|
public let LocksmithDefaultService = NSBundle.mainBundle().infoDictionary![String(kCFBundleIdentifierKey)] as? String ?? "com.locksmith.defaultService"
|
|
|
|
public typealias PerformRequestClosureType = (requestReference: CFDictionaryRef, inout result: AnyObject?) -> (OSStatus)
|
|
|
|
|
|
// MARK: - Locksmith
|
|
public struct Locksmith {
|
|
public static func loadDataForUserAccount(userAccount: String, inService service: String = LocksmithDefaultService) -> [String: AnyObject]? {
|
|
struct ReadRequest: GenericPasswordSecureStorable, ReadableSecureStorable {
|
|
let service: String
|
|
let account: String
|
|
}
|
|
|
|
let request = ReadRequest(service: service, account: userAccount)
|
|
return request.readFromSecureStore()?.data
|
|
}
|
|
|
|
public static func saveData(data: [String: AnyObject], forUserAccount userAccount: String, inService service: String = LocksmithDefaultService) throws {
|
|
struct CreateRequest: GenericPasswordSecureStorable, CreateableSecureStorable {
|
|
let service: String
|
|
let account: String
|
|
let data: [String: AnyObject]
|
|
}
|
|
|
|
let request = CreateRequest(service: service, account: userAccount, data: data)
|
|
return try request.createInSecureStore()
|
|
}
|
|
|
|
public static func deleteDataForUserAccount(userAccount: String, inService service: String = LocksmithDefaultService) throws {
|
|
struct DeleteRequest: GenericPasswordSecureStorable, DeleteableSecureStorable {
|
|
let service: String
|
|
let account: String
|
|
}
|
|
|
|
let request = DeleteRequest(service: service, account: userAccount)
|
|
return try request.deleteFromSecureStore()
|
|
}
|
|
|
|
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]
|
|
}
|
|
|
|
let request = UpdateRequest(service: service, account: userAccount, data: data)
|
|
try request.updateInSecureStore()
|
|
}
|
|
}
|
|
|
|
// MARK: - SecureStorable
|
|
/// The base protocol that indicates conforming types will have the ability to be stored in a secure storage container, such as the iOS keychain.
|
|
public protocol SecureStorable {
|
|
var accessible: LocksmithAccessibleOption? { get }
|
|
var accessGroup: String? { get }
|
|
}
|
|
|
|
public extension SecureStorable {
|
|
var accessible: LocksmithAccessibleOption? { return nil }
|
|
var accessGroup: String? { return nil }
|
|
|
|
var secureStorableBaseStoragePropertyDictionary: [String: AnyObject] {
|
|
let dictionary = [
|
|
String(kSecAttrAccessGroup): accessGroup,
|
|
String(kSecAttrAccessible): accessible?.rawValue
|
|
]
|
|
|
|
return Dictionary(withoutOptionalValues: dictionary)
|
|
}
|
|
|
|
private func performSecureStorageAction(closure: PerformRequestClosureType, secureStoragePropertyDictionary: [String: AnyObject]) throws -> [String: AnyObject]? {
|
|
var result: AnyObject?
|
|
let request = secureStoragePropertyDictionary
|
|
let requestReference = request as CFDictionaryRef
|
|
|
|
let status = closure(requestReference: requestReference, result: &result)
|
|
|
|
let statusCode = Int(status)
|
|
|
|
if let error = LocksmithError(fromStatusCode: statusCode) {
|
|
throw error
|
|
}
|
|
|
|
// hmmmm... bit leaky
|
|
if status != errSecSuccess {
|
|
return nil
|
|
}
|
|
|
|
guard let dictionary = result as? NSDictionary else {
|
|
return nil
|
|
}
|
|
|
|
if dictionary[String(kSecValueData)] as? NSData == nil {
|
|
return nil
|
|
}
|
|
|
|
return result as? [String: AnyObject]
|
|
}
|
|
}
|
|
|
|
public extension SecureStorable where Self : InternetPasswordSecureStorable {
|
|
private var internetPasswordBaseStoragePropertyDictionary: [String: AnyObject] {
|
|
var dictionary = [String: AnyObject]()
|
|
|
|
// add in whatever turns out to be required...
|
|
dictionary[String(kSecAttrServer)] = server
|
|
dictionary[String(kSecAttrPort)] = port
|
|
dictionary[String(kSecAttrProtocol)] = internetProtocol.rawValue
|
|
dictionary[String(kSecAttrAuthenticationType)] = authenticationType.rawValue
|
|
dictionary[String(kSecAttrSecurityDomain)] = securityDomain
|
|
dictionary[String(kSecAttrPath)] = path
|
|
dictionary[String(kSecClass)] = LocksmithSecurityClass.InternetPassword.rawValue
|
|
|
|
let toMergeWith = [
|
|
accountSecureStoragePropertyDictionary,
|
|
describableSecureStoragePropertyDictionary,
|
|
commentableSecureStoragePropertyDictionary,
|
|
creatorDesignatableSecureStoragePropertyDictionary,
|
|
typeDesignatableSecureStoragePropertyDictionary,
|
|
isInvisibleSecureStoragePropertyDictionary,
|
|
isNegativeSecureStoragePropertyDictionary
|
|
]
|
|
|
|
for dict in toMergeWith {
|
|
dictionary = Dictionary(initial: dictionary, toMerge: dict)
|
|
}
|
|
|
|
return dictionary
|
|
}
|
|
}
|
|
|
|
public protocol AccountBasedSecureStorable {
|
|
/// The account that the stored value will belong to
|
|
var account: String { get }
|
|
}
|
|
|
|
public extension AccountBasedSecureStorable {
|
|
private var accountSecureStoragePropertyDictionary: [String: AnyObject] {
|
|
return [String(kSecAttrAccount): account]
|
|
}
|
|
}
|
|
|
|
public protocol AccountBasedSecureStorableResultType: AccountBasedSecureStorable, SecureStorableResultType {}
|
|
|
|
public extension AccountBasedSecureStorableResultType {
|
|
var account: String {
|
|
return resultDictionary[String(kSecAttrAccount)] as! String
|
|
}
|
|
}
|
|
|
|
public protocol DescribableSecureStorable {
|
|
/// A description of the item in the secure storage container.
|
|
var description: String? { get }
|
|
}
|
|
|
|
public extension DescribableSecureStorable {
|
|
var description: String? { return nil }
|
|
|
|
private var describableSecureStoragePropertyDictionary: [String: AnyObject] {
|
|
return Dictionary(withoutOptionalValues: [
|
|
String(kSecAttrDescription): description
|
|
])
|
|
}
|
|
}
|
|
|
|
public protocol DescribableSecureStorableResultType: DescribableSecureStorable, SecureStorableResultType {}
|
|
|
|
public extension DescribableSecureStorableResultType {
|
|
var description: String? {
|
|
return resultDictionary[String(kSecAttrDescription)] as? String
|
|
}
|
|
}
|
|
|
|
public protocol CommentableSecureStorable {
|
|
/// A comment attached to the item in the secure storage container.
|
|
var comment: String? { get }
|
|
}
|
|
|
|
public extension CommentableSecureStorable {
|
|
var comment: String? { return nil }
|
|
|
|
private var commentableSecureStoragePropertyDictionary: [String: AnyObject] {
|
|
return Dictionary(withoutOptionalValues: [
|
|
String(kSecAttrComment): comment
|
|
])
|
|
}
|
|
}
|
|
|
|
public protocol CommentableSecureStorableResultType: CommentableSecureStorable, SecureStorableResultType {}
|
|
|
|
public extension CommentableSecureStorableResultType {
|
|
var comment: String? {
|
|
return resultDictionary[String(kSecAttrComment)] as? String
|
|
}
|
|
}
|
|
|
|
public protocol CreatorDesignatableSecureStorable {
|
|
/// The creator of the item in the secure storage container.
|
|
var creator: UInt? { get }
|
|
}
|
|
|
|
public extension CreatorDesignatableSecureStorable {
|
|
var creator: UInt? { return nil }
|
|
|
|
private var creatorDesignatableSecureStoragePropertyDictionary: [String: AnyObject] {
|
|
return Dictionary(withoutOptionalValues: [String(kSecAttrCreator): creator])
|
|
}
|
|
}
|
|
|
|
public protocol CreatorDesignatableSecureStorableResultType: CreatorDesignatableSecureStorable, SecureStorableResultType {}
|
|
|
|
public extension CreatorDesignatableSecureStorableResultType {
|
|
var creator: UInt? {
|
|
return resultDictionary[String(kSecAttrCreator)] as? UInt
|
|
}
|
|
}
|
|
|
|
public protocol LabellableSecureStorable {
|
|
/// A label for the item in the secure storage container.
|
|
var label: String? { get }
|
|
}
|
|
|
|
public extension LabellableSecureStorable {
|
|
var label: String? { return nil }
|
|
|
|
private var labellableSecureStoragePropertyDictionary: [String: AnyObject] {
|
|
return Dictionary(withoutOptionalValues: [String(kSecAttrLabel): label])
|
|
}
|
|
}
|
|
|
|
public protocol LabellableSecureStorableResultType: LabellableSecureStorable, SecureStorableResultType {}
|
|
|
|
public extension LabellableSecureStorableResultType {
|
|
var label: String? {
|
|
return resultDictionary[String(kSecAttrLabel)] as? String
|
|
}
|
|
}
|
|
|
|
public protocol TypeDesignatableSecureStorable {
|
|
/// The type of the stored item
|
|
var type: UInt? { get }
|
|
}
|
|
|
|
public extension TypeDesignatableSecureStorable {
|
|
var type: UInt? { return nil }
|
|
|
|
private var typeDesignatableSecureStoragePropertyDictionary: [String: AnyObject] {
|
|
return Dictionary(withoutOptionalValues: [String(kSecAttrType): type])
|
|
}
|
|
}
|
|
|
|
public protocol TypeDesignatableSecureStorableResultType: TypeDesignatableSecureStorable, SecureStorableResultType {}
|
|
|
|
public extension TypeDesignatableSecureStorableResultType {
|
|
var type: UInt? {
|
|
return resultDictionary[String(kSecAttrType)] as? UInt
|
|
}
|
|
}
|
|
|
|
public protocol IsInvisibleAssignableSecureStorable {
|
|
var isInvisible: Bool? { get }
|
|
}
|
|
|
|
public extension IsInvisibleAssignableSecureStorable {
|
|
var isInvisible: Bool? { return nil }
|
|
|
|
private var isInvisibleSecureStoragePropertyDictionary: [String: AnyObject] {
|
|
return Dictionary(withoutOptionalValues: [String(kSecAttrIsInvisible): isInvisible])
|
|
}
|
|
}
|
|
|
|
public protocol IsInvisibleAssignableSecureStorableResultType: IsInvisibleAssignableSecureStorable, SecureStorableResultType {}
|
|
|
|
public extension IsInvisibleAssignableSecureStorableResultType {
|
|
var isInvisible: Bool? {
|
|
return resultDictionary[String(kSecAttrIsInvisible)] as? Bool
|
|
}
|
|
}
|
|
|
|
public protocol IsNegativeAssignableSecureStorable {
|
|
var isNegative: Bool? { get }
|
|
}
|
|
|
|
public extension IsNegativeAssignableSecureStorable {
|
|
var isNegative: Bool? { return nil }
|
|
|
|
private var isNegativeSecureStoragePropertyDictionary: [String: AnyObject] {
|
|
return Dictionary(withoutOptionalValues: [String(kSecAttrIsNegative): isNegative])
|
|
}
|
|
}
|
|
|
|
public protocol IsNegativeAssignableSecureStorableResultType: IsNegativeAssignableSecureStorable, SecureStorableResultType {
|
|
}
|
|
|
|
public extension IsNegativeAssignableSecureStorableResultType {
|
|
var isNegative: Bool? {
|
|
return resultDictionary[String(kSecAttrIsNegative)] as? Bool
|
|
}
|
|
}
|
|
|
|
// MARK: - GenericPasswordSecureStorable
|
|
/// The protocol that indicates a type conforms to the requirements of a generic password item in a secure storage container.
|
|
/// Generic passwords are the most common types of things that are stored securely.
|
|
public protocol GenericPasswordSecureStorable: AccountBasedSecureStorable, DescribableSecureStorable, CommentableSecureStorable, CreatorDesignatableSecureStorable, LabellableSecureStorable, TypeDesignatableSecureStorable, IsInvisibleAssignableSecureStorable, IsNegativeAssignableSecureStorable {
|
|
|
|
/// The service to which the type belongs
|
|
var service: String { get }
|
|
|
|
// Optional properties
|
|
var generic: NSData? { get }
|
|
}
|
|
|
|
// Add extension to allow for optional properties in protocol
|
|
public extension GenericPasswordSecureStorable {
|
|
var generic: NSData? { return nil}
|
|
}
|
|
|
|
// dear god what have i done...
|
|
public protocol GenericPasswordSecureStorableResultType: GenericPasswordSecureStorable, SecureStorableResultType, AccountBasedSecureStorableResultType, DescribableSecureStorableResultType, CommentableSecureStorableResultType, CreatorDesignatableSecureStorableResultType, LabellableSecureStorableResultType, TypeDesignatableSecureStorableResultType, IsInvisibleAssignableSecureStorableResultType, IsNegativeAssignableSecureStorableResultType {}
|
|
|
|
public extension GenericPasswordSecureStorableResultType {
|
|
var service: String {
|
|
return resultDictionary[String(kSecAttrService)] as! String
|
|
}
|
|
|
|
var generic: NSData? {
|
|
return resultDictionary[String(kSecAttrGeneric)] as? NSData
|
|
}
|
|
}
|
|
|
|
public extension SecureStorable where Self : GenericPasswordSecureStorable {
|
|
private var genericPasswordBaseStoragePropertyDictionary: [String: AnyObject] {
|
|
var dictionary = [String: AnyObject?]()
|
|
|
|
dictionary[String(kSecAttrService)] = service
|
|
dictionary[String(kSecAttrGeneric)] = generic
|
|
dictionary[String(kSecClass)] = LocksmithSecurityClass.GenericPassword.rawValue
|
|
|
|
dictionary = Dictionary(initial: dictionary, toMerge: describableSecureStoragePropertyDictionary)
|
|
|
|
let toMergeWith = [
|
|
secureStorableBaseStoragePropertyDictionary,
|
|
accountSecureStoragePropertyDictionary,
|
|
describableSecureStoragePropertyDictionary,
|
|
commentableSecureStoragePropertyDictionary,
|
|
creatorDesignatableSecureStoragePropertyDictionary,
|
|
typeDesignatableSecureStoragePropertyDictionary,
|
|
labellableSecureStoragePropertyDictionary,
|
|
isInvisibleSecureStoragePropertyDictionary,
|
|
isNegativeSecureStoragePropertyDictionary
|
|
]
|
|
|
|
for dict in toMergeWith {
|
|
dictionary = Dictionary(initial: dictionary, toMerge: dict)
|
|
}
|
|
|
|
return Dictionary(withoutOptionalValues: dictionary)
|
|
}
|
|
}
|
|
|
|
// MARK: - InternetPasswordSecureStorable
|
|
/// A protocol that indicates a type conforms to the requirements of an internet password in a secure storage container.
|
|
public protocol InternetPasswordSecureStorable: AccountBasedSecureStorable, DescribableSecureStorable, CommentableSecureStorable, CreatorDesignatableSecureStorable, TypeDesignatableSecureStorable, IsInvisibleAssignableSecureStorable, IsNegativeAssignableSecureStorable {
|
|
var server: String { get }
|
|
var port: Int { get }
|
|
var internetProtocol: LocksmithInternetProtocol { get }
|
|
var authenticationType: LocksmithInternetAuthenticationType { get }
|
|
var securityDomain: String? { get }
|
|
var path: String? { get }
|
|
}
|
|
|
|
public extension InternetPasswordSecureStorable {
|
|
var securityDomain: String? { return nil }
|
|
var path: String? { return nil }
|
|
}
|
|
|
|
public protocol InternetPasswordSecureStorableResultType: AccountBasedSecureStorableResultType, DescribableSecureStorableResultType, CommentableSecureStorableResultType, CreatorDesignatableSecureStorableResultType, TypeDesignatableSecureStorableResultType, IsInvisibleAssignableSecureStorableResultType, IsNegativeAssignableSecureStorableResultType {}
|
|
|
|
public extension InternetPasswordSecureStorableResultType {
|
|
private func stringFromResultDictionary(key: CFString) -> String? {
|
|
return resultDictionary[String(key)] as? String
|
|
}
|
|
|
|
var server: String {
|
|
return stringFromResultDictionary(kSecAttrServer)!
|
|
}
|
|
|
|
var port: Int {
|
|
return resultDictionary[String(kSecAttrPort)] as! Int
|
|
}
|
|
|
|
var internetProtocol: LocksmithInternetProtocol {
|
|
return LocksmithInternetProtocol(rawValue: stringFromResultDictionary(kSecAttrProtocol)!)!
|
|
}
|
|
|
|
var authenticationType: LocksmithInternetAuthenticationType {
|
|
return LocksmithInternetAuthenticationType(rawValue: stringFromResultDictionary(kSecAttrAuthenticationType)!)!
|
|
}
|
|
|
|
var securityDomain: String? {
|
|
return stringFromResultDictionary(kSecAttrSecurityDomain)
|
|
}
|
|
|
|
var path: String? {
|
|
return stringFromResultDictionary(kSecAttrPath)
|
|
}
|
|
}
|
|
|
|
// MARK: - CertificateSecureStorable
|
|
|
|
public protocol CertificateSecureStorable: SecureStorable {}
|
|
|
|
// MARK: - KeySecureStorable
|
|
|
|
public protocol KeySecureStorable: SecureStorable {}
|
|
|
|
// MARK: - CreateableSecureStorable
|
|
|
|
/// Conformance to this protocol indicates that your type is able to be created and saved to a secure storage container.
|
|
public protocol CreateableSecureStorable: SecureStorable {
|
|
var data: [String: AnyObject] { get }
|
|
var performCreateRequestClosure: PerformRequestClosureType { get }
|
|
func createInSecureStore() throws
|
|
func updateInSecureStore() throws
|
|
}
|
|
|
|
// MARK: - ReadableSecureStorable
|
|
/// Conformance to this protocol indicates that your type is able to be read from a secure storage container.
|
|
public protocol ReadableSecureStorable: SecureStorable {
|
|
var performReadRequestClosure: PerformRequestClosureType { get }
|
|
func readFromSecureStore() -> SecureStorableResultType?
|
|
}
|
|
|
|
public extension ReadableSecureStorable {
|
|
var performReadRequestClosure: PerformRequestClosureType {
|
|
return { (requestReference: CFDictionaryRef, inout result: AnyObject?) in
|
|
return withUnsafeMutablePointer(&result) { SecItemCopyMatching(requestReference, UnsafeMutablePointer($0)) }
|
|
}
|
|
}
|
|
|
|
func readFromSecureStore() -> SecureStorableResultType? {
|
|
// This must be implemented here so that we can properly override it in the type-specific implementations
|
|
return nil
|
|
}
|
|
}
|
|
|
|
public extension ReadableSecureStorable where Self : GenericPasswordSecureStorable {
|
|
var asReadableSecureStoragePropertyDictionary: [String: AnyObject] {
|
|
var old = genericPasswordBaseStoragePropertyDictionary
|
|
old[String(kSecReturnData)] = true
|
|
old[String(kSecMatchLimit)] = kSecMatchLimitOne
|
|
old[String(kSecReturnAttributes)] = kCFBooleanTrue
|
|
|
|
return old
|
|
}
|
|
}
|
|
|
|
public extension ReadableSecureStorable where Self : InternetPasswordSecureStorable {
|
|
var asReadableSecureStoragePropertyDictionary: [String: AnyObject] {
|
|
var old = internetPasswordBaseStoragePropertyDictionary
|
|
old[String(kSecReturnData)] = true
|
|
old[String(kSecMatchLimit)] = kSecMatchLimitOne
|
|
old[String(kSecReturnAttributes)] = kCFBooleanTrue
|
|
return old
|
|
}
|
|
}
|
|
|
|
struct GenericPasswordResult: GenericPasswordSecureStorableResultType {
|
|
var resultDictionary: [String: AnyObject]
|
|
}
|
|
|
|
public extension ReadableSecureStorable where Self : GenericPasswordSecureStorable {
|
|
func readFromSecureStore() -> GenericPasswordSecureStorableResultType? {
|
|
do {
|
|
if let result = try performSecureStorageAction(performReadRequestClosure, secureStoragePropertyDictionary: asReadableSecureStoragePropertyDictionary) {
|
|
return GenericPasswordResult(resultDictionary: result)
|
|
} else {
|
|
return nil
|
|
}
|
|
} catch {
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
|
|
public extension ReadableSecureStorable where Self : InternetPasswordSecureStorable {
|
|
func readFromSecureStore() -> InternetPasswordSecureStorableResultType? {
|
|
do {
|
|
if let result = try performSecureStorageAction(performReadRequestClosure, secureStoragePropertyDictionary: asReadableSecureStoragePropertyDictionary) {
|
|
return InternetPasswordResult(resultDictionary: result)
|
|
} else {
|
|
return nil
|
|
}
|
|
} catch {
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// MARK: - DeleteableSecureStorable
|
|
/// Conformance to this protocol indicates that your type is able to be deleted from a secure storage container.
|
|
public protocol DeleteableSecureStorable: SecureStorable {
|
|
var performDeleteRequestClosure: PerformRequestClosureType { get }
|
|
func deleteFromSecureStore() throws
|
|
}
|
|
|
|
// 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
|
|
old[String(kSecValueData)] = NSKeyedArchiver.archivedDataWithRootObject(data)
|
|
return old
|
|
}
|
|
}
|
|
|
|
public extension CreateableSecureStorable where Self : GenericPasswordSecureStorable {
|
|
func createInSecureStore() throws {
|
|
try performSecureStorageAction(performCreateRequestClosure, secureStoragePropertyDictionary: asCreateableSecureStoragePropertyDictionary)
|
|
}
|
|
func updateInSecureStore() throws {
|
|
try self.updateInSecureStore(self.asCreateableSecureStoragePropertyDictionary)
|
|
}
|
|
}
|
|
|
|
public extension CreateableSecureStorable where Self : InternetPasswordSecureStorable {
|
|
var asCreateableSecureStoragePropertyDictionary: [String: AnyObject] {
|
|
var old = internetPasswordBaseStoragePropertyDictionary
|
|
old[String(kSecValueData)] = NSKeyedArchiver.archivedDataWithRootObject(data)
|
|
return old
|
|
}
|
|
}
|
|
|
|
public extension CreateableSecureStorable {
|
|
var performCreateRequestClosure: PerformRequestClosureType {
|
|
return { (requestReference: CFDictionaryRef, inout result: AnyObject?) in
|
|
return withUnsafeMutablePointer(&result) { SecItemAdd(requestReference, UnsafeMutablePointer($0)) }
|
|
}
|
|
}
|
|
}
|
|
|
|
public extension CreateableSecureStorable where Self : InternetPasswordSecureStorable {
|
|
func createInSecureStore() throws {
|
|
try performSecureStorageAction(performCreateRequestClosure, secureStoragePropertyDictionary: asCreateableSecureStoragePropertyDictionary)
|
|
}
|
|
func updateInSecureStore() throws {
|
|
try self.updateInSecureStore(self.asCreateableSecureStoragePropertyDictionary)
|
|
}
|
|
}
|
|
|
|
public extension DeleteableSecureStorable {
|
|
var performDeleteRequestClosure: PerformRequestClosureType {
|
|
return { (requestReference, _) in
|
|
return SecItemDelete(requestReference)
|
|
}
|
|
}
|
|
}
|
|
|
|
public extension DeleteableSecureStorable where Self : GenericPasswordSecureStorable {
|
|
var asDeleteableSecureStoragePropertyDictionary: [String: AnyObject] {
|
|
return genericPasswordBaseStoragePropertyDictionary
|
|
}
|
|
}
|
|
|
|
public extension DeleteableSecureStorable where Self : InternetPasswordSecureStorable {
|
|
var asDeleteableSecureStoragePropertyDictionary: [String: AnyObject] {
|
|
return internetPasswordBaseStoragePropertyDictionary
|
|
}
|
|
}
|
|
|
|
public extension DeleteableSecureStorable where Self : GenericPasswordSecureStorable {
|
|
func deleteFromSecureStore() throws {
|
|
try performSecureStorageAction(performDeleteRequestClosure, secureStoragePropertyDictionary: asDeleteableSecureStoragePropertyDictionary)
|
|
}
|
|
}
|
|
|
|
public extension DeleteableSecureStorable where Self : InternetPasswordSecureStorable {
|
|
func deleteFromSecureStore() throws {
|
|
try performSecureStorageAction(performDeleteRequestClosure, secureStoragePropertyDictionary: asDeleteableSecureStoragePropertyDictionary)
|
|
}
|
|
}
|
|
|
|
// MARK: ResultTypes
|
|
public protocol SecureStorableResultType: SecureStorable {
|
|
var resultDictionary: [String: AnyObject] { get }
|
|
var data: [String: AnyObject]? { get }
|
|
}
|
|
|
|
struct InternetPasswordResult: InternetPasswordSecureStorableResultType {
|
|
var resultDictionary: [String: AnyObject]
|
|
}
|
|
|
|
public extension SecureStorableResultType {
|
|
var resultDictionary: [String: AnyObject] {
|
|
return [String: AnyObject]()
|
|
}
|
|
|
|
var data: [String: AnyObject]? {
|
|
guard let aData = resultDictionary[String(kSecValueData)] as? NSData else {
|
|
return nil
|
|
}
|
|
|
|
return NSKeyedUnarchiver.unarchiveObjectWithData(aData) as? [String: AnyObject]
|
|
}
|
|
}
|