101 lines
3.9 KiB
Swift
101 lines
3.9 KiB
Swift
//
|
|
// https://mczachurski.dev
|
|
// Copyright © 2022 Marcin Czachurski and the repository contributors.
|
|
// Licensed under the Apache License 2.0.
|
|
//
|
|
|
|
import Foundation
|
|
import OAuthSwift
|
|
import AuthenticationServices
|
|
|
|
public extension PixelfedClient {
|
|
|
|
/// Creates OAuth application in Pixelfed.
|
|
func createApp(named name: String,
|
|
redirectUri: String,
|
|
scopes: Scopes,
|
|
website: URL) async throws -> Application {
|
|
|
|
let request = try Self.request(
|
|
for: baseURL,
|
|
target: Pixelfed.Apps.register(
|
|
clientName: name,
|
|
redirectUris: redirectUri,
|
|
scopes: scopes.reduce("") { $0 == "" ? $1 : $0 + " " + $1},
|
|
website: website.absoluteString
|
|
)
|
|
)
|
|
|
|
return try await downloadJson(Application.self, request: request)
|
|
}
|
|
|
|
/// Refresh access token..
|
|
func refreshToken(clientId: String, clientSecret: String, refreshToken: String) async throws -> OAuthSwiftCredential {
|
|
oauthClient = OAuth2Swift(
|
|
consumerKey: clientId,
|
|
consumerSecret: clientSecret,
|
|
authorizeUrl: baseURL.appendingPathComponent("oauth/authorize"),
|
|
accessTokenUrl: baseURL.appendingPathComponent("oauth/token"),
|
|
responseType: "code"
|
|
)
|
|
|
|
return try await withCheckedThrowingContinuation { [weak self] continuation in
|
|
self?.oAuthContinuation = continuation
|
|
|
|
oauthClient?.renewAccessToken(
|
|
withRefreshToken: refreshToken,
|
|
completionHandler: { result in
|
|
switch result {
|
|
case let .success((credentials, _, _)):
|
|
continuation.resume(with: .success(credentials))
|
|
case let .failure(error):
|
|
continuation.resume(throwing: error)
|
|
}
|
|
self?.oAuthContinuation = nil
|
|
})
|
|
}
|
|
}
|
|
|
|
/// User authentication.
|
|
func authenticate(app: Application,
|
|
scope: Scopes,
|
|
callbackUrlScheme: String,
|
|
presentationContextProvider: ASWebAuthenticationPresentationContextProviding
|
|
) async throws -> OAuthSwiftCredential {
|
|
|
|
oauthClient = OAuth2Swift(
|
|
consumerKey: app.clientId,
|
|
consumerSecret: app.clientSecret,
|
|
authorizeUrl: baseURL.appendingPathComponent("oauth/authorize"),
|
|
accessTokenUrl: baseURL.appendingPathComponent("oauth/token"),
|
|
responseType: "code"
|
|
)
|
|
|
|
oauthClient?.authorizeURLHandler = ASWebAuthenticationURLHandler(callbackUrlScheme: callbackUrlScheme,
|
|
presentationContextProvider: presentationContextProvider,
|
|
prefersEphemeralWebBrowserSession: true)
|
|
|
|
return try await withCheckedThrowingContinuation { [weak self] continuation in
|
|
self?.oAuthContinuation = continuation
|
|
oAuthHandle = oauthClient?.authorize(
|
|
withCallbackURL: app.redirectUri,
|
|
scope: scope.joined(separator: " "),
|
|
state: "PixELfed_AUTH",
|
|
completionHandler: { result in
|
|
switch result {
|
|
case let .success((credentials, _, _)):
|
|
continuation.resume(with: .success(credentials))
|
|
case let .failure(error):
|
|
continuation.resume(throwing: error)
|
|
}
|
|
self?.oAuthContinuation = nil
|
|
}
|
|
)
|
|
}
|
|
}
|
|
|
|
static func handleOAuthResponse(url: URL) {
|
|
OAuthSwift.handle(url: url)
|
|
}
|
|
}
|