2021-04-27 10:26:59 +02:00
|
|
|
//
|
|
|
|
// AppSecret.swift
|
|
|
|
// AppShared
|
|
|
|
//
|
|
|
|
// Created by MainasuK Cirno on 2021-4-27.
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
import Foundation
|
|
|
|
import CryptoKit
|
|
|
|
import KeychainAccess
|
|
|
|
import Keys
|
2022-04-29 08:38:18 +02:00
|
|
|
import MastodonCommon
|
2021-04-27 10:26:59 +02:00
|
|
|
|
|
|
|
public final class AppSecret {
|
|
|
|
|
2021-06-11 22:37:54 +02:00
|
|
|
public static let keychain = Keychain(service: "org.joinmastodon.app.keychain", accessGroup: AppName.groupID)
|
2021-04-27 10:26:59 +02:00
|
|
|
|
|
|
|
static let notificationPrivateKeyName = "notification-private-key-base64"
|
|
|
|
static let notificationAuthName = "notification-auth-base64"
|
|
|
|
|
|
|
|
public let notificationEndpoint: String
|
|
|
|
|
|
|
|
public var notificationPrivateKey: P256.KeyAgreement.PrivateKey {
|
|
|
|
AppSecret.createOrFetchNotificationPrivateKey()
|
|
|
|
}
|
|
|
|
public var notificationPublicKey: P256.KeyAgreement.PublicKey {
|
|
|
|
notificationPrivateKey.publicKey
|
|
|
|
}
|
|
|
|
public var notificationAuth: Data {
|
|
|
|
AppSecret.createOrFetchNotificationAuth()
|
|
|
|
}
|
|
|
|
|
|
|
|
public static let `default`: AppSecret = {
|
|
|
|
return AppSecret()
|
|
|
|
}()
|
|
|
|
|
|
|
|
init() {
|
|
|
|
let keys = MastodonKeys()
|
|
|
|
|
|
|
|
#if DEBUG
|
|
|
|
self.notificationEndpoint = keys.notification_endpoint_debug
|
|
|
|
#else
|
|
|
|
self.notificationEndpoint = keys.notification_endpoint
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
public func register() {
|
|
|
|
_ = AppSecret.createOrFetchNotificationPrivateKey()
|
|
|
|
_ = AppSecret.createOrFetchNotificationAuth()
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
extension AppSecret {
|
|
|
|
|
|
|
|
private static func createOrFetchNotificationPrivateKey() -> P256.KeyAgreement.PrivateKey {
|
|
|
|
if let encoded = AppSecret.keychain[AppSecret.notificationPrivateKeyName],
|
|
|
|
let data = Data(base64Encoded: encoded) {
|
|
|
|
do {
|
|
|
|
let privateKey = try P256.KeyAgreement.PrivateKey(rawRepresentation: data)
|
|
|
|
return privateKey
|
|
|
|
} catch {
|
|
|
|
assertionFailure()
|
|
|
|
return AppSecret.resetNotificationPrivateKey()
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return AppSecret.resetNotificationPrivateKey()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static func resetNotificationPrivateKey() -> P256.KeyAgreement.PrivateKey {
|
|
|
|
let privateKey = P256.KeyAgreement.PrivateKey()
|
|
|
|
keychain[AppSecret.notificationPrivateKeyName] = privateKey.rawRepresentation.base64EncodedString()
|
|
|
|
return privateKey
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
extension AppSecret {
|
|
|
|
|
|
|
|
private static func createOrFetchNotificationAuth() -> Data {
|
|
|
|
if let encoded = keychain[AppSecret.notificationAuthName],
|
|
|
|
let data = Data(base64Encoded: encoded) {
|
|
|
|
return data
|
|
|
|
} else {
|
|
|
|
return AppSecret.resetNotificationAuth()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static func resetNotificationAuth() -> Data {
|
|
|
|
let auth = AppSecret.createRandomAuthBytes()
|
|
|
|
keychain[AppSecret.notificationAuthName] = auth.base64EncodedString()
|
|
|
|
return auth
|
|
|
|
}
|
|
|
|
|
|
|
|
private static func createRandomAuthBytes() -> Data {
|
|
|
|
let byteCount = 16
|
|
|
|
var bytes = Data(count: byteCount)
|
|
|
|
_ = bytes.withUnsafeMutableBytes { SecRandomCopyBytes(kSecRandomDefault, byteCount, $0.baseAddress!) }
|
|
|
|
return bytes
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|