Skip to content

Commit

Permalink
Add VERY BASIC Sign In with Apple
Browse files Browse the repository at this point in the history
  • Loading branch information
ZachOrr committed Mar 19, 2024
1 parent 5d04532 commit 6b85767
Show file tree
Hide file tree
Showing 7 changed files with 263 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ public class MyTBAOperation: TBAOperation {

let request = myTBA.createRequest(method, bodyData)
task = myTBA.urlSession.dataTask(with: request) { [weak self] (data: Data?, response: URLResponse?, error: Error?) in
if let error = error {
if let response = response as? HTTPURLResponse, response.statusCode == 500 {
// Catch 500s as errors
completion(nil, MyTBAError.error(500, "Internal server error"))
} else if let error = error {
completion(nil, error)
} else if let data = data {
#if DEBUG
Expand Down
4 changes: 4 additions & 0 deletions the-blue-alliance-ios.entitlements
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
<dict>
<key>aps-environment</key>
<string>production</string>
<key>com.apple.developer.applesignin</key>
<array>
<string>Default</string>
</array>
<key>com.apple.developer.associated-domains</key>
<array>
<string>activitycontinuation:www.thebluealliance.com</string>
Expand Down
91 changes: 89 additions & 2 deletions the-blue-alliance-ios.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 52;
objectVersion = 60;
objects = {

/* Begin PBXBuildFile section */
Expand Down Expand Up @@ -194,6 +194,13 @@
92DF54E121B1B65A0082C58C /* StatusService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92DF54E021B1B65A0082C58C /* StatusService.swift */; };
92E9F0AB216C439700C1F916 /* NoDataViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92E9F0AA216C439700C1F916 /* NoDataViewController.swift */; };
92F481F11E7DA04B00B4ED7E /* EventsContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92F481F01E7DA04B00B4ED7E /* EventsContainerViewController.swift */; };
92F63E9B2BA91B4F0025CC03 /* MyTBAKit in Frameworks */ = {isa = PBXBuildFile; productRef = 92F63E9A2BA91B4F0025CC03 /* MyTBAKit */; };
92F63E9E2BA91BCA0025CC03 /* Search in Frameworks */ = {isa = PBXBuildFile; productRef = 92F63E9D2BA91BCA0025CC03 /* Search */; };
92F63EA12BA91BD80025CC03 /* TBAData in Frameworks */ = {isa = PBXBuildFile; productRef = 92F63EA02BA91BD80025CC03 /* TBAData */; };
92F63EA42BA91BEC0025CC03 /* TBAKit in Frameworks */ = {isa = PBXBuildFile; productRef = 92F63EA32BA91BEC0025CC03 /* TBAKit */; };
92F63EA72BA91BFB0025CC03 /* TBAOperation in Frameworks */ = {isa = PBXBuildFile; productRef = 92F63EA62BA91BFB0025CC03 /* TBAOperation */; };
92F63EAA2BA91C070025CC03 /* TBAProtocols in Frameworks */ = {isa = PBXBuildFile; productRef = 92F63EA92BA91C070025CC03 /* TBAProtocols */; };
92F63EAD2BA91C170025CC03 /* TBAUtils in Frameworks */ = {isa = PBXBuildFile; productRef = 92F63EAC2BA91C170025CC03 /* TBAUtils */; };
92F79A7623D6536A0026E9E8 /* SearchContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92F79A7523D6536A0026E9E8 /* SearchContainer.swift */; };
92F8E356209AAE890094213F /* PushService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92F8E355209AAE890094213F /* PushService.swift */; };
92FA4D2D228606BB00030BA3 /* TeamHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92FA4D2C228606BB00030BA3 /* TeamHeaderView.swift */; };
Expand Down Expand Up @@ -513,12 +520,19 @@
924BDD9026D2B366008BE7D2 /* FirebaseMessaging in Frameworks */,
9202400D2AEB6ADC0003D118 /* MyTBAKit in Frameworks */,
924BDD8E26D2B366008BE7D2 /* FirebaseCrashlytics in Frameworks */,
92F63EA12BA91BD80025CC03 /* TBAData in Frameworks */,
920240112AEB6AE60003D118 /* TBAData in Frameworks */,
920240072AEB6AAD0003D118 /* PureLayout in Frameworks */,
92F63EA72BA91BFB0025CC03 /* TBAOperation in Frameworks */,
920240092AEB6AC30003D118 /* TBAOperation in Frameworks */,
924BDD8A26D2B366008BE7D2 /* FirebaseAnalyticsWithoutAdIdSupport in Frameworks */,
92F63EAD2BA91C170025CC03 /* TBAUtils in Frameworks */,
9202400F2AEB6ADC0003D118 /* TBAKit in Frameworks */,
92F63E9B2BA91B4F0025CC03 /* MyTBAKit in Frameworks */,
92F63E9E2BA91BCA0025CC03 /* Search in Frameworks */,
92C5FBDF2B0038250006AE48 /* Agrume in Frameworks */,
92F63EAA2BA91C070025CC03 /* TBAProtocols in Frameworks */,
92F63EA42BA91BEC0025CC03 /* TBAKit in Frameworks */,
924BDD9226D2B366008BE7D2 /* FirebaseRemoteConfig in Frameworks */,
924BDD9526D2B391008BE7D2 /* GoogleSignIn in Frameworks */,
);
Expand Down Expand Up @@ -1420,6 +1434,13 @@
920240102AEB6AE60003D118 /* TBAData */,
92C5FBDB2B0037E10006AE48 /* YouTubeiOSPlayerHelper */,
92C5FBDE2B0038250006AE48 /* Agrume */,
92F63E9A2BA91B4F0025CC03 /* MyTBAKit */,
92F63E9D2BA91BCA0025CC03 /* Search */,
92F63EA02BA91BD80025CC03 /* TBAData */,
92F63EA32BA91BEC0025CC03 /* TBAKit */,
92F63EA62BA91BFB0025CC03 /* TBAOperation */,
92F63EA92BA91C070025CC03 /* TBAProtocols */,
92F63EAC2BA91C170025CC03 /* TBAUtils */,
);
productName = "the-blue-alliance";
productReference = 92942D921E2154DA008E79CA /* The Blue Alliance.app */;
Expand Down Expand Up @@ -1493,6 +1514,13 @@
92B3217D26ED1A79003B28DC /* XCRemoteSwiftPackageReference "PureLayout" */,
92C5FBDA2B0037E10006AE48 /* XCRemoteSwiftPackageReference "youtube-ios-player-helper" */,
92C5FBDD2B0038250006AE48 /* XCRemoteSwiftPackageReference "Agrume" */,
92F63E992BA91B4F0025CC03 /* XCLocalSwiftPackageReference "Packages/MyTBAKit" */,
92F63E9C2BA91BCA0025CC03 /* XCLocalSwiftPackageReference "Packages/Search" */,
92F63E9F2BA91BD80025CC03 /* XCLocalSwiftPackageReference "Packages/TBAData" */,
92F63EA22BA91BEC0025CC03 /* XCLocalSwiftPackageReference "Packages/TBAKit" */,
92F63EA52BA91BFB0025CC03 /* XCLocalSwiftPackageReference "Packages/TBAOperation" */,
92F63EA82BA91C070025CC03 /* XCLocalSwiftPackageReference "Packages/TBAProtocols" */,
92F63EAB2BA91C170025CC03 /* XCLocalSwiftPackageReference "Packages/TBAUtils" */,
);
productRefGroup = 92942D931E2154DA008E79CA /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -2159,13 +2187,44 @@
};
/* End XCConfigurationList section */

/* Begin XCLocalSwiftPackageReference section */
92F63E992BA91B4F0025CC03 /* XCLocalSwiftPackageReference "Packages/MyTBAKit" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = Packages/MyTBAKit;
};
92F63E9C2BA91BCA0025CC03 /* XCLocalSwiftPackageReference "Packages/Search" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = Packages/Search;
};
92F63E9F2BA91BD80025CC03 /* XCLocalSwiftPackageReference "Packages/TBAData" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = Packages/TBAData;
};
92F63EA22BA91BEC0025CC03 /* XCLocalSwiftPackageReference "Packages/TBAKit" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = Packages/TBAKit;
};
92F63EA52BA91BFB0025CC03 /* XCLocalSwiftPackageReference "Packages/TBAOperation" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = Packages/TBAOperation;
};
92F63EA82BA91C070025CC03 /* XCLocalSwiftPackageReference "Packages/TBAProtocols" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = Packages/TBAProtocols;
};
92F63EAB2BA91C170025CC03 /* XCLocalSwiftPackageReference "Packages/TBAUtils" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = Packages/TBAUtils;
};
/* End XCLocalSwiftPackageReference section */

/* Begin XCRemoteSwiftPackageReference section */
924BDD8826D2B366008BE7D2 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/firebase/firebase-ios-sdk.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 7.0.0;
minimumVersion = 10.0.0;
};
};
924BDD9326D2B391008BE7D2 /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */ = {
Expand Down Expand Up @@ -2276,6 +2335,34 @@
package = 92C5FBDD2B0038250006AE48 /* XCRemoteSwiftPackageReference "Agrume" */;
productName = Agrume;
};
92F63E9A2BA91B4F0025CC03 /* MyTBAKit */ = {
isa = XCSwiftPackageProductDependency;
productName = MyTBAKit;
};
92F63E9D2BA91BCA0025CC03 /* Search */ = {
isa = XCSwiftPackageProductDependency;
productName = Search;
};
92F63EA02BA91BD80025CC03 /* TBAData */ = {
isa = XCSwiftPackageProductDependency;
productName = TBAData;
};
92F63EA32BA91BEC0025CC03 /* TBAKit */ = {
isa = XCSwiftPackageProductDependency;
productName = TBAKit;
};
92F63EA62BA91BFB0025CC03 /* TBAOperation */ = {
isa = XCSwiftPackageProductDependency;
productName = TBAOperation;
};
92F63EA92BA91C070025CC03 /* TBAProtocols */ = {
isa = XCSwiftPackageProductDependency;
productName = TBAProtocols;
};
92F63EAC2BA91C170025CC03 /* TBAUtils */ = {
isa = XCSwiftPackageProductDependency;
productName = TBAUtils;
};
/* End XCSwiftPackageProductDependency section */

/* Begin XCVersionGroup section */
Expand Down
8 changes: 5 additions & 3 deletions the-blue-alliance-ios/AppDelegate/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
}
}

// Kickoff background myTBA/Google sign in, along with setting up delegates
setupGoogleAuthentication()
// Kickoff background myTBA, along with setting up delegates
setupPreviousAuthentication()

// Our app setup operation will load our persistent stores, propogate persistance container
let appSetupOperation = AppSetupOperation(indexDelegate: indexDelegate, persistentContainer: persistentContainer, tbaKit: tbaKit, userDefaults: userDefaults)
Expand Down Expand Up @@ -294,9 +294,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
myTBA.authenticationProvider.add(observer: pushService)
}

private func setupGoogleAuthentication() {
private func setupPreviousAuthentication() {
// If we're authenticated with Google but don't have a Firebase user, get a Firebase user
if Auth.auth().currentUser == nil, GIDSignIn.sharedInstance.hasPreviousSignIn() {
// TODO: Need to figure out if it's a Google user or an Apple user?
// I suppose, let's print something here...
GIDSignIn.sharedInstance.restorePreviousSignIn { [unowned self] user, error in
if let error = error {
errorRecorder.record(error)
Expand Down
4 changes: 2 additions & 2 deletions the-blue-alliance-ios/StatusDefaults.plist
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
<plist version="1.0">
<dict>
<key>max_season</key>
<real>2022</real>
<integer>2024</integer>
<key>min_app_version</key>
<integer>-1</integer>
<key>latest_app_version</key>
<integer>-1</integer>
<key>current_season</key>
<real>2022</real>
<integer>2024</integer>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import AuthenticationServices
import CryptoKit
import GoogleSignIn
import FirebaseAuth
import Foundation
Expand All @@ -9,7 +11,7 @@ protocol SignInViewControllerDelegate: AnyObject {
func pushRegistrationError(error: Error)
}

class MyTBASignInViewController: UIViewController {
class MyTBASignInViewController: UIViewController, ASAuthorizationControllerPresentationContextProviding {

@IBOutlet var starImageView: UIImageView! {
didSet {
Expand All @@ -22,6 +24,9 @@ class MyTBASignInViewController: UIViewController {

weak var delegate: SignInViewControllerDelegate?

// Unhashed nonce.
fileprivate var currentNonce: String?

init() {
super.init(nibName: String(describing: type(of: self)), bundle: Bundle.main)
}
Expand Down Expand Up @@ -108,4 +113,96 @@ class MyTBASignInViewController: UIViewController {
}
}

// https://firebase.google.com/docs/auth/ios/apple

private func sha256(_ input: String) -> String {
let inputData = Data(input.utf8)
let hashedData = SHA256.hash(data: inputData)
let hashString = hashedData.compactMap {
String(format: "%02x", $0)
}.joined()

return hashString
}

@IBAction private func signInWithApple() {
let nonce = randomNonceString()
currentNonce = nonce
let appleIDProvider = ASAuthorizationAppleIDProvider()
let request = appleIDProvider.createRequest()
request.requestedScopes = [.fullName, .email]
request.nonce = sha256(nonce)

let authorizationController = ASAuthorizationController(authorizationRequests: [request])
authorizationController.delegate = self
authorizationController.presentationContextProvider = self
authorizationController.performRequests()
}

private func randomNonceString(length: Int = 32) -> String {
precondition(length > 0)
var randomBytes = [UInt8](repeating: 0, count: length)
let errorCode = SecRandomCopyBytes(kSecRandomDefault, randomBytes.count, &randomBytes)
if errorCode != errSecSuccess {
fatalError(
"Unable to generate nonce. SecRandomCopyBytes failed with OSStatus \(errorCode)"
)
}

let charset: [Character] =
Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._")

let nonce = randomBytes.map { byte in
// Pick a random character from the set, wrapping around if needed.
charset[Int(byte) % charset.count]
}

return String(nonce)
}

}

extension MyTBASignInViewController: ASAuthorizationControllerDelegate {

func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
return view.window!
}

func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
guard let nonce = currentNonce else {
fatalError("Invalid state: A login callback was received, but no login request was sent.")
}
guard let appleIDToken = appleIDCredential.identityToken else {
print("Unable to fetch identity token")
return
}
guard let idTokenString = String(data: appleIDToken, encoding: .utf8) else {
print("Unable to serialize token string from data: \(appleIDToken.debugDescription)")
return
}
// Initialize a Firebase credential, including the user's full name.
let credential = OAuthProvider.appleCredential(withIDToken: idTokenString,
rawNonce: nonce,
fullName: appleIDCredential.fullName)
// Sign in with Firebase.
Auth.auth().signIn(with: credential) { (authResult, error) in
if let error {
// Error. If error.code == .MissingOrInvalidNonce, make sure
// you're sending the SHA256-hashed nonce as a hex string with
// your request to Apple.
print(error.localizedDescription)
return
}

// TODO: Need to do something here......
}
}
}

func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
// Handle error.
print("Sign in with Apple errored: \(error)")
}

}
Loading

0 comments on commit 6b85767

Please sign in to comment.