Huge refactor to add better structure to the project. Separating features with their associated view and model structure. This should be better organization and will allow us to improve the overall architecture in the future. I forsee many more improvements that can follow this change. e.g. MVVM Arch As well as cleaning up duplicate, unused, functionality. Many files have global functions that can also be moved or be renamed. damus/ ├── Features/ │ ├── <Feature>/ │ │ ├── Views/ │ │ └── Models/ ├── Shared/ │ ├── Components/ │ ├── Media/ │ ├── Buttons/ │ ├── Extensions/ │ ├── Empty Views/ │ ├── ErrorHandling/ │ ├── Modifiers/ │ └── Utilities/ ├── Core/ │ ├── Nostr/ │ ├── NIPs/ │ ├── DIPs/ │ ├── Types/ │ ├── Networking/ │ └── Storage/ Signed-off-by: ericholguin <ericholguin@apache.org>
74 lines
2.3 KiB
Swift
74 lines
2.3 KiB
Swift
//
|
|
// KeychainStorage.swift
|
|
// damus
|
|
//
|
|
// Created by Bryan Montz on 5/2/23.
|
|
//
|
|
|
|
import Foundation
|
|
import Security
|
|
|
|
@propertyWrapper struct KeychainStorage {
|
|
let account: String
|
|
private let service = "damus"
|
|
|
|
var wrappedValue: String? {
|
|
get {
|
|
let query = [
|
|
kSecAttrService: service,
|
|
kSecAttrAccount: account,
|
|
kSecClass: kSecClassGenericPassword,
|
|
kSecReturnData: true,
|
|
kSecMatchLimit: kSecMatchLimitOne
|
|
] as [CFString: Any] as CFDictionary
|
|
|
|
var result: AnyObject?
|
|
let status = SecItemCopyMatching(query, &result)
|
|
|
|
if status == errSecSuccess, let data = result as? Data {
|
|
return String(data: data, encoding: .utf8)
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
set {
|
|
if let newValue {
|
|
let query = [
|
|
kSecAttrService: service,
|
|
kSecAttrAccount: account,
|
|
kSecClass: kSecClassGenericPassword,
|
|
kSecValueData: newValue.data(using: .utf8) as Any
|
|
] as [CFString: Any] as CFDictionary
|
|
|
|
var status = SecItemAdd(query, nil)
|
|
|
|
if status == errSecDuplicateItem {
|
|
let query = [
|
|
kSecAttrService: service,
|
|
kSecAttrAccount: account,
|
|
kSecClass: kSecClassGenericPassword
|
|
] as [CFString: Any] as CFDictionary
|
|
|
|
let updates = [
|
|
kSecValueData: newValue.data(using: .utf8) as Any
|
|
] as CFDictionary
|
|
|
|
status = SecItemUpdate(query, updates)
|
|
}
|
|
} else {
|
|
let query = [
|
|
kSecAttrService: service,
|
|
kSecAttrAccount: account,
|
|
kSecClass: kSecClassGenericPassword
|
|
] as [CFString: Any] as CFDictionary
|
|
|
|
_ = SecItemDelete(query)
|
|
}
|
|
}
|
|
}
|
|
|
|
init(account: String) {
|
|
self.account = account
|
|
}
|
|
}
|