mirror of https://github.com/oxen-io/session-ios
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			112 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Swift
		
	
			
		
		
	
	
			112 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Swift
		
	
//
 | 
						|
//  Copyright (c) 2018 Open Whisper Systems. All rights reserved.
 | 
						|
//
 | 
						|
 | 
						|
import Foundation
 | 
						|
import SAMKeychain
 | 
						|
 | 
						|
public enum KeychainStorageError: Error {
 | 
						|
    case failure(code: Int32?, description: String)
 | 
						|
    
 | 
						|
    public var code: Int32? {
 | 
						|
        switch self {
 | 
						|
            case .failure(let code, _): return code
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
// MARK: -
 | 
						|
 | 
						|
@objc public protocol SSKKeychainStorage: AnyObject {
 | 
						|
 | 
						|
    @objc func string(forService service: String, key: String) throws -> String
 | 
						|
 | 
						|
    @objc(setString:service:key:error:) func set(string: String, service: String, key: String) throws
 | 
						|
 | 
						|
    @objc func data(forService service: String, key: String) throws -> Data
 | 
						|
 | 
						|
    @objc func set(data: Data, service: String, key: String) throws
 | 
						|
 | 
						|
    @objc func remove(service: String, key: String) throws
 | 
						|
}
 | 
						|
 | 
						|
// MARK: -
 | 
						|
 | 
						|
@objc
 | 
						|
public class SSKDefaultKeychainStorage: NSObject, SSKKeychainStorage {
 | 
						|
 | 
						|
    @objc public static let shared = SSKDefaultKeychainStorage()
 | 
						|
 | 
						|
    // Force usage as a singleton
 | 
						|
    override private init() {
 | 
						|
        super.init()
 | 
						|
    }
 | 
						|
 | 
						|
    @objc public func string(forService service: String, key: String) throws -> String {
 | 
						|
        var error: NSError?
 | 
						|
        let result = SAMKeychain.password(forService: service, account: key, error: &error)
 | 
						|
        if let error = error {
 | 
						|
            throw KeychainStorageError.failure(code: Int32(error.code), description: "\(logTag) error retrieving string: \(error)")
 | 
						|
        }
 | 
						|
        guard let string = result else {
 | 
						|
            throw KeychainStorageError.failure(code: nil, description: "\(logTag) could not retrieve string")
 | 
						|
        }
 | 
						|
        return string
 | 
						|
    }
 | 
						|
 | 
						|
    @objc public func set(string: String, service: String, key: String) throws {
 | 
						|
 | 
						|
        SAMKeychain.setAccessibilityType(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly)
 | 
						|
 | 
						|
        var error: NSError?
 | 
						|
        let result = SAMKeychain.setPassword(string, forService: service, account: key, error: &error)
 | 
						|
        if let error = error {
 | 
						|
            throw KeychainStorageError.failure(code: Int32(error.code), description: "\(logTag) error setting string: \(error)")
 | 
						|
        }
 | 
						|
        guard result else {
 | 
						|
            throw KeychainStorageError.failure(code: nil, description: "\(logTag) could not set string")
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    @objc public func data(forService service: String, key: String) throws -> Data {
 | 
						|
        var error: NSError?
 | 
						|
        let result = SAMKeychain.passwordData(forService: service, account: key, error: &error)
 | 
						|
        if let error = error {
 | 
						|
            throw KeychainStorageError.failure(code: Int32(error.code), description: "\(logTag) error retrieving data: \(error)")
 | 
						|
        }
 | 
						|
        guard let data = result else {
 | 
						|
            throw KeychainStorageError.failure(code: nil, description: "\(logTag) could not retrieve data")
 | 
						|
        }
 | 
						|
        return data
 | 
						|
    }
 | 
						|
 | 
						|
    @objc public func set(data: Data, service: String, key: String) throws {
 | 
						|
 | 
						|
        SAMKeychain.setAccessibilityType(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly)
 | 
						|
 | 
						|
        var error: NSError?
 | 
						|
        let result = SAMKeychain.setPasswordData(data, forService: service, account: key, error: &error)
 | 
						|
        if let error = error {
 | 
						|
            throw KeychainStorageError.failure(code: Int32(error.code), description: "\(logTag) error setting data: \(error)")
 | 
						|
        }
 | 
						|
        guard result else {
 | 
						|
            throw KeychainStorageError.failure(code: nil, description: "\(logTag) could not set data")
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    @objc public func remove(service: String, key: String) throws {
 | 
						|
        var error: NSError?
 | 
						|
        let result = SAMKeychain.deletePassword(forService: service, account: key, error: &error)
 | 
						|
        if let error = error {
 | 
						|
            // If deletion failed because the specified item could not be found in the keychain, consider it success.
 | 
						|
            if error.code == errSecItemNotFound {
 | 
						|
                return
 | 
						|
            }
 | 
						|
            throw KeychainStorageError.failure(code: Int32(error.code), description: "\(logTag) error removing data: \(error)")
 | 
						|
        }
 | 
						|
        guard result else {
 | 
						|
            throw KeychainStorageError.failure(code: nil, description: "\(logTag) could not remove data")
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |