Move oauthAuthorizationCodeGrantRequest and requestOAuthAccessToken from FeedlyAccountDelegate to FeedlyAPICaller.

This commit is contained in:
Brent Simmons 2024-05-01 20:36:33 -07:00
parent 15e33e3659
commit 0a4be8f49f
4 changed files with 45 additions and 63 deletions

View File

@ -377,27 +377,6 @@ public enum FetchType {
}
}
internal static func oauthAuthorizationClient(for type: AccountType, secretsProvider: SecretsProvider) -> OAuthAuthorizationClient {
switch type {
case .feedly:
return FeedlyAccountDelegate.environment.oauthAuthorizationClient(secretsProvider: secretsProvider)
default:
fatalError("\(type) is not a client for OAuth authorization code granting.")
}
}
public static func requestOAuthAccessToken(with response: OAuthAuthorizationResponse,
client: OAuthAuthorizationClient,
accountType: AccountType,
transport: Transport = URLSession.webserviceTransport(),
secretsProvider: SecretsProvider) async throws -> OAuthAuthorizationGrant {
guard accountType == .feedly else {
fatalError("\(accountType) does not support OAuth authorization code granting.")
}
return try await FeedlyAccountDelegate.requestOAuthAccessToken(with: response, transport: transport, secretsProvider: secretsProvider)
}
public func receiveRemoteNotification(userInfo: [AnyHashable: Any]) async {
await delegate.receiveRemoteNotification(for: self, userInfo: userInfo)
}

View File

@ -11,46 +11,8 @@ import Web
import Secrets
import Feedly
extension FeedlyAccountDelegate {
private static let oauthAuthorizationGrantScope = "https://cloud.feedly.com/subscriptions"
static func oauthAuthorizationCodeGrantRequest(secretsProvider: SecretsProvider) -> URLRequest {
let client = environment.oauthAuthorizationClient(secretsProvider: secretsProvider)
let authorizationRequest = OAuthAuthorizationRequest(clientID: client.id,
redirectURI: client.redirectURI,
scope: oauthAuthorizationGrantScope,
state: client.state)
let baseURLComponents = environment.baseUrlComponents
return FeedlyAPICaller.authorizationCodeURLRequest(for: authorizationRequest, baseUrlComponents: baseURLComponents)
}
static func requestOAuthAccessToken(with response: OAuthAuthorizationResponse, transport: any Web.Transport, secretsProvider: any Secrets.SecretsProvider) async throws -> OAuthAuthorizationGrant {
let client = environment.oauthAuthorizationClient(secretsProvider: secretsProvider)
let request = OAuthAccessTokenRequest(authorizationResponse: response,
scope: oauthAuthorizationGrantScope,
client: client)
let caller = FeedlyAPICaller(transport: transport, api: environment, secretsProvider: secretsProvider)
let response = try await caller.requestAccessToken(request)
let accessToken = Credentials(type: .oauthAccessToken, username: response.id, secret: response.accessToken)
let refreshToken: Credentials? = {
guard let token = response.refreshToken else {
return nil
}
return Credentials(type: .oauthRefreshToken, username: response.id, secret: token)
}()
let grant = OAuthAuthorizationGrant(accessToken: accessToken, refreshToken: refreshToken)
return grant
}
}
extension FeedlyAccountDelegate {
func refreshAccessToken(with refreshToken: String, client: OAuthAuthorizationClient) async throws -> OAuthAuthorizationGrant {
let request = OAuthRefreshAccessTokenRequest(refreshToken: refreshToken, scope: nil, client: client)

View File

@ -50,13 +50,13 @@ public enum OAuthAccountAuthorizationOperationError: LocalizedError {
public init(accountType: AccountType, secretsProvider: SecretsProvider) {
self.accountType = accountType
self.secretsProvider = secretsProvider
self.oauthClient = Account.oauthAuthorizationClient(for: accountType, secretsProvider: secretsProvider)
self.oauthClient = FeedlyAPICaller.API.cloud.oauthAuthorizationClient(secretsProvider: secretsProvider)
}
@MainActor public func run() {
assert(presentationAnchor != nil, "\(self) outlived presentation anchor.")
let request = FeedlyAccountDelegate.oauthAuthorizationCodeGrantRequest(secretsProvider: secretsProvider)
let request = FeedlyAPICaller.oauthAuthorizationCodeGrantRequest(secretsProvider: secretsProvider)
guard let url = request.url else {
return DispatchQueue.main.async {
@ -120,7 +120,7 @@ public enum OAuthAccountAuthorizationOperationError: LocalizedError {
let response = try OAuthAuthorizationResponse(url: url, client: self.oauthClient)
let tokenResponse = try await Account.requestOAuthAccessToken(with: response, client: oauthClient, accountType: accountType, secretsProvider: secretsProvider)
let tokenResponse = try await FeedlyAPICaller.requestOAuthAccessToken(with: response, transport: URLSession.webserviceTransport(), secretsProvider: secretsProvider)
saveAccount(for: tokenResponse)
} catch is ASWebAuthenticationSessionError {

View File

@ -51,11 +51,13 @@ public protocol FeedlyAPICallerDelegate: AnyObject {
private let baseURLComponents: URLComponents
private let uriComponentAllowed: CharacterSet
private let secretsProvider: SecretsProvider
private let api: FeedlyAPICaller.API
public init(transport: Transport, api: API, secretsProvider: SecretsProvider) {
self.transport = transport
self.baseURLComponents = api.baseUrlComponents
self.secretsProvider = secretsProvider
self.api = api
var urlHostAllowed = CharacterSet.urlHostAllowed
urlHostAllowed.remove("+")
@ -578,6 +580,45 @@ extension FeedlyAPICaller {
}
}
// MARK: - OAuth
extension FeedlyAPICaller {
private static let oauthAuthorizationGrantScope = "https://cloud.feedly.com/subscriptions"
public static func oauthAuthorizationCodeGrantRequest(secretsProvider: SecretsProvider) -> URLRequest {
let client = API.cloud.oauthAuthorizationClient(secretsProvider: secretsProvider)
let authorizationRequest = OAuthAuthorizationRequest(clientID: client.id,
redirectURI: client.redirectURI,
scope: oauthAuthorizationGrantScope,
state: client.state)
let baseURLComponents = API.cloud.baseUrlComponents
return FeedlyAPICaller.authorizationCodeURLRequest(for: authorizationRequest, baseUrlComponents: baseURLComponents)
}
public static func requestOAuthAccessToken(with response: OAuthAuthorizationResponse, transport: any Web.Transport, secretsProvider: any Secrets.SecretsProvider) async throws -> OAuthAuthorizationGrant {
let client = API.cloud.oauthAuthorizationClient(secretsProvider: secretsProvider)
let request = OAuthAccessTokenRequest(authorizationResponse: response,
scope: oauthAuthorizationGrantScope,
client: client)
let caller = FeedlyAPICaller(transport: transport, api: .cloud, secretsProvider: secretsProvider)
let response = try await caller.requestAccessToken(request)
let accessToken = Credentials(type: .oauthAccessToken, username: response.id, secret: response.accessToken)
let refreshToken: Credentials? = {
guard let token = response.refreshToken else {
return nil
}
return Credentials(type: .oauthRefreshToken, username: response.id, secret: token)
}()
let grant = OAuthAuthorizationGrant(accessToken: accessToken, refreshToken: refreshToken)
return grant
}
}
private extension FeedlyAPICaller {
func urlRequest(path: String, method: String, includeJSONHeaders: Bool, includeOAuthToken: Bool) throws -> URLRequest {