Skip to content

Commit

Permalink
🎨 Make profile request only when scopes are provided
Browse files Browse the repository at this point in the history
  • Loading branch information
lukasackee committed Jul 8, 2021
1 parent 8ff7f19 commit 5b1f23e
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 20 deletions.
1 change: 0 additions & 1 deletion Sources/OpenGoogleSignInSDK/Model/GoogleSignInError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ public enum GoogleSignInError: Error, Equatable {
case authenticationError(Error)
case invalidCode
case invalidResponse
case invalidTokenRequest
case networkError(Error)
case tokenDecodingError(Error)
case userCancelledSignInFlow
Expand Down
48 changes: 29 additions & 19 deletions Sources/OpenGoogleSignInSDK/OpenGoogleSignInSDK.swift
Original file line number Diff line number Diff line change
Expand Up @@ -141,37 +141,26 @@ public final class OpenGoogleSignIn: NSObject {
/// After successful authentication we made another request
/// to obtain user's profile data, e.g. email and name.
private func handleTokenResponse(using redirectUrl: URL, completion: @escaping (Result<GoogleUser, GoogleSignInError>) -> Void) {
guard let code = self.parseCode(from: redirectUrl) else {
guard let code = parseCode(from: redirectUrl) else {
completion(.failure(.invalidCode))
return
}

guard let tokenRequest = makeTokenRequest(with: code) else {
completion(.failure(.invalidTokenRequest))
assertionFailure("Invalid token request")
return
}

makeRequest(tokenRequest) { result in
switch result {
case let .success(data):
do {
var user = try self.decodeUser(from: data)
let user = try self.decodeUser(from: data)

guard let profileRequest = self.makeProfileRequest(user: user) else {
if self.scopes.contains(.email) || self.scopes.contains(.profile) {
self.fetchProfile(user: user, completion: completion)
} else {
completion(.success(user))
return
}

self.makeRequest(profileRequest) { result in
switch result {
case let .success(data):
let profile = try? JSONDecoder.app.decode(GoogleUser.Profile.self, from: data)
user.profile = profile
completion(.success(user))

case let .failure(error):
completion(.failure(.noProfile(error)))
}
}
} catch {
completion(.failure(.tokenDecodingError(error)))
Expand All @@ -182,6 +171,27 @@ public final class OpenGoogleSignIn: NSObject {
}
}
}

private func fetchProfile(user: GoogleUser, completion: @escaping (Result<GoogleUser, GoogleSignInError>) -> Void) {
guard let profileRequest = makeProfileRequest(user: user) else {
assertionFailure("Invalid profile request")
return
}

var user = user

makeRequest(profileRequest) { result in
switch result {
case let .success(data):
let profile = try? JSONDecoder.app.decode(GoogleUser.Profile.self, from: data)
user.profile = profile
completion(.success(user))

case let .failure(error):
completion(.failure(.noProfile(error)))
}
}
}

/// Wrapper for easier `URLRequest` handling.
private func makeRequest(_ request: URLRequest, completion: @escaping (Result<Data, GoogleSignInError>) -> Void) {
Expand Down Expand Up @@ -209,7 +219,7 @@ public final class OpenGoogleSignIn: NSObject {
}

/// Returns `URLRequest` to retrieve Google sign-in OAuth 2.0 token using arameters provided by the app.
private func makeTokenRequest(with code: String) -> URLRequest? {
func makeTokenRequest(with code: String) -> URLRequest? {
guard let tokenURL = OpenGoogleSignIn.tokenURL else { return nil }

var request = URLRequest(url: tokenURL)
Expand All @@ -234,7 +244,7 @@ public final class OpenGoogleSignIn: NSObject {
}

/// Returns `URLRequest` to retrieve user's profile data
private func makeProfileRequest(user: GoogleUser) -> URLRequest? {
func makeProfileRequest(user: GoogleUser) -> URLRequest? {
guard let profileURL = OpenGoogleSignIn.profileURL else { return nil }

var request = URLRequest(url: profileURL)
Expand Down
22 changes: 22 additions & 0 deletions Tests/OpenGoogleSignInSDKTests/OpenGoogleSignInSDKTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,28 @@ final class OpenGoogleSignInTests: XCTestCase {
XCTAssertNotNil(mockDelegate.user)
}

// Since `URL` has optional initializer we need to
// check if the URL provided by us is valid and
// therefore we don't need to worry about this edge case.
func test_tokenRequest_isValid() {
// When
let request = sharedInstance.makeTokenRequest(with: "code")

// Then
XCTAssertNotNil(request)
}

// Since `URL` has optional initializer we need to
// check if the URL provided by us is valid and
// therefore we don't need to worry about this edge case.
func test_profileRequest_isValid() {
// Given
let user = mockUser()

// Then
XCTAssertNotNil(sharedInstance.makeProfileRequest(user: user))
}

// MARK: - Private helpers

private func mockUser() -> GoogleUser {
Expand Down

0 comments on commit 5b1f23e

Please sign in to comment.