-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[#73] 로그인 API연동 완료 | 자동로그인, 키체인 토큰 저장 구현중
- Loading branch information
Showing
5 changed files
with
170 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
// | ||
// KeyChainManager.swift | ||
// Spon-us | ||
// | ||
// Created by 박현수 on 2/12/24. | ||
// | ||
|
||
import Foundation | ||
|
||
enum KeychainError: Error { | ||
case itemNotFound | ||
case duplicateItem | ||
case invalidItemFormat | ||
case unknown(OSStatus) | ||
} | ||
|
||
class KeychainManager { | ||
static let service = Bundle.main.bundleIdentifier | ||
|
||
static func save(account: String, value: String, isForce: Bool = false) throws { | ||
try save(account: account, value: value.data(using: .utf8)!, isForce: isForce) | ||
} | ||
|
||
static func save(account: String, value: Data, isForce: Bool = false) throws { | ||
let query: [String: AnyObject] = [ | ||
kSecAttrService as String: service as AnyObject, | ||
kSecAttrAccount as String: account as AnyObject, | ||
kSecClass as String: kSecClassGenericPassword, | ||
kSecValueData as String: value as AnyObject, | ||
] | ||
|
||
let status = SecItemAdd(query as CFDictionary, nil) | ||
|
||
if status == errSecDuplicateItem { | ||
if isForce { | ||
try update(account: account, value: value) | ||
return | ||
} else { | ||
throw KeychainError.duplicateItem | ||
} | ||
} | ||
|
||
guard status == errSecSuccess else { | ||
throw KeychainError.unknown(status) | ||
} | ||
} | ||
|
||
// MARK: - Update | ||
|
||
static func update(account: String, value: String) throws { | ||
try update(account: account, value: value.data(using: .utf8)!) | ||
} | ||
|
||
static func update(account: String, value: Data) throws { | ||
let query: [String: AnyObject] = [ | ||
kSecAttrService as String: service as AnyObject, | ||
kSecAttrAccount as String: account as AnyObject, | ||
kSecClass as String: kSecClassGenericPassword, | ||
kSecValueData as String: value as AnyObject, | ||
] | ||
|
||
let attributes: [String: AnyObject] = [ | ||
kSecValueData as String: value as AnyObject | ||
] | ||
|
||
let status = SecItemUpdate(query as CFDictionary, attributes as CFDictionary) | ||
|
||
guard status != errSecDuplicateItem else { | ||
throw KeychainError.duplicateItem | ||
} | ||
|
||
guard status == errSecSuccess else { | ||
throw KeychainError.unknown(status) | ||
} | ||
} | ||
|
||
// MARK: - Load | ||
|
||
static func load(account: String) throws -> String { | ||
try String(decoding: load(account: account), as: UTF8.self) | ||
} | ||
|
||
static func load(account: String) throws -> Data { | ||
let query: [String: AnyObject] = [ | ||
kSecAttrService as String: service as AnyObject, | ||
kSecAttrAccount as String: account as AnyObject, | ||
kSecClass as String: kSecClassGenericPassword, | ||
kSecMatchLimit as String: kSecMatchLimitOne, | ||
kSecReturnData as String: kCFBooleanTrue, | ||
] | ||
|
||
var result: AnyObject? | ||
let status = SecItemCopyMatching(query as CFDictionary, &result) | ||
guard status != errSecItemNotFound else { | ||
throw KeychainError.itemNotFound | ||
} | ||
|
||
guard status == errSecSuccess else { | ||
throw KeychainError.unknown(status) | ||
} | ||
|
||
guard let password = result as? Data else { | ||
throw KeychainError.invalidItemFormat | ||
} | ||
|
||
return password | ||
} | ||
|
||
// MARK: - Delete | ||
|
||
static func delete(account: String) throws { | ||
let query: [String: AnyObject] = [ | ||
kSecAttrService as String: service as AnyObject, | ||
kSecAttrAccount as String: account as AnyObject, | ||
kSecClass as String: kSecClassGenericPassword | ||
] | ||
|
||
let status = SecItemDelete(query as CFDictionary) | ||
|
||
guard status == errSecSuccess else { | ||
throw KeychainError.unknown(status) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters