I have a password managing app. Currently, I store all of the user's accounts (i.e. Netflix, Spotify, etc) in an array that is then stored in User Defaults. Now, I want to make things more secure by storing each account in iOS keychain. I realized that even if I store each account in keychain, I will still need to keep track of them all in a data structure (for populating tableviews, etc) and that data structure will need to be stored somewhere. I am struggling to understand the best way to go about implementing this.
My current design approach is to have: • An array of custom Account objects stored in User Defaults • each Account in the array is stored in keychain
I am using Locksmith for working with keychain (Note: I'm not married to this framework). Locksmith requires me to implement several protocols in my Account class. This is then confusing me when it comes to trying to encode Account objects into the master array being stored in User Defaults. I am trying to make Account conform to Codable and am royally confused about what is going/needs to go on on this point.
class Account: ReadableSecureStorable,
CreateableSecureStorable,
DeleteableSecureStorable,
GenericPasswordSecureStorable,
Codable {
var username: String // can i make these let's
var password: String
// Required by GenericPasswordSecureStorable
let service: String
var account: String { return username }
// Required by CreateableSecureStorable
var data: [String: Any] {
return ["password": password]
}
init(service: String, username: String, password: String) {
self.username = username
self.password = password
self.service = service
}
private enum CodingKeys: String, CodingKey {
case username
case password = "secret"
case service
}
}
struct AccountDefaults {
static private let accountsKey = "accountsKey"
static var accounts: [Account] = {
guard let data = UserDefaults.standard.data(forKey: accountsKey) else { return [] }
return try! JSONDecoder().decode([Account].self, from: data)
}() {
didSet {
guard let data = try? JSONEncoder().encode(accounts) else { return }
UserDefaults.standard.set(data, forKey: accountsKey)
}
}
}
I was getting errors stating that Account does not conform to decodable before adding the codingKeys enum.
From here on, I can't figure out where to go.
When I add an account, I can store it with Locksmith. Will the default codingKeys password override the real password I'm trying to save into keychain?
I know I'm not supposed to include multiple questions here, but the thoughts going through my head are: What do I need to encode/decode? How does using Locksmith affect what I need to encode/decode? Will the password need to be encoded?