frenzy-ios/Persistence/Sources/Persistence/LocalData.swift

84 lines
2.5 KiB
Swift

//
// LocalData.swift
// Reader
//
// Created by Shadowfacts on 11/25/21.
//
import Foundation
import Fervor
import CryptoKit
public struct LocalData {
private init() {}
private static let encoder = JSONEncoder()
private static let decoder = JSONDecoder()
public static var defaults = UserDefaults(suiteName: "group.net.shadowfacts.Reader")!
public static var accounts: [Account] {
get {
guard let data = defaults.data(forKey: "accounts"),
let accounts = try? decoder.decode([Account].self, from: data) else {
return []
}
return accounts
}
set {
let data = try! encoder.encode(newValue)
defaults.set(data, forKey: "accounts")
}
}
public static var mostRecentAccountID: Data? {
get {
return defaults.data(forKey: "mostRecentAccountID")
}
set {
defaults.set(newValue, forKey: "mostRecentAccountID")
}
}
public static func mostRecentAccount() -> Account? {
guard let id = mostRecentAccountID else {
return nil
}
return account(with: id)
}
public static func account(with id: Data) -> Account? {
return accounts.first(where: { $0.id == id })
}
public struct Account: Codable {
public let id: Data
public let instanceURL: URL
public let clientID: String
public let clientSecret: String
public let token: Token
/// A filename-safe string for this account
public var persistenceKey: String {
// slashes the base64 string turn into subdirectories which we don't want
id.base64EncodedString().replacingOccurrences(of: "/", with: "_")
}
public init(instanceURL: URL, clientID: String, clientSecret: String, token: Token) {
// we use a hash of instance host and account id rather than random ids so that
// user activites can uniquely identify accounts across devices
var hasher = SHA256()
hasher.update(data: instanceURL.host!.data(using: .utf8)!)
hasher.update(data: token.owner!.data(using: .utf8)!)
self.id = Data(hasher.finalize())
self.instanceURL = instanceURL
self.clientID = clientID
self.clientSecret = clientSecret
self.token = token
}
}
}