forked from shadowfacts/Tusker
112 lines
4.1 KiB
Swift
112 lines
4.1 KiB
Swift
//
|
|
// UserAccountInfo.swift
|
|
// UserAccounts
|
|
//
|
|
// Created by Shadowfacts on 3/5/23.
|
|
//
|
|
|
|
import Foundation
|
|
import CryptoKit
|
|
|
|
public struct UserAccountInfo: Equatable, Hashable, Identifiable, Sendable {
|
|
public let id: String
|
|
public let instanceURL: URL
|
|
public internal(set) var clientID: String
|
|
public internal(set) var clientSecret: String
|
|
public let username: String!
|
|
public internal(set) var accessToken: String
|
|
public internal(set) var scopes: [String]?
|
|
|
|
// Sort of hack to be able to access these from the share extension.
|
|
public internal(set) var serverDefaultLanguage: String?
|
|
public internal(set) var serverDefaultVisibility: String?
|
|
public internal(set) var serverDefaultFederation: Bool?
|
|
|
|
fileprivate static let tempAccountID = "temp"
|
|
|
|
static func id(instanceURL: URL, username: String?) -> String {
|
|
// We hash the instance host and username to form the account ID
|
|
// so that account IDs will match across devices, allowing for data syncing and handoff.
|
|
var hasher = SHA256()
|
|
hasher.update(data: instanceURL.host!.data(using: .utf8)!)
|
|
if let username {
|
|
hasher.update(data: username.data(using: .utf8)!)
|
|
}
|
|
return Data(hasher.finalize()).base64EncodedString()
|
|
}
|
|
|
|
/// Only to be used for temporary MastodonController needed to fetch own account info and create final UserAccountInfo with real username
|
|
public init(tempInstanceURL instanceURL: URL, clientID: String, clientSecret: String, accessToken: String) {
|
|
self.id = UserAccountInfo.tempAccountID
|
|
self.instanceURL = instanceURL
|
|
self.clientID = clientID
|
|
self.clientSecret = clientSecret
|
|
self.username = nil
|
|
self.accessToken = accessToken
|
|
self.scopes = nil
|
|
}
|
|
|
|
init(instanceURL: URL, clientID: String, clientSecret: String, username: String? = nil, accessToken: String, scopes: [String]) {
|
|
self.id = UserAccountInfo.id(instanceURL: instanceURL, username: username)
|
|
self.instanceURL = instanceURL
|
|
self.clientID = clientID
|
|
self.clientSecret = clientSecret
|
|
self.username = username
|
|
self.accessToken = accessToken
|
|
self.scopes = scopes
|
|
}
|
|
|
|
init?(userDefaultsDict dict: [String: Any]) {
|
|
guard let id = dict["id"] as? String,
|
|
let instanceURL = dict["instanceURL"] as? String,
|
|
let url = URL(string: instanceURL),
|
|
let clientID = dict["clientID"] as? String,
|
|
let secret = dict["clientSecret"] as? String,
|
|
let accessToken = dict["accessToken"] as? String else {
|
|
return nil
|
|
}
|
|
self.id = id
|
|
self.instanceURL = url
|
|
self.clientID = clientID
|
|
self.clientSecret = secret
|
|
self.username = dict["username"] as? String
|
|
self.accessToken = accessToken
|
|
self.scopes = dict["scopes"] as? [String]
|
|
self.serverDefaultLanguage = dict["serverDefaultLanguage"] as? String
|
|
self.serverDefaultVisibility = dict["serverDefaultVisibility"] as? String
|
|
self.serverDefaultFederation = dict["serverDefaultFederation"] as? Bool
|
|
}
|
|
|
|
var userDefaultsDict: [String: Any] {
|
|
var dict: [String: Any] = [
|
|
"id": id,
|
|
"instanceURL": instanceURL.absoluteString,
|
|
"clientID": clientID,
|
|
"clientSecret": clientSecret,
|
|
"accessToken": accessToken,
|
|
]
|
|
if let username {
|
|
dict["username"] = username
|
|
}
|
|
if let scopes {
|
|
dict["scopes"] = scopes
|
|
}
|
|
if let serverDefaultLanguage {
|
|
dict["serverDefaultLanguage"] = serverDefaultLanguage
|
|
}
|
|
if let serverDefaultVisibility {
|
|
dict["serverDefaultVisibility"] = serverDefaultVisibility
|
|
}
|
|
if let serverDefaultFederation {
|
|
dict["serverDefaultFederation"] = serverDefaultFederation
|
|
}
|
|
return dict
|
|
}
|
|
|
|
/// A filename-safe string for this account
|
|
public var persistenceKey: String {
|
|
// slashes are not allowed in the persistent store coordinator name
|
|
id.replacingOccurrences(of: "/", with: "_")
|
|
}
|
|
}
|