From 8a339ec171c3f4787a62808e2f9e8afbf2c06af5 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Thu, 11 Apr 2024 22:19:29 -0400 Subject: [PATCH] Reregister client when adding push scope --- .../UserAccounts/UserAccountInfo.swift | 4 +- .../UserAccounts/UserAccountsManager.swift | 6 ++- Tusker/API/MastodonController.swift | 5 +- .../PreferencesNavigationController.swift | 49 +++++++++++++++++-- 4 files changed, 55 insertions(+), 9 deletions(-) diff --git a/Packages/UserAccounts/Sources/UserAccounts/UserAccountInfo.swift b/Packages/UserAccounts/Sources/UserAccounts/UserAccountInfo.swift index d35c43df..fee1540c 100644 --- a/Packages/UserAccounts/Sources/UserAccounts/UserAccountInfo.swift +++ b/Packages/UserAccounts/Sources/UserAccounts/UserAccountInfo.swift @@ -11,8 +11,8 @@ import CryptoKit public struct UserAccountInfo: Equatable, Hashable, Identifiable, Sendable { public let id: String public let instanceURL: URL - public let clientID: String - public let clientSecret: String + 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]? diff --git a/Packages/UserAccounts/Sources/UserAccounts/UserAccountsManager.swift b/Packages/UserAccounts/Sources/UserAccounts/UserAccountsManager.swift index 63309dd6..e0d197fc 100644 --- a/Packages/UserAccounts/Sources/UserAccounts/UserAccountsManager.swift +++ b/Packages/UserAccounts/Sources/UserAccounts/UserAccountsManager.swift @@ -148,12 +148,14 @@ public class UserAccountsManager: ObservableObject { accounts[index] = account } - public func updateAccessToken(_ account: UserAccountInfo, token: String, scopes: [String]) { + public func updateCredentials(_ account: UserAccountInfo, clientID: String, clientSecret: String, accessToken: String, scopes: [String]) { guard let index = accounts.firstIndex(where: { $0.id == account.id }) else { return } var account = account - account.accessToken = token + account.clientID = clientID + account.clientSecret = clientSecret + account.accessToken = accessToken account.scopes = scopes accounts[index] = account } diff --git a/Tusker/API/MastodonController.swift b/Tusker/API/MastodonController.swift index 5911a421..f587b90a 100644 --- a/Tusker/API/MastodonController.swift +++ b/Tusker/API/MastodonController.swift @@ -173,8 +173,9 @@ final class MastodonController: ObservableObject, Sendable { } /// - Returns: A tuple of client ID and client secret. - func registerApp() async throws -> (String, String) { - if let clientID = client.clientID, + func registerApp(reregister: Bool = false) async throws -> (String, String) { + if !reregister, + let clientID = client.clientID, let clientSecret = client.clientSecret { return (clientID, clientSecret) } else { diff --git a/Tusker/Screens/Preferences/PreferencesNavigationController.swift b/Tusker/Screens/Preferences/PreferencesNavigationController.swift index a9870224..a1403095 100644 --- a/Tusker/Screens/Preferences/PreferencesNavigationController.swift +++ b/Tusker/Screens/Preferences/PreferencesNavigationController.swift @@ -121,13 +121,54 @@ class PreferencesNavigationController: UINavigationController { guard let account = notification.object as? UserAccountInfo else { return } + + let dimmingView = UIView() + dimmingView.translatesAutoresizingMaskIntoConstraints = false + dimmingView.backgroundColor = .black.withAlphaComponent(0.1) + + let blur = UIBlurEffect(style: .prominent) + let blurView = UIVisualEffectView(effect: blur) + blurView.translatesAutoresizingMaskIntoConstraints = false + blurView.layer.cornerRadius = 15 + blurView.layer.masksToBounds = true + + let spinner = UIActivityIndicatorView(style: .large) + spinner.translatesAutoresizingMaskIntoConstraints = false + spinner.startAnimating() + + blurView.contentView.addSubview(spinner) + dimmingView.addSubview(blurView) + view.addSubview(dimmingView) + NSLayoutConstraint.activate([ + dimmingView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + dimmingView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + dimmingView.topAnchor.constraint(equalTo: view.topAnchor), + dimmingView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + + blurView.widthAnchor.constraint(equalToConstant: 100), + blurView.heightAnchor.constraint(equalToConstant: 100), + blurView.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor), + blurView.centerYAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerYAnchor), + + spinner.centerXAnchor.constraint(equalTo: blurView.contentView.centerXAnchor), + spinner.centerYAnchor.constraint(equalTo: blurView.contentView.centerYAnchor), + ]) + dimmingView.layer.opacity = 0 + blurView.transform = CGAffineTransform(scaleX: 1.2, y: 1.2) + UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseInOut) { + dimmingView.layer.opacity = 1 + blurView.transform = .identity + } + Task { do { - let service = GetAuthorizationTokenService(instanceURL: account.instanceURL, clientID: account.clientID, presentationContextProvider: self) - let code = try await service.run() let mastodonController = MastodonController.getForAccount(account) + let (clientID, clientSecret) = try await mastodonController.registerApp(reregister: true) + + let service = GetAuthorizationTokenService(instanceURL: account.instanceURL, clientID: clientID, presentationContextProvider: self) + let code = try await service.run() let token = try await mastodonController.authorize(authorizationCode: code) - UserAccountsManager.shared.updateAccessToken(account, token: token, scopes: MastodonController.oauthScopes.map(\.rawValue)) + UserAccountsManager.shared.updateCredentials(account, clientID: clientID, clientSecret: clientSecret, accessToken: token, scopes: MastodonController.oauthScopes.map(\.rawValue)) // try to revoke the old token try? await Client(baseURL: account.instanceURL, accessToken: account.accessToken, clientID: account.clientID, clientSecret: account.clientSecret).revokeAccessToken() } catch { @@ -135,6 +176,8 @@ class PreferencesNavigationController: UINavigationController { alert.addAction(UIAlertAction(title: "OK", style: .default)) self.present(alert, animated: true) } + + dimmingView.removeFromSuperview() } }