Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

App section #12420

Merged
merged 32 commits into from
May 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
2964dfe
Add PhoneAuth details in Settings view
pragatimodi Jan 29, 2024
c594c19
undo SwiftApplication.plist changes
pragatimodi Jan 29, 2024
354a6ef
undo SwiftApplication.plist changes
pragatimodi Jan 29, 2024
3ab2ac8
undo SwiftApplication.plist changes
pragatimodi Jan 29, 2024
ae27388
clang formatting
pragatimodi Jan 29, 2024
e057b17
game center auth login
pragatimodi Feb 6, 2024
b38a988
lint
pragatimodi Feb 6, 2024
c4d8943
correct method name
pragatimodi Feb 6, 2024
121c656
add game center icon
pragatimodi Feb 6, 2024
e6b298f
add game center account linking
pragatimodi Feb 6, 2024
46e2b62
Merge branch 'game-center' of https://github.com/firebase/firebase-io…
pragatimodi Feb 6, 2024
417168b
lint
pragatimodi Feb 6, 2024
660551c
add app-section
pragatimodi Feb 23, 2024
c704b1a
undo accidental changes
pragatimodi Feb 23, 2024
22272f2
lint fixes
pragatimodi Feb 23, 2024
dd5d5a9
add game center to AuthMenu
pragatimodi Feb 23, 2024
cd79c97
add verifyClient() method
pragatimodi Feb 24, 2024
7bf243d
fix .plist line deletion
pragatimodi Mar 12, 2024
9b5639c
fix unit test
pragatimodi Mar 12, 2024
4f8fbb4
Merge branch 'auth-swift' of https://github.com/firebase/firebase-ios…
pragatimodi Mar 18, 2024
0471e5d
Merge branch 'auth-swift' of https://github.com/firebase/firebase-ios…
pragatimodi Mar 18, 2024
72d213d
Merge branch 'settings-phoneauth' of https://github.com/firebase/fire…
pragatimodi Mar 18, 2024
50d308a
Merge branch 'auth-swift' of https://github.com/firebase/firebase-ios…
pragatimodi Apr 3, 2024
ffcee37
Merge branch 'game-center' of https://github.com/firebase/firebase-io…
pragatimodi Apr 3, 2024
db885d7
style.sh changes
pragatimodi Apr 3, 2024
19b6c57
remove authMenu test
pragatimodi Apr 4, 2024
b55b1f1
style
pragatimodi Apr 4, 2024
7235386
comment out AuthMenu UI test
pragatimodi Apr 4, 2024
1c331eb
cleanup
pragatimodi Apr 4, 2024
8171aca
Merge branch 'game-center' of https://github.com/firebase/firebase-io…
pragatimodi Apr 4, 2024
6ad6d58
Merge branch 'auth-swift' of https://github.com/firebase/firebase-ios…
pragatimodi May 6, 2024
efe678e
lint
pragatimodi May 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,19 @@ enum AuthMenu: String {
case custom
case initRecaptcha
case customAuthDomain

/// More intuitively named getter for `rawValue`.
case getToken
case getTokenForceRefresh
case addAuthStateChangeListener
case removeLastAuthStateChangeListener
case addIdTokenChangeListener
case removeLastIdTokenChangeListener
case verifyClient
case deleteApp

// More intuitively named getter for `rawValue`.
var id: String { rawValue }

/// The UI friendly name of the `AuthMenu`. Used for display.
// The UI friendly name of the `AuthMenu`. Used for display.
var name: String {
switch self {
case .settings:
Expand Down Expand Up @@ -71,11 +79,27 @@ enum AuthMenu: String {
return "Initialize reCAPTCHA Enterprise"
case .customAuthDomain:
return "Set Custom Auth Domain"
case .getToken:
return "Get Token"
case .getTokenForceRefresh:
return "Get Token Force Refresh"
case .addAuthStateChangeListener:
return "Add Auth State Change Listener"
case .removeLastAuthStateChangeListener:
return "Remove Last Auth State Change Listener"
case .addIdTokenChangeListener:
return "Add ID Token Change Listener"
case .removeLastIdTokenChangeListener:
return "Remove Last ID Token Change Listener"
case .verifyClient:
return "Verify Client"
case .deleteApp:
return "Delete App"
}
}

/// Failable initializer to create an `AuthMenu` from it's corresponding `name` value.
/// - Parameter rawValue: String value representing `AuthMenu`'s name or type.
// Failable initializer to create an `AuthMenu` from its corresponding `name` value.
// - Parameter rawValue: String value representing `AuthMenu`'s name or type.
init?(rawValue: String) {
switch rawValue {
case "Settings":
Expand Down Expand Up @@ -110,7 +134,24 @@ enum AuthMenu: String {
self = .initRecaptcha
case "Set Custom Auth Domain":
self = .customAuthDomain
default: return nil
case "Get Token":
self = .getToken
case "Get Token Force Refresh":
self = .getTokenForceRefresh
case "Add Auth State Change Listener":
self = .addAuthStateChangeListener
case "Remove Last Auth State Change Listener":
self = .removeLastAuthStateChangeListener
case "Add ID Token Change Listener":
self = .addIdTokenChangeListener
case "Remove Last ID Token Change Listener":
self = .removeLastIdTokenChangeListener
case "Verify Client":
self = .verifyClient
case "Delete App":
self = .deleteApp
default:
return nil
}
}
}
Expand Down Expand Up @@ -172,9 +213,24 @@ extension AuthMenu: DataSourceProvidable {
return Section(headerDescription: header, items: [item])
}

static var appSection: Section {
let header = "APP"
let items: [Item] = [
Item(title: getToken.name),
Item(title: getTokenForceRefresh.name),
Item(title: addAuthStateChangeListener.name),
Item(title: removeLastAuthStateChangeListener.name),
Item(title: addIdTokenChangeListener.name),
Item(title: removeLastIdTokenChangeListener.name),
Item(title: verifyClient.name),
Item(title: deleteApp.name),
]
return Section(headerDescription: header, items: items)
}

static var sections: [Section] {
[settingsSection, providerSection, emailPasswordSection, otherSection, recaptchaSection,
customAuthDomainSection]
customAuthDomainSection, appSection]
}

static var authLinkSections: [Section] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,15 @@ extension User: DataSourceProvidable {
// MARK: - UIKit Extensions

public extension UIViewController {
func displayInfo(title: String, message: String, style: UIAlertController.Style) {
let alert = UIAlertController(title: title, message: message, preferredStyle: style)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))

DispatchQueue.main.async { // Ensure UI updates on the main thread
self.present(alert, animated: true, completion: nil)
}
}

func displayError(_ error: Error?, from function: StaticString = #function) {
guard let error = error else { return }
print("ⓧ Error in \(function): \(error.localizedDescription)")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

// For Sign in with Facebook
import FBSDKLoginKit
import FirebaseAuth
@testable import FirebaseAuth

// [START auth_import]
import FirebaseCore
Expand All @@ -33,6 +33,8 @@ private let kFacebookAppID = "ENTER APP ID HERE"

class AuthViewController: UIViewController, DataSourceProviderDelegate {
var dataSourceProvider: DataSourceProvider<AuthMenu>!
var authStateDidChangeListeners: [AuthStateDidChangeListenerHandle] = []
var IDTokenDidChangeListeners: [IDTokenDidChangeListenerHandle] = []

override func loadView() {
view = UITableView(frame: .zero, style: .insetGrouped)
Expand Down Expand Up @@ -95,6 +97,30 @@ class AuthViewController: UIViewController, DataSourceProviderDelegate {

case .customAuthDomain:
performCustomAuthDomainFlow()

case .getToken:
getUserTokenResult(force: false)

case .getTokenForceRefresh:
getUserTokenResult(force: true)

case .addAuthStateChangeListener:
addAuthStateListener()

case .removeLastAuthStateChangeListener:
removeAuthStateListener()

case .addIdTokenChangeListener:
addIDTokenListener()

case .removeLastIdTokenChangeListener:
removeIDTokenListener()

case .verifyClient:
verifyClient()

case .deleteApp:
deleteApp()
}
}

Expand Down Expand Up @@ -316,6 +342,142 @@ class AuthViewController: UIViewController, DataSourceProviderDelegate {
present(prompt, animated: true)
}

private func getUserTokenResult(force: Bool) {
guard let currentUser = Auth.auth().currentUser else {
print("Error: No user logged in")
return
}

currentUser.getIDTokenResult(forcingRefresh: force, completion: { tokenResult, error in
if error != nil {
print("Error: Error refreshing token")
return // Handle error case, returning early
}

if let tokenResult = tokenResult, let claims = tokenResult.claims as? [String: Any] {
var message = "Token refresh succeeded\n\n"
for (key, value) in claims {
message += "\(key): \(value)\n"
}
self.displayInfo(title: "Info", message: message, style: .alert)
} else {
print("Error: Unable to access claims.")
}
})
}

private func addAuthStateListener() {
weak var weakSelf = self
let index = authStateDidChangeListeners.count
print("Auth State Did Change Listener #\(index) was added.")
let handle = Auth.auth().addStateDidChangeListener { [weak weakSelf] auth, user in
guard weakSelf != nil else { return }
print("Auth State Did Change Listener #\(index) was invoked on user '\(user?.uid ?? "nil")'")
}
authStateDidChangeListeners.append(handle)
}

private func removeAuthStateListener() {
guard !authStateDidChangeListeners.isEmpty else {
print("No remaining Auth State Did Change Listeners.")
return
}
let index = authStateDidChangeListeners.count - 1
let handle = authStateDidChangeListeners.last!
Auth.auth().removeStateDidChangeListener(handle)
authStateDidChangeListeners.removeLast()
print("Auth State Did Change Listener #\(index) was removed.")
}

private func addIDTokenListener() {
weak var weakSelf = self
let index = IDTokenDidChangeListeners.count
print("ID Token Did Change Listener #\(index) was added.")
let handle = Auth.auth().addIDTokenDidChangeListener { [weak weakSelf] auth, user in
guard weakSelf != nil else { return }
print("ID Token Did Change Listener #\(index) was invoked on user '\(user?.uid ?? "")'.")
}
IDTokenDidChangeListeners.append(handle)
}

func removeIDTokenListener() {
guard !IDTokenDidChangeListeners.isEmpty else {
print("No remaining ID Token Did Change Listeners.")
return
}
let index = IDTokenDidChangeListeners.count - 1
let handle = IDTokenDidChangeListeners.last!
Auth.auth().removeIDTokenDidChangeListener(handle)
IDTokenDidChangeListeners.removeLast()
print("ID Token Did Change Listener #\(index) was removed.")
}

func verifyClient() {
AppManager.shared.auth().tokenManager.getTokenInternal { token, error in
if token == nil {
print("Verify iOS Client failed.")
return
}
let request = VerifyClientRequest(
withAppToken: token?.string,
isSandbox: token?.type == .sandbox,
requestConfiguration: AppManager.shared.auth().requestConfiguration
)

Task {
do {
let verifyResponse = try await AuthBackend.call(with: request)

guard let receipt = verifyResponse.receipt,
let timeoutDate = verifyResponse.suggestedTimeOutDate else {
print("Internal Auth Error: invalid VerifyClientResponse.")
return
}

let timeout = timeoutDate.timeIntervalSinceNow
do {
let credential = await AppManager.shared.auth().appCredentialManager
.didStartVerification(
withReceipt: receipt,
timeout: timeout
)

guard credential.secret != nil else {
print("Failed to receive remote notification to verify App ID.")
return
}

let testPhoneNumber = "+16509964692"
let request = SendVerificationCodeRequest(
phoneNumber: testPhoneNumber,
codeIdentity: CodeIdentity.credential(credential),
requestConfiguration: AppManager.shared.auth().requestConfiguration
)

do {
_ = try await AuthBackend.call(with: request)
print("Verify iOS client succeeded")
} catch {
print("Verify iOS Client failed: \(error.localizedDescription)")
}
}
} catch {
print("Verify iOS Client failed: \(error.localizedDescription)")
}
}
}
}

func deleteApp() {
AppManager.shared.app.delete { success in
if success {
print("App deleted successfully.")
} else {
print("Failed to delete app.")
}
}
}

// MARK: - Private Helpers

private func configureDataSourceProvider() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,15 @@ extension AuthSettings: DataSourceProvidable {

func appCredentialString() -> String {
if let credential = AppManager.shared.auth().appCredentialManager.credential {
let message = "receipt: \(credential.receipt)\nsecret: \(credential.secret)"

showPromptWithTitle("Clear App Credential?", message: message,
showCancelButton: true) { userPressedOK, _ in
if userPressedOK {
AppManager.shared.auth().appCredentialManager.clearCredential()
}
}
}
let truncatedReceipt = truncatedString(string: credential.receipt, length: 13)
let truncatedSecret = truncatedString(string: credential.secret ?? "", length: 13)
return "\(truncatedReceipt)/\(truncatedSecret)"
Expand Down
Loading