From 32830e95494a484f1f72476563353de73b848b30 Mon Sep 17 00:00:00 2001 From: Andrei Diaconu Date: Sun, 17 Feb 2019 22:00:59 +0200 Subject: [PATCH] Revert "Introduce credentials to firebase_auth (#928)" This reverts commit 3658ccc469d244785bc75ed321c3a546a0f30ce8. --- packages/firebase_auth/CHANGELOG.md | 7 - .../firebaseauth/FirebaseAuthPlugin.java | 248 +++- packages/firebase_auth/example/lib/main.dart | 7 +- .../ios/Classes/FirebaseAuthPlugin.m | 168 ++- packages/firebase_auth/lib/firebase_auth.dart | 1054 ++++++++++++++++- .../lib/src/auth_credential.dart | 13 - .../firebase_auth/lib/src/auth_exception.dart | 14 - .../auth_provider/email_auth_provider.dart | 19 - .../auth_provider/facebook_auth_provider.dart | 16 - .../auth_provider/github_auth_provider.dart | 13 - .../auth_provider/google_auth_provider.dart | 19 - .../auth_provider/phone_auth_provider.dart | 19 - .../auth_provider/twitter_auth_provider.dart | 19 - .../firebase_auth/lib/src/firebase_auth.dart | 408 ------- .../firebase_auth/lib/src/firebase_user.dart | 179 --- packages/firebase_auth/lib/src/user_info.dart | 37 - .../firebase_auth/lib/src/user_metadata.dart | 16 - .../lib/src/user_update_info.dart | 23 - packages/firebase_auth/pubspec.yaml | 2 +- .../test/firebase_auth_test.dart | 389 +++--- 20 files changed, 1503 insertions(+), 1167 deletions(-) delete mode 100644 packages/firebase_auth/lib/src/auth_credential.dart delete mode 100644 packages/firebase_auth/lib/src/auth_exception.dart delete mode 100644 packages/firebase_auth/lib/src/auth_provider/email_auth_provider.dart delete mode 100644 packages/firebase_auth/lib/src/auth_provider/facebook_auth_provider.dart delete mode 100644 packages/firebase_auth/lib/src/auth_provider/github_auth_provider.dart delete mode 100644 packages/firebase_auth/lib/src/auth_provider/google_auth_provider.dart delete mode 100644 packages/firebase_auth/lib/src/auth_provider/phone_auth_provider.dart delete mode 100644 packages/firebase_auth/lib/src/auth_provider/twitter_auth_provider.dart delete mode 100644 packages/firebase_auth/lib/src/firebase_auth.dart delete mode 100644 packages/firebase_auth/lib/src/firebase_user.dart delete mode 100644 packages/firebase_auth/lib/src/user_info.dart delete mode 100644 packages/firebase_auth/lib/src/user_metadata.dart delete mode 100644 packages/firebase_auth/lib/src/user_update_info.dart diff --git a/packages/firebase_auth/CHANGELOG.md b/packages/firebase_auth/CHANGELOG.md index ab3894449584..d0aa9da89192 100644 --- a/packages/firebase_auth/CHANGELOG.md +++ b/packages/firebase_auth/CHANGELOG.md @@ -1,10 +1,3 @@ -## 0.7.0 - -* Introduce third-party auth provider classes that generate `AuthCredential`s -* **Breaking Change** Signing in, linking, and reauthenticating now require an `AuthCredential` -* **Breaking Change** Unlinking now uses providerId -* **Breaking Change** Moved reauthentication to FirebaseUser - ## 0.6.7 * `FirebaseAuth` and `FirebaseUser` are now fully documented. diff --git a/packages/firebase_auth/android/src/main/java/io/flutter/plugins/firebaseauth/FirebaseAuthPlugin.java b/packages/firebase_auth/android/src/main/java/io/flutter/plugins/firebaseauth/FirebaseAuthPlugin.java index 9bf2032da72f..4bf1ce277a29 100755 --- a/packages/firebase_auth/android/src/main/java/io/flutter/plugins/firebaseauth/FirebaseAuthPlugin.java +++ b/packages/firebase_auth/android/src/main/java/io/flutter/plugins/firebaseauth/FirebaseAuthPlugin.java @@ -103,26 +103,62 @@ public void onMethodCall(MethodCall call, Result result) { case "delete": handleDelete(call, result, getAuth(call)); break; - case "signInWithCredential": - handleSignInWithCredential(call, result, getAuth(call)); + case "signInWithEmailAndPassword": + handleSignInWithEmailAndPassword(call, result, getAuth(call)); + break; + case "signInWithGoogle": + handleSignInWithGoogle(call, result, getAuth(call)); break; case "signInWithCustomToken": handleSignInWithCustomToken(call, result, getAuth(call)); break; + case "signInWithFacebook": + handleSignInWithFacebook(call, result, getAuth(call)); + break; + case "signInWithTwitter": + handleSignInWithTwitter(call, result, getAuth(call)); + break; + case "signInWithGithub": + handleSignInWithGithub(call, result, getAuth(call)); + break; case "signOut": handleSignOut(call, result, getAuth(call)); break; case "getIdToken": handleGetToken(call, result, getAuth(call)); break; - case "reauthenticateWithCredential": - handleReauthenticateWithCredential(call, result, getAuth(call)); + case "reauthenticateWithEmailAndPassword": + handleReauthenticateWithEmailAndPassword(call, result, getAuth(call)); + break; + case "reauthenticateWithGoogleCredential": + handleReauthenticateWithGoogleCredential(call, result, getAuth(call)); + break; + case "reauthenticateWithFacebookCredential": + handleReauthenticateWithFacebookCredential(call, result, getAuth(call)); + break; + case "reauthenticateWithTwitterCredential": + handleReauthenticateWithTwitterCredential(call, result, getAuth(call)); + break; + case "reauthenticateWithGithubCredential": + handleReauthenticateWithGithubCredential(call, result, getAuth(call)); break; - case "linkWithCredential": + case "linkWithEmailAndPassword": handleLinkWithEmailAndPassword(call, result, getAuth(call)); break; - case "unlinkFromProvider": - handleUnlinkFromProvider(call, result, getAuth(call)); + case "linkWithGoogleCredential": + handleLinkWithGoogleCredential(call, result, getAuth(call)); + break; + case "linkWithFacebookCredential": + handleLinkWithFacebookCredential(call, result, getAuth(call)); + break; + case "linkWithTwitterCredential": + handleLinkWithTwitterCredential(call, result, getAuth(call)); + break; + case "linkWithGithubCredential": + handleLinkWithGithubCredential(call, result, getAuth(call)); + break; + case "unlinkCredential": + handleUnlinkCredential(call, result, getAuth(call)); break; case "updateEmail": handleUpdateEmail(call, result, getAuth(call)); @@ -345,70 +381,168 @@ private void handleDelete(MethodCall call, Result result, FirebaseAuth firebaseA .addOnCompleteListener(new TaskVoidCompleteListener(result)); } - private AuthCredential getCredential(Map arguments) { - AuthCredential credential; - Map data = (Map) arguments.get("data"); - switch ((String) arguments.get("provider")) { - case EmailAuthProvider.PROVIDER_ID: - { - String email = data.get("email"); - String password = data.get("password"); - credential = EmailAuthProvider.getCredential(email, password); - break; - } - case GoogleAuthProvider.PROVIDER_ID: - { - String idToken = data.get("idToken"); - String accessToken = data.get("accessToken"); - credential = GoogleAuthProvider.getCredential(idToken, accessToken); - break; - } - case FacebookAuthProvider.PROVIDER_ID: - { - String accessToken = data.get("accessToken"); - credential = FacebookAuthProvider.getCredential(accessToken); - break; - } - case TwitterAuthProvider.PROVIDER_ID: - { - String authToken = data.get("authToken"); - String authTokenSecret = data.get("authTokenSecret"); - credential = TwitterAuthProvider.getCredential(authToken, authTokenSecret); - break; - } - case GithubAuthProvider.PROVIDER_ID: - { - String token = data.get("token"); - credential = GithubAuthProvider.getCredential(token); - break; - } - default: - { - credential = null; - break; - } - } - return credential; + private void handleSignInWithEmailAndPassword( + MethodCall call, Result result, FirebaseAuth firebaseAuth) { + Map arguments = call.arguments(); + String email = arguments.get("email"); + String password = arguments.get("password"); + + firebaseAuth + .signInWithEmailAndPassword(email, password) + .addOnCompleteListener(new SignInCompleteListener(result)); } - private void handleSignInWithCredential( - MethodCall call, Result result, FirebaseAuth firebaseAuth) { - AuthCredential credential = getCredential((Map) call.arguments()); + private void handleSignInWithGoogle(MethodCall call, Result result, FirebaseAuth firebaseAuth) { + Map arguments = call.arguments(); + String idToken = arguments.get("idToken"); + String accessToken = arguments.get("accessToken"); + + AuthCredential credential = GoogleAuthProvider.getCredential(idToken, accessToken); firebaseAuth .signInWithCredential(credential) .addOnCompleteListener(new SignInCompleteListener(result)); } - private void handleReauthenticateWithCredential( + private void handleReauthenticateWithEmailAndPassword( MethodCall call, Result result, FirebaseAuth firebaseAuth) { - AuthCredential credential = getCredential((Map) call.arguments()); + Map arguments = call.arguments(); + String email = arguments.get("email"); + String password = arguments.get("password"); + + AuthCredential credential = EmailAuthProvider.getCredential(email, password); + firebaseAuth + .getCurrentUser() + .reauthenticate(credential) + .addOnCompleteListener(new TaskVoidCompleteListener(result)); + } + + private void handleReauthenticateWithGoogleCredential( + MethodCall call, final Result result, FirebaseAuth firebaseAuth) { + Map arguments = call.arguments(); + String idToken = arguments.get("idToken"); + String accessToken = arguments.get("accessToken"); + + AuthCredential credential = GoogleAuthProvider.getCredential(idToken, accessToken); + firebaseAuth + .getCurrentUser() + .reauthenticate(credential) + .addOnCompleteListener(new TaskVoidCompleteListener(result)); + } + + private void handleReauthenticateWithFacebookCredential( + MethodCall call, final Result result, FirebaseAuth firebaseAuth) { + Map arguments = call.arguments(); + String accessToken = arguments.get("accessToken"); + + AuthCredential credential = FacebookAuthProvider.getCredential(accessToken); + firebaseAuth + .getCurrentUser() + .reauthenticate(credential) + .addOnCompleteListener(new TaskVoidCompleteListener(result)); + } + + private void handleReauthenticateWithTwitterCredential( + MethodCall call, final Result result, FirebaseAuth firebaseAuth) { + Map arguments = call.arguments(); + String authToken = arguments.get("authToken"); + String authTokenSecret = arguments.get("authTokenSecret"); + + AuthCredential credential = TwitterAuthProvider.getCredential(authToken, authTokenSecret); firebaseAuth .getCurrentUser() .reauthenticate(credential) .addOnCompleteListener(new TaskVoidCompleteListener(result)); } - private void handleUnlinkFromProvider(MethodCall call, Result result, FirebaseAuth firebaseAuth) { + private void handleReauthenticateWithGithubCredential( + MethodCall call, final Result result, FirebaseAuth firebaseAuth) { + String token = call.argument("token"); + + AuthCredential credential = GithubAuthProvider.getCredential(token); + firebaseAuth + .getCurrentUser() + .reauthenticate(credential) + .addOnCompleteListener(new TaskVoidCompleteListener(result)); + } + + private void handleLinkWithGoogleCredential( + MethodCall call, Result result, FirebaseAuth firebaseAuth) { + Map arguments = call.arguments(); + String idToken = arguments.get("idToken"); + String accessToken = arguments.get("accessToken"); + + AuthCredential credential = GoogleAuthProvider.getCredential(idToken, accessToken); + firebaseAuth + .getCurrentUser() + .linkWithCredential(credential) + .addOnCompleteListener(new SignInCompleteListener(result)); + } + + private void handleLinkWithFacebookCredential( + MethodCall call, Result result, FirebaseAuth firebaseAuth) { + Map arguments = call.arguments(); + String accessToken = arguments.get("accessToken"); + + AuthCredential credential = FacebookAuthProvider.getCredential(accessToken); + firebaseAuth + .getCurrentUser() + .linkWithCredential(credential) + .addOnCompleteListener(new SignInCompleteListener(result)); + } + + private void handleSignInWithFacebook(MethodCall call, Result result, FirebaseAuth firebaseAuth) { + Map arguments = call.arguments(); + String accessToken = arguments.get("accessToken"); + + AuthCredential credential = FacebookAuthProvider.getCredential(accessToken); + firebaseAuth + .signInWithCredential(credential) + .addOnCompleteListener(new SignInCompleteListener(result)); + } + + private void handleSignInWithTwitter(MethodCall call, Result result, FirebaseAuth firebaseAuth) { + String authToken = call.argument("authToken"); + String authTokenSecret = call.argument("authTokenSecret"); + + AuthCredential credential = TwitterAuthProvider.getCredential(authToken, authTokenSecret); + firebaseAuth + .signInWithCredential(credential) + .addOnCompleteListener(new SignInCompleteListener(result)); + } + + private void handleLinkWithTwitterCredential( + MethodCall call, Result result, FirebaseAuth firebaseAuth) { + String authToken = call.argument("authToken"); + String authTokenSecret = call.argument("authTokenSecret"); + + AuthCredential credential = TwitterAuthProvider.getCredential(authToken, authTokenSecret); + firebaseAuth + .getCurrentUser() + .linkWithCredential(credential) + .addOnCompleteListener(new SignInCompleteListener(result)); + } + + private void handleSignInWithGithub(MethodCall call, Result result, FirebaseAuth firebaseAuth) { + String token = call.argument("token"); + + AuthCredential credential = GithubAuthProvider.getCredential(token); + firebaseAuth + .signInWithCredential(credential) + .addOnCompleteListener(new SignInCompleteListener(result)); + } + + private void handleLinkWithGithubCredential( + MethodCall call, Result result, FirebaseAuth firebaseAuth) { + String token = call.argument("token"); + + AuthCredential credential = GithubAuthProvider.getCredential(token); + firebaseAuth + .getCurrentUser() + .linkWithCredential(credential) + .addOnCompleteListener(new SignInCompleteListener(result)); + } + + private void handleUnlinkCredential(MethodCall call, Result result, FirebaseAuth firebaseAuth) { Map arguments = call.arguments(); final String provider = arguments.get("provider"); diff --git a/packages/firebase_auth/example/lib/main.dart b/packages/firebase_auth/example/lib/main.dart index 9d4141e1e58d..2dce1c78b61a 100755 --- a/packages/firebase_auth/example/lib/main.dart +++ b/packages/firebase_auth/example/lib/main.dart @@ -71,11 +71,10 @@ class _MyHomePageState extends State { final GoogleSignInAccount googleUser = await _googleSignIn.signIn(); final GoogleSignInAuthentication googleAuth = await googleUser.authentication; - final AuthCredential credential = GoogleAuthProvider.getCredential( + final FirebaseUser user = await _auth.signInWithGoogle( accessToken: googleAuth.accessToken, idToken: googleAuth.idToken, ); - final FirebaseUser user = await _auth.signInWithCredential(credential); assert(user.email != null); assert(user.displayName != null); assert(!user.isAnonymous); @@ -126,11 +125,11 @@ class _MyHomePageState extends State { } Future _testSignInWithPhoneNumber(String smsCode) async { - final AuthCredential credential = PhoneAuthProvider.getCredential( + final FirebaseUser user = await _auth.signInWithPhoneNumber( verificationId: verificationId, smsCode: smsCode, ); - final FirebaseUser user = await _auth.signInWithCredential(credential); + final FirebaseUser currentUser = await _auth.currentUser(); assert(user.uid == currentUser.uid); diff --git a/packages/firebase_auth/ios/Classes/FirebaseAuthPlugin.m b/packages/firebase_auth/ios/Classes/FirebaseAuthPlugin.m index 5ed02361aca6..5bbeaf30a77d 100644 --- a/packages/firebase_auth/ios/Classes/FirebaseAuthPlugin.m +++ b/packages/firebase_auth/ios/Classes/FirebaseAuthPlugin.m @@ -78,12 +78,38 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result signInAnonymouslyWithCompletion:^(FIRAuthDataResult *authResult, NSError *error) { [self sendResult:result forUser:authResult.user error:error]; }]; - } else if ([@"signInWithCredential" isEqualToString:call.method]) { - [[self getAuth:call.arguments] - signInAndRetrieveDataWithCredential:[self getCredential:call.arguments] - completion:^(FIRAuthDataResult *authResult, NSError *error) { - [self sendResult:result forUser:authResult.user error:error]; - }]; + } else if ([@"signInWithGoogle" isEqualToString:call.method]) { + NSString *idToken = call.arguments[@"idToken"]; + NSString *accessToken = call.arguments[@"accessToken"]; + FIRAuthCredential *credential = [FIRGoogleAuthProvider credentialWithIDToken:idToken + accessToken:accessToken]; + [[self getAuth:call.arguments] signInWithCredential:credential + completion:^(FIRUser *user, NSError *error) { + [self sendResult:result forUser:user error:error]; + }]; + } else if ([@"signInWithFacebook" isEqualToString:call.method]) { + NSString *accessToken = call.arguments[@"accessToken"]; + FIRAuthCredential *credential = [FIRFacebookAuthProvider credentialWithAccessToken:accessToken]; + [[self getAuth:call.arguments] signInWithCredential:credential + completion:^(FIRUser *user, NSError *error) { + [self sendResult:result forUser:user error:error]; + }]; + } else if ([@"signInWithTwitter" isEqualToString:call.method]) { + NSString *authToken = call.arguments[@"authToken"]; + NSString *authTokenSecret = call.arguments[@"authTokenSecret"]; + FIRAuthCredential *credential = [FIRTwitterAuthProvider credentialWithToken:authToken + secret:authTokenSecret]; + [[self getAuth:call.arguments] signInWithCredential:credential + completion:^(FIRUser *user, NSError *error) { + [self sendResult:result forUser:user error:error]; + }]; + } else if ([@"signInWithGithub" isEqualToString:call.method]) { + NSString *token = call.arguments[@"token"]; + FIRAuthCredential *credential = [FIRGitHubAuthProvider credentialWithToken:token]; + [[self getAuth:call.arguments] signInWithCredential:credential + completion:^(FIRUser *user, NSError *error) { + [self sendResult:result forUser:user error:error]; + }]; } else if ([@"createUserWithEmailAndPassword" isEqualToString:call.method]) { NSString *email = call.arguments[@"email"]; NSString *password = call.arguments[@"password"]; @@ -145,19 +171,103 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result completion:^(NSString *_Nullable token, NSError *_Nullable error) { [self sendResult:result forObject:token error:error]; }]; - } else if ([@"reauthenticateWithCredential" isEqualToString:call.method]) { + } else if ([@"reauthenticateWithEmailAndPassword" isEqualToString:call.method]) { + NSString *email = call.arguments[@"email"]; + NSString *password = call.arguments[@"password"]; + FIRAuthCredential *credential = [FIREmailAuthProvider credentialWithEmail:email + password:password]; + [[self getAuth:call.arguments].currentUser + reauthenticateWithCredential:credential + completion:^(NSError *_Nullable error) { + [self sendResult:result forObject:nil error:error]; + }]; + } else if ([@"reauthenticateWithGoogleCredential" isEqualToString:call.method]) { + NSString *idToken = call.arguments[@"idToken"]; + NSString *accessToken = call.arguments[@"accessToken"]; + FIRAuthCredential *credential = [FIRGoogleAuthProvider credentialWithIDToken:idToken + accessToken:accessToken]; [[self getAuth:call.arguments].currentUser - reauthenticateWithCredential:[self getCredential:call.arguments] + reauthenticateWithCredential:credential completion:^(NSError *_Nullable error) { [self sendResult:result forObject:nil error:error]; }]; - } else if ([@"linkWithCredential" isEqualToString:call.method]) { + } else if ([@"reauthenticateWithFacebookCredential" isEqualToString:call.method]) { + NSString *accessToken = call.arguments[@"accessToken"]; + FIRAuthCredential *credential = [FIRFacebookAuthProvider credentialWithAccessToken:accessToken]; [[self getAuth:call.arguments].currentUser - linkWithCredential:[self getCredential:call.arguments] - completion:^(FIRUser *user, NSError *error) { + reauthenticateWithCredential:credential + completion:^(NSError *_Nullable error) { + [self sendResult:result forObject:nil error:error]; + }]; + } else if ([@"reauthenticateWithTwitterCredential" isEqualToString:call.method]) { + NSString *authToken = call.arguments[@"authToken"]; + NSString *authTokenSecret = call.arguments[@"authTokenSecret"]; + FIRAuthCredential *credential = [FIRTwitterAuthProvider credentialWithToken:authToken + secret:authTokenSecret]; + [[self getAuth:call.arguments].currentUser + reauthenticateWithCredential:credential + completion:^(NSError *_Nullable error) { + [self sendResult:result forObject:nil error:error]; + }]; + } else if ([@"reauthenticateWithGithubCredential" isEqualToString:call.method]) { + NSString *token = call.arguments[@"token"]; + FIRAuthCredential *credential = [FIRGitHubAuthProvider credentialWithToken:token]; + [[self getAuth:call.arguments].currentUser + reauthenticateWithCredential:credential + completion:^(NSError *_Nullable error) { + [self sendResult:result forObject:nil error:error]; + }]; + } else if ([@"linkWithEmailAndPassword" isEqualToString:call.method]) { + NSString *email = call.arguments[@"email"]; + NSString *password = call.arguments[@"password"]; + FIRAuthCredential *credential = [FIREmailAuthProvider credentialWithEmail:email + password:password]; + [[self getAuth:call.arguments].currentUser linkWithCredential:credential + completion:^(FIRUser *user, NSError *error) { + [self sendResult:result + forUser:user + error:error]; + }]; + } else if ([@"linkWithGoogleCredential" isEqualToString:call.method]) { + NSString *idToken = call.arguments[@"idToken"]; + NSString *accessToken = call.arguments[@"accessToken"]; + FIRAuthCredential *credential = [FIRGoogleAuthProvider credentialWithIDToken:idToken + accessToken:accessToken]; + [[self getAuth:call.arguments].currentUser linkWithCredential:credential + completion:^(FIRUser *user, NSError *error) { + [self sendResult:result + forUser:user + error:error]; + }]; + } else if ([@"linkWithFacebookCredential" isEqualToString:call.method]) { + NSString *accessToken = call.arguments[@"accessToken"]; + FIRAuthCredential *credential = [FIRFacebookAuthProvider credentialWithAccessToken:accessToken]; + [[self getAuth:call.arguments].currentUser linkWithCredential:credential + completion:^(FIRUser *user, NSError *error) { + [self sendResult:result + forUser:user + error:error]; + }]; + } else if ([@"linkWithTwitterCredential" isEqualToString:call.method]) { + NSString *authToken = call.arguments[@"authToken"]; + NSString *authTokenSecret = call.arguments[@"authTokenSecret"]; + FIRAuthCredential *credential = [FIRTwitterAuthProvider credentialWithToken:authToken + secret:authTokenSecret]; + [[self getAuth:call.arguments].currentUser linkWithCredential:credential + completion:^(FIRUser *user, NSError *error) { + [self sendResult:result + forUser:user + error:error]; + }]; + } else if ([@"linkWithGithubCredential" isEqualToString:call.method]) { + NSString *token = call.arguments[@"token"]; + FIRAuthCredential *credential = [FIRGitHubAuthProvider credentialWithToken:token]; + [[self getAuth:call.arguments].currentUser + linkWithCredential:credential + completion:^(FIRUser *_Nullable user, NSError *_Nullable error) { [self sendResult:result forUser:user error:error]; }]; - } else if ([@"unlinkFromProvider" isEqualToString:call.method]) { + } else if ([@"unlinkCredential" isEqualToString:call.method]) { NSString *provider = call.arguments[@"provider"]; [[self getAuth:call.arguments].currentUser unlinkFromProvider:provider @@ -323,38 +433,4 @@ - (id)mapVerifyPhoneError:(NSError *)error { } return @{@"code" : errorCode, @"message" : error.localizedDescription}; } - -- (FIRAuthCredential *)getCredential:(NSDictionary *)arguments { - NSString *provider = arguments[@"provider"]; - NSDictionary *data = arguments[@"data"]; - FIRAuthCredential *credential; - if ([FIREmailAuthProviderID isEqualToString:provider]) { - NSString *email = data[@"email"]; - NSString *password = data[@"password"]; - credential = [FIREmailAuthProvider credentialWithEmail:email password:password]; - } else if ([FIRGoogleAuthProviderID isEqualToString:provider]) { - NSString *idToken = data[@"idToken"]; - NSString *accessToken = data[@"accessToken"]; - credential = [FIRGoogleAuthProvider credentialWithIDToken:idToken accessToken:accessToken]; - } else if ([FIRFacebookAuthProviderID isEqualToString:provider]) { - NSString *accessToken = data[@"accessToken"]; - credential = [FIRFacebookAuthProvider credentialWithAccessToken:accessToken]; - } else if ([FIRTwitterAuthProviderID isEqualToString:provider]) { - NSString *authToken = data[@"authToken"]; - NSString *authTokenSecret = data[@"authTokenSecret"]; - credential = [FIRTwitterAuthProvider credentialWithToken:authToken secret:authTokenSecret]; - } else if ([FIRGitHubAuthProviderID isEqualToString:provider]) { - NSString *token = data[@"token"]; - credential = [FIRGitHubAuthProvider credentialWithToken:token]; - } else if ([FIRPhoneAuthProviderID isEqualToString:provider]) { - NSString *verificationId = data[@"verificationId"]; - NSString *smsCode = data[@"smsCode"]; - credential = [[FIRPhoneAuthProvider providerWithAuth:[self getAuth:arguments]] - credentialWithVerificationID:verificationId - verificationCode:smsCode]; - } else { - NSLog(@"Support for an auth provider with identifier '%@' is not implemented.", provider); - } - return credential; -} @end diff --git a/packages/firebase_auth/lib/firebase_auth.dart b/packages/firebase_auth/lib/firebase_auth.dart index 1f31ead02dc0..1c377e581ab6 100755 --- a/packages/firebase_auth/lib/firebase_auth.dart +++ b/packages/firebase_auth/lib/firebase_auth.dart @@ -1,8 +1,6 @@ -// Copyright 2018, the Flutter project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library firebase_auth; +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. import 'dart:async'; @@ -10,16 +8,1036 @@ import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/services.dart'; import 'package:meta/meta.dart'; -part 'src/auth_provider/email_auth_provider.dart'; -part 'src/auth_provider/facebook_auth_provider.dart'; -part 'src/auth_provider/github_auth_provider.dart'; -part 'src/auth_provider/google_auth_provider.dart'; -part 'src/auth_provider/phone_auth_provider.dart'; -part 'src/auth_provider/twitter_auth_provider.dart'; -part 'src/auth_credential.dart'; -part 'src/auth_exception.dart'; -part 'src/firebase_auth.dart'; -part 'src/firebase_user.dart'; -part 'src/user_info.dart'; -part 'src/user_metadata.dart'; -part 'src/user_update_info.dart'; +/// Represents user data returned from an identity provider. + +class FirebaseUserMetadata { + FirebaseUserMetadata._(this._data); + + final Map _data; + + int get creationTimestamp => _data['creationTimestamp']; + + int get lastSignInTimestamp => _data['lastSignInTimestamp']; +} + +class UserInfo { + UserInfo._(this._data, this._app); + + final FirebaseApp _app; + + final Map _data; + + /// The provider identifier. + String get providerId => _data['providerId']; + + /// The provider’s user ID for the user. + String get uid => _data['uid']; + + /// The name of the user. + String get displayName => _data['displayName']; + + /// The URL of the user’s profile photo. + String get photoUrl => _data['photoUrl']; + + /// The user’s email address. + String get email => _data['email']; + + /// The user's phone number. + String get phoneNumber => _data['phoneNumber']; + + @override + String toString() { + return '$runtimeType($_data)'; + } +} + +/// Represents user profile data that can be updated by [updateProfile] +/// +/// The purpose of having separate class with a map is to give possibility +/// to check if value was set to null or not provided +class UserUpdateInfo { + /// Container of data that will be send in update request + final Map _updateData = {}; + + set displayName(String displayName) => + _updateData['displayName'] = displayName; + + String get displayName => _updateData['displayName']; + + set photoUrl(String photoUri) => _updateData['photoUrl'] = photoUri; + + String get photoUrl => _updateData['photoUrl']; +} + +/// Represents a user. +class FirebaseUser extends UserInfo { + FirebaseUser._(Map data, FirebaseApp app) + : providerData = data['providerData'] + .map((dynamic item) => UserInfo._(item, app)) + .toList(), + _metadata = FirebaseUserMetadata._(data), + super._(data, app); + + final List providerData; + final FirebaseUserMetadata _metadata; + + // Returns true if the user is anonymous; that is, the user account was + // created with signInAnonymously() and has not been linked to another + // account. + FirebaseUserMetadata get metadata => _metadata; + + bool get isAnonymous => _data['isAnonymous']; + + /// Returns true if the user's email is verified. + bool get isEmailVerified => _data['isEmailVerified']; + + /// Obtains the id token for the current user, forcing a [refresh] if desired. + /// + /// Useful when authenticating against your own backend. Use our server + /// SDKs or follow the official documentation to securely verify the + /// integrity and validity of this token. + /// + /// Completes with an error if the user is signed out. + Future getIdToken({bool refresh = false}) async { + return await FirebaseAuth.channel + .invokeMethod('getIdToken', { + 'refresh': refresh, + 'app': _app.name, + }); + } + + /// Initiates email verification for the user. + Future sendEmailVerification() async { + await FirebaseAuth.channel.invokeMethod( + 'sendEmailVerification', {'app': _app.name}); + } + + /// Manually refreshes the data of the current user (for example, + /// attached providers, display name, and so on). + Future reload() async { + await FirebaseAuth.channel + .invokeMethod('reload', {'app': _app.name}); + } + + /// Deletes the user record from your Firebase project's database. + Future delete() async { + await FirebaseAuth.channel + .invokeMethod('delete', {'app': _app.name}); + } + + /// Updates the email address of the user. + /// + /// The original email address recipient will receive an email that allows + /// them to revoke the email address change, in order to protect them + /// from account hijacking. + /// + /// **Important**: This is a security sensitive operation that requires + /// the user to have recently signed in. + /// + /// Errors: + /// • `ERROR_INVALID_CREDENTIAL` - If the email address is malformed. + /// • `ERROR_EMAIL_ALREADY_IN_USE` - If the email is already in use by a different account. + /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) + /// • `ERROR_USER_NOT_FOUND` - If the user has been deleted (for example, in the Firebase console) + /// • `ERROR_REQUIRES_RECENT_LOGIN` - If the user's last sign-in time does not meet the security threshold. Use reauthenticate methods to resolve. + /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that Email & Password accounts are not enabled. + Future updateEmail(String email) async { + assert(email != null); + return await FirebaseAuth.channel.invokeMethod( + 'updateEmail', + {'email': email, 'app': _app.name}, + ); + } + + /// Updates the password of the user. + /// + /// Anonymous users who update both their email and password will no + /// longer be anonymous. They will be able to log in with these credentials. + /// + /// **Important**: This is a security sensitive operation that requires + /// the user to have recently signed in. + /// + /// Errors: + /// • `ERROR_WEAK_PASSWORD` - If the password is not strong enough. + /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) + /// • `ERROR_USER_NOT_FOUND` - If the user has been deleted (for example, in the Firebase console) + /// • `ERROR_REQUIRES_RECENT_LOGIN` - If the user's last sign-in time does not meet the security threshold. Use reauthenticate methods to resolve. + /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that Email & Password accounts are not enabled. + Future updatePassword(String password) async { + assert(password != null); + return await FirebaseAuth.channel.invokeMethod( + 'updatePassword', + {'password': password, 'app': _app.name}, + ); + } + + /// Updates the user profile information. + /// + /// Errors: + /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) + /// • `ERROR_USER_NOT_FOUND` - If the user has been deleted (for example, in the Firebase console) + Future updateProfile(UserUpdateInfo userUpdateInfo) async { + assert(userUpdateInfo != null); + final Map data = userUpdateInfo._updateData; + data['app'] = _app.name; + return await FirebaseAuth.channel.invokeMethod( + 'updateProfile', + data, + ); + } + + /// Detaches Email & Password from this user. + /// + /// This detaches the Email & Password from the current user. This will + /// prevent the user from signing in to this account with those credentials. + /// + /// **Important**: This is a security sensitive operation that requires + /// the user to have recently signed in. + /// + /// Errors: + /// • `ERROR_NO_SUCH_PROVIDER` - If the user does not have an Email & Password linked to their account. + /// • `ERROR_REQUIRES_RECENT_LOGIN` - If the user's last sign-in time does not meet the security threshold. Use reauthenticate methods to resolve. + Future unlinkEmailAndPassword() async { + return await FirebaseAuth.channel.invokeMethod( + 'unlinkCredential', + {'provider': 'password', 'app': _app.name}, + ); + } + + /// Detaches Google from this user. + /// + /// This detaches the Google Account from the current user. This will + /// prevent the user from signing in to this account with those credentials. + /// + /// **Important**: This is a security sensitive operation that requires + /// the user to have recently signed in. + /// + /// Errors: + /// • `ERROR_NO_SUCH_PROVIDER` - If the user does not have a Google Account linked to their account. + /// • `ERROR_REQUIRES_RECENT_LOGIN` - If the user's last sign-in time does not meet the security threshold. Use reauthenticate methods to resolve. + Future unlinkGoogleCredential() async { + return await FirebaseAuth.channel.invokeMethod( + 'unlinkCredential', + {'provider': 'google.com', 'app': _app.name}, + ); + } + + /// Detaches Facebook from this user. + /// + /// This detaches the Facebook Account from the current user. This will + /// prevent the user from signing in to this account with those credentials. + /// + /// **Important**: This is a security sensitive operation that requires + /// the user to have recently signed in. + /// + /// Errors: + /// • `ERROR_NO_SUCH_PROVIDER` - If the user does not have a Facebook Account linked to their account. + /// • `ERROR_REQUIRES_RECENT_LOGIN` - If the user's last sign-in time does not meet the security threshold. Use reauthenticate methods to resolve. + Future unlinkFacebookCredential() async { + return await FirebaseAuth.channel.invokeMethod( + 'unlinkCredential', + {'provider': 'facebook.com', 'app': _app.name}, + ); + } + + /// Detaches Twitter from this user. + /// + /// This detaches the Twitter Account from the current user. This will + /// prevent the user from signing in to this account with those credentials. + /// + /// **Important**: This is a security sensitive operation that requires + /// the user to have recently signed in. + /// + /// Errors: + /// • `ERROR_NO_SUCH_PROVIDER` - If the user does not have a Twitter Account linked to their account. + /// • `ERROR_REQUIRES_RECENT_LOGIN` - If the user's last sign-in time does not meet the security threshold. Use reauthenticate methods to resolve. + Future unlinkTwitterCredential() async { + return await FirebaseAuth.channel.invokeMethod( + 'unlinkCredential', + {'provider': 'twitter.com', 'app': _app.name}, + ); + } + + /// Detaches Github from this user. + /// + /// This detaches the Github Account from the current user. This will + /// prevent the user from signing in to this account with those credentials. + /// + /// **Important**: This is a security sensitive operation that requires + /// the user to have recently signed in. + /// + /// Errors: + /// • `ERROR_NO_SUCH_PROVIDER` - If the user does not have a Github Account linked to their account. + /// • `ERROR_REQUIRES_RECENT_LOGIN` - If the user's last sign-in time does not meet the security threshold. Use reauthenticate methods to resolve. + Future unlinkGithubCredential() async { + return await FirebaseAuth.channel.invokeMethod( + 'unlinkCredential', + {'provider': 'github.com', 'app': _app.name}, + ); + } + + @override + String toString() { + return '$runtimeType($_data)'; + } +} + +class AuthException implements Exception { + const AuthException(this.code, this.message); + + final String code; + final String message; +} + +typedef void PhoneVerificationCompleted(FirebaseUser firebaseUser); +typedef void PhoneVerificationFailed(AuthException error); +typedef void PhoneCodeSent(String verificationId, [int forceResendingToken]); +typedef void PhoneCodeAutoRetrievalTimeout(String verificationId); + +class FirebaseAuth { + FirebaseAuth._(this.app) { + channel.setMethodCallHandler(_callHandler); + } + + /// Provides an instance of this class corresponding to `app`. + factory FirebaseAuth.fromApp(FirebaseApp app) { + assert(app != null); + return FirebaseAuth._(app); + } + + /// Provides an instance of this class corresponding to the default app. + static final FirebaseAuth instance = FirebaseAuth._(FirebaseApp.instance); + + @visibleForTesting + static const MethodChannel channel = MethodChannel( + 'plugins.flutter.io/firebase_auth', + ); + + final Map> _authStateChangedControllers = + >{}; + + static int nextHandle = 0; + final Map> _phoneAuthCallbacks = + >{}; + + final FirebaseApp app; + + /// Receive [FirebaseUser] each time the user signIn or signOut + Stream get onAuthStateChanged { + Future _handle; + + StreamController controller; + controller = StreamController.broadcast(onListen: () { + _handle = channel.invokeMethod('startListeningAuthState', + {"app": app.name}).then((dynamic v) => v); + _handle.then((int handle) { + _authStateChangedControllers[handle] = controller; + }); + }, onCancel: () { + _handle.then((int handle) async { + await channel.invokeMethod("stopListeningAuthState", + {"id": handle, "app": app.name}); + _authStateChangedControllers.remove(handle); + }); + }); + + return controller.stream; + } + + /// Asynchronously creates and becomes an anonymous user. + /// + /// If there is already an anonymous user signed in, that user will be + /// returned instead. If there is any other existing user signed in, that + /// user will be signed out. + /// + /// **Important**: You must enable Anonymous accounts in the Auth section + /// of the Firebase console before being able to use them. + /// + /// Errors: + /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that Anonymous accounts are not enabled. + Future signInAnonymously() async { + final Map data = await channel + .invokeMethod('signInAnonymously', {"app": app.name}); + final FirebaseUser currentUser = FirebaseUser._(data, app); + return currentUser; + } + + /// Tries to create a new user account with the given email address and password. + /// + /// If successful, it also signs the user in into the app and updates + /// the [onAuthStateChanged] stream. + /// + /// Errors: + /// • `ERROR_WEAK_PASSWORD` - If the password is not strong enough. + /// • `ERROR_INVALID_CREDENTIAL` - If the email address is malformed. + /// • `ERROR_EMAIL_ALREADY_IN_USE` - If the email is already in use by a different account. + Future createUserWithEmailAndPassword({ + @required String email, + @required String password, + }) async { + assert(email != null); + assert(password != null); + final Map data = await channel.invokeMethod( + 'createUserWithEmailAndPassword', + {'email': email, 'password': password, 'app': app.name}, + ); + final FirebaseUser currentUser = FirebaseUser._(data, app); + return currentUser; + } + + /// Returns a list of sign-in methods that can be used to sign in a given + /// user (identified by its main email address). + /// + /// This method is useful when you support multiple authentication mechanisms + /// if you want to implement an email-first authentication flow. + /// + /// Errors: + /// • `ERROR_INVALID_CREDENTIAL` - If the [email] address is malformed. + /// • `ERROR_USER_NOT_FOUND` - If there is no user corresponding to the given [email] address. + Future> fetchSignInMethodsForEmail({ + @required String email, + }) async { + assert(email != null); + final List providers = await channel.invokeMethod( + 'fetchSignInMethodsForEmail', + {'email': email, 'app': app.name}, + ); + return providers?.cast(); + } + + /// Triggers the Firebase Authentication backend to send a password-reset + /// email to the given email address, which must correspond to an existing + /// user of your app. + /// + /// Errors: + /// • `ERROR_INVALID_EMAIL` - If the [email] address is malformed. + /// • `ERROR_USER_NOT_FOUND` - If there is no user corresponding to the given [email] address. + Future sendPasswordResetEmail({ + @required String email, + }) async { + assert(email != null); + return await channel.invokeMethod( + 'sendPasswordResetEmail', + {'email': email, 'app': app.name}, + ); + } + + /// Tries to sign in a user with the given email address and password. + /// + /// If successful, it also signs the user in into the app and updates + /// the [onAuthStateChanged] stream. + /// + /// **Important**: You must enable Email & Password accounts in the Auth + /// section of the Firebase console before being able to use them. + /// + /// Errors: + /// • `ERROR_INVALID_EMAIL` - If the [email] address is malformed. + /// • `ERROR_WRONG_PASSWORD` - If the [password] is wrong. + /// • `ERROR_USER_NOT_FOUND` - If there is no user corresponding to the given [email] address, or if the user has been deleted. + /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) + /// • `ERROR_TOO_MANY_REQUESTS` - If there was too many attempts to sign in as this user. + /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that Email & Password accounts are not enabled. + Future signInWithEmailAndPassword({ + @required String email, + @required String password, + }) async { + assert(email != null); + assert(password != null); + final Map data = await channel.invokeMethod( + 'signInWithEmailAndPassword', + {'email': email, 'password': password, 'app': app.name}, + ); + final FirebaseUser currentUser = FirebaseUser._(data, app); + return currentUser; + } + + /// Tries to sign in a user with the given Google [idToken] and [accessToken]. + /// + /// If successful, it also signs the user in into the app and updates + /// the [onAuthStateChanged] stream. + /// + /// If the user doesn't have an account already, one will be created automatically. + /// + /// **Important**: You must enable Google accounts in the Auth section + /// of the Firebase console before being able to use them. + /// + /// Errors: + /// • `ERROR_INVALID_CREDENTIAL` - If the [authToken] or [authTokenSecret] is malformed or has expired. + /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) + /// • `ERROR_ACCOUNT_EXISTS_WITH_DIFFERENT_CREDENTIAL` - If there already exists an account with the email address asserted by Google. + /// Resolve this case by calling [fetchSignInMethodsForEmail] and then asking the user to sign in using one of them. + /// This error will only be thrown if the "One account per email address" setting is enabled in the Firebase console (recommended). + /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that Google accounts are not enabled. + Future signInWithGoogle({ + @required String idToken, + @required String accessToken, + }) async { + assert(idToken != null); + assert(accessToken != null); + final Map data = await channel.invokeMethod( + 'signInWithGoogle', + { + 'idToken': idToken, + 'accessToken': accessToken, + 'app': app.name, + }, + ); + final FirebaseUser currentUser = FirebaseUser._(data, app); + return currentUser; + } + + /// Tries to sign in a user with the given Facebook [accessToken]. + /// + /// If successful, it also signs the user in into the app and updates + /// the [onAuthStateChanged] stream. + /// + /// If the user doesn't have an account already, one will be created automatically. + /// + /// **Important**: You must enable Facebook accounts in the Auth section + /// of the Firebase console before being able to use them. + /// + /// Errors: + /// • `ERROR_INVALID_CREDENTIAL` - If the [accessToken] is malformed or has expired. + /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) + /// • `ERROR_ACCOUNT_EXISTS_WITH_DIFFERENT_CREDENTIAL` - If there already exists an account with the email address asserted by Facebook. + /// Resolve this case by calling [fetchSignInMethodsForEmail] and then asking the user to sign in using one of them. + /// This error will only be thrown if the "One account per email address" setting is enabled in the Firebase console (recommended). + /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that Facebook accounts are not enabled. + Future signInWithFacebook( + {@required String accessToken}) async { + assert(accessToken != null); + final Map data = + await channel.invokeMethod('signInWithFacebook', { + 'accessToken': accessToken, + 'app': app.name, + }); + final FirebaseUser currentUser = FirebaseUser._(data, app); + return currentUser; + } + + /// Tries to sign in a user with the given Twitter [authToken] and [authTokenSecret]. + /// + /// If successful, it also signs the user in into the app and updates + /// the [onAuthStateChanged] stream. + /// + /// If the user doesn't have an account already, one will be created automatically. + /// + /// **Important**: You must enable Twitter accounts in the Auth section + /// of the Firebase console before being able to use them. + /// + /// Errors: + /// • `ERROR_INVALID_CREDENTIAL` - If the [authToken] or [authTokenSecret] is malformed or has expired. + /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) + /// • `ERROR_ACCOUNT_EXISTS_WITH_DIFFERENT_CREDENTIAL` - If there already exists an account with the email address asserted by Twitter. + /// Resolve this case by calling [fetchSignInMethodsForEmail] and then asking the user to sign in using one of them. + /// This error will only be thrown if the "One account per email address" setting is enabled in the Firebase console (recommended). + /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that Twitter accounts are not enabled. + Future signInWithTwitter({ + @required String authToken, + @required String authTokenSecret, + }) async { + assert(authToken != null); + assert(authTokenSecret != null); + final Map data = + await channel.invokeMethod('signInWithTwitter', { + 'authToken': authToken, + 'authTokenSecret': authTokenSecret, + 'app': app.name, + }); + final FirebaseUser currentUser = FirebaseUser._(data, app); + return currentUser; + } + + /// Tries to sign in a user with the given Github [token]. + /// + /// If successful, it also signs the user in into the app and updates + /// the [onAuthStateChanged] stream. + /// + /// If the user doesn't have an account already, one will be created automatically. + /// + /// **Important**: You must enable Github accounts in the Auth section + /// of the Firebase console before being able to use them. + /// + /// Errors: + /// • `ERROR_INVALID_CREDENTIAL` - If the [token] is malformed or has expired. + /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) + /// • `ERROR_ACCOUNT_EXISTS_WITH_DIFFERENT_CREDENTIAL` - If there already exists an account with the email address asserted by Github. + /// Resolve this case by calling [fetchSignInMethodsForEmail] and then asking the user to sign in using one of them. + /// This error will only be thrown if the "One account per email address" setting is enabled in the Firebase console (recommended). + /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that Github accounts are not enabled. + Future signInWithGithub({ + @required String token, + }) async { + assert(token != null); + final Map data = + await channel.invokeMethod('signInWithGithub', { + 'token': token, + 'app': app.name, + }); + final FirebaseUser currentUser = FirebaseUser._(data, app); + return currentUser; + } + + /// Tries to sign in a user with the given Phone [verificationId] and [smsCode]. + /// + /// If successful, it also signs the user in into the app and updates + /// the [onAuthStateChanged] stream. + /// + /// If the user doesn't have an account already, one will be created automatically. + /// + /// **Important**: You must enable Phone accounts in the Auth section + /// of the Firebase console before being able to use them. + /// + /// Errors: + /// • `ERROR_INVALID_CREDENTIAL` - If the [verificationId] or [smsCode] is malformed or has expired. + /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) + /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that Phone accounts are not enabled. + Future signInWithPhoneNumber({ + @required String verificationId, + @required String smsCode, + }) async { + final Map data = await channel.invokeMethod( + 'signInWithPhoneNumber', + { + 'verificationId': verificationId, + 'smsCode': smsCode, + 'app': app.name, + }, + ); + final FirebaseUser currentUser = FirebaseUser._(data, app); + return currentUser; + } + + /// Starts the phone number verification process for the given phone number. + /// + /// Either sends an SMS with a 6 digit code to the phone number specified, + /// or sign's the user in and [verificationCompleted] is called. + /// + /// No duplicated SMS will be sent out upon re-entry (before timeout). + /// + /// Make sure to test all scenarios below: + /// • You directly get logged in if Google Play Services verified the phone + /// number instantly or helped you auto-retrieve the verification code. + /// • Auto-retrieve verification code timed out. + /// • Error cases when you receive [verificationFailed] callback. + /// + /// [phoneNumber] The phone number for the account the user is signing up + /// for or signing into. Make sure to pass in a phone number with country + /// code prefixed with plus sign ('+'). + /// + /// [timeout] The maximum amount of time you are willing to wait for SMS + /// auto-retrieval to be completed by the library. Maximum allowed value + /// is 2 minutes. Use 0 to disable SMS-auto-retrieval. Setting this to 0 + /// will also cause [codeAutoRetrievalTimeout] to be called immediately. + /// If you specified a positive value less than 30 seconds, library will + /// default to 30 seconds. + /// + /// [forceResendingToken] The [forceResendingToken] obtained from [codeSent] + /// callback to force re-sending another verification SMS before the + /// auto-retrieval timeout. + /// + /// [verificationCompleted] This callback must be implemented. + /// It will trigger when an SMS is auto-retrieved or the phone number has + /// been instantly verified. The callback will provide a [FirebaseUser]. + /// + /// [verificationFailed] This callback must be implemented. + /// Triggered when an error occurred during phone number verification. + /// + /// [codeSent] Optional callback. + /// It will trigger when an SMS has been sent to the users phone, + /// and will include a [verificationId] and [forceResendingToken]. + /// + /// [codeAutoRetrievalTimeout] Optional callback. + /// It will trigger when SMS auto-retrieval times out and provide a + /// [verificationId]. + Future verifyPhoneNumber({ + @required String phoneNumber, + @required Duration timeout, + int forceResendingToken, + @required PhoneVerificationCompleted verificationCompleted, + @required PhoneVerificationFailed verificationFailed, + @required PhoneCodeSent codeSent, + @required PhoneCodeAutoRetrievalTimeout codeAutoRetrievalTimeout, + }) async { + final Map callbacks = { + 'PhoneVerificationCompleted': verificationCompleted, + 'PhoneVerificationFailed': verificationFailed, + 'PhoneCodeSent': codeSent, + 'PhoneCodeAuthRetrievalTimeout': codeAutoRetrievalTimeout, + }; + nextHandle += 1; + _phoneAuthCallbacks[nextHandle] = callbacks; + + final Map params = { + 'handle': nextHandle, + 'phoneNumber': phoneNumber, + 'timeout': timeout.inMilliseconds, + 'forceResendingToken': forceResendingToken, + 'app': app.name, + }; + + await channel.invokeMethod('verifyPhoneNumber', params); + } + + /// Tries to sign in a user with a given Custom Token [token]. + /// + /// If successful, it also signs the user in into the app and updates + /// the [onAuthStateChanged] stream. + /// + /// Use this method after you retrieve a Firebase Auth Custom Token from your server. + /// + /// If the user identified by the [uid] specified in the token doesn't + /// have an account already, one will be created automatically. + /// + /// Read how to use Custom Token authentication and the cases where it is + /// useful in [the guides](https://firebase.google.com/docs/auth/android/custom-auth). + /// + /// Errors: + /// • `ERROR_INVALID_CUSTOM_TOKEN` - The custom token format is incorrect. + /// Please check the documentation. + /// • `ERROR_CUSTOM_TOKEN_MISMATCH` - Invalid configuration. + /// Ensure your app's SHA1 is correct in the Firebase console. + Future signInWithCustomToken({@required String token}) async { + assert(token != null); + final Map data = await channel.invokeMethod( + 'signInWithCustomToken', + {'token': token, 'app': app.name}, + ); + final FirebaseUser currentUser = FirebaseUser._(data, app); + return currentUser; + } + + /// Signs out the current user and clears it from the disk cache. + /// + /// If successful, it signs the user out of the app and updates + /// the [onAuthStateChanged] stream. + Future signOut() async { + return await channel + .invokeMethod("signOut", {'app': app.name}); + } + + /// Returns the currently signed-in [FirebaseUser] or [null] if there is none. + Future currentUser() async { + final Map data = await channel + .invokeMethod("currentUser", {'app': app.name}); + final FirebaseUser currentUser = + data == null ? null : FirebaseUser._(data, app); + return currentUser; + } + + /// Links the given [email] and [password] to the current user. + /// + /// This allows the user to sign in to this account in the future with + /// the given [email] and [password]. + /// + /// Errors: + /// • `ERROR_WEAK_PASSWORD` - If the password is not strong enough. + /// • `ERROR_INVALID_CREDENTIAL` - If the email address is malformed. + /// • `ERROR_CREDENTIAL_ALREADY_IN_USE` - If the email is already in use by a different account. + /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) + /// • `ERROR_REQUIRES_RECENT_LOGIN` - If the user's last sign-in time does not meet the security threshold. Use reauthenticate methods to resolve. + /// • `ERROR_PROVIDER_ALREADY_LINKED` - If the current user already has an Email & Password linked. + /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that Email & Password accounts are not enabled. + Future linkWithEmailAndPassword({ + @required String email, + @required String password, + }) async { + assert(email != null); + assert(password != null); + final Map data = await channel.invokeMethod( + 'linkWithEmailAndPassword', + {'email': email, 'password': password, 'app': app.name}, + ); + final FirebaseUser currentUser = FirebaseUser._(data, app); + return currentUser; + } + + /// Links the Google Account to the current user using [idToken] and [accessToken]. + /// + /// This allows the user to sign in to this account in the future with + /// the given Google Account. + /// + /// Errors: + /// • `ERROR_INVALID_CREDENTIAL` - If the [idToken] or [accessToken] is malformed or has expired. + /// • `ERROR_CREDENTIAL_ALREADY_IN_USE` - If the Google account is already in use by a different account. + /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) + /// • `ERROR_REQUIRES_RECENT_LOGIN` - If the user's last sign-in time does not meet the security threshold. Use reauthenticate methods to resolve. + /// • `ERROR_PROVIDER_ALREADY_LINKED` - If the current user already has a Google account linked. + /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that Google accounts are not enabled. + Future linkWithGoogleCredential({ + @required String idToken, + @required String accessToken, + }) async { + assert(idToken != null); + assert(accessToken != null); + final Map data = await channel.invokeMethod( + 'linkWithGoogleCredential', + { + 'idToken': idToken, + 'accessToken': accessToken, + 'app': app.name, + }, + ); + final FirebaseUser currentUser = FirebaseUser._(data, app); + return currentUser; + } + + /// Links the Facebook Account to the current user using [accessToken]. + /// + /// This allows the user to sign in to this account in the future with + /// the given Facebook Account. + /// + /// Errors: + /// • `ERROR_INVALID_CREDENTIAL` - If the [accessToken] is malformed or has expired. + /// • `ERROR_CREDENTIAL_ALREADY_IN_USE` - If the Facebook account is already in use by a different account. + /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) + /// • `ERROR_REQUIRES_RECENT_LOGIN` - If the user's last sign-in time does not meet the security threshold. Use reauthenticate methods to resolve. + /// • `ERROR_PROVIDER_ALREADY_LINKED` - If the current user already has a Facebook account linked. + /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that Facebook accounts are not enabled. + Future linkWithFacebookCredential({ + @required String accessToken, + }) async { + assert(accessToken != null); + final Map data = await channel.invokeMethod( + 'linkWithFacebookCredential', + { + 'accessToken': accessToken, + 'app': app.name, + }, + ); + final FirebaseUser currentUser = FirebaseUser._(data, app); + return currentUser; + } + + /// Links the Twitter Account to the current user using [authToken] and [authTokenSecret]. + /// + /// This allows the user to sign in to this account in the future with + /// the given Twitter Account. + /// + /// Errors: + /// • `ERROR_INVALID_CREDENTIAL` - If the [authToken] or [authTokenSecret] is malformed or has expired. + /// • `ERROR_CREDENTIAL_ALREADY_IN_USE` - If the Twitter account is already in use by a different account. + /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) + /// • `ERROR_REQUIRES_RECENT_LOGIN` - If the user's last sign-in time does not meet the security threshold. Use reauthenticate methods to resolve. + /// • `ERROR_PROVIDER_ALREADY_LINKED` - If the current user already has a Twitter account linked. + /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that Twitter accounts are not enabled. + Future linkWithTwitterCredential({ + @required String authToken, + @required String authTokenSecret, + }) async { + assert(authToken != null); + assert(authTokenSecret != null); + final Map data = await channel.invokeMethod( + 'linkWithTwitterCredential', + { + 'authToken': authToken, + 'authTokenSecret': authTokenSecret, + 'app': app.name, + }, + ); + final FirebaseUser currentUser = FirebaseUser._(data, app); + return currentUser; + } + + /// Links the Github Account to the current user using [token]. + /// + /// This allows the user to sign in to this account in the future with + /// the given Github Account. + /// + /// Errors: + /// • `ERROR_INVALID_CREDENTIAL` - If the [token] is malformed or has expired. + /// • `ERROR_CREDENTIAL_ALREADY_IN_USE` - If the Github account is already in use by a different account. + /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) + /// • `ERROR_REQUIRES_RECENT_LOGIN` - If the user's last sign-in time does not meet the security threshold. Use reauthenticate methods to resolve. + /// • `ERROR_PROVIDER_ALREADY_LINKED` - If the current user already has a Github account linked. + /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that Github accounts are not enabled. + Future linkWithGithubCredential({ + @required String token, + }) async { + assert(token != null); + final Map data = await channel.invokeMethod( + 'linkWithGithubCredential', + { + 'app': app.name, + 'token': token, + }, + ); + final FirebaseUser currentUser = FirebaseUser._(data, app); + return currentUser; + } + + /// Reauthenticates the current user with given [email] and [password]. + /// + /// This is used to prevent or resolve `ERROR_REQUIRES_RECENT_LOGIN` + /// response to operations that require a recent sign-in. + /// + /// Errors: + /// • `ERROR_INVALID_CREDENTIAL` - If the [email] and/or [password] are incorrect. + /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) + /// • `ERROR_USER_NOT_FOUND` - If the user has been deleted (for example, in the Firebase console) + /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that Email & Password accounts are not enabled. + Future reauthenticateWithEmailAndPassword({ + @required String email, + @required String password, + }) { + assert(email != null); + assert(password != null); + return channel.invokeMethod( + 'reauthenticateWithEmailAndPassword', + {'email': email, 'password': password, 'app': app.name}, + ); + } + + /// Reauthenticates the current user with the Google Account specified by [idToken] and [accessToken]. + /// + /// This is used to prevent or resolve `ERROR_REQUIRES_RECENT_LOGIN` + /// response to operations that require a recent sign-in. + /// + /// Errors: + /// • `ERROR_INVALID_CREDENTIAL` - If the [idToken] or [accessToken] is malformed or has expired. + /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) + /// • `ERROR_USER_NOT_FOUND` - If the user has been deleted (for example, in the Firebase console) + /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that Email & Password accounts are not enabled. + Future reauthenticateWithGoogleCredential({ + @required String idToken, + @required String accessToken, + }) { + assert(idToken != null); + assert(accessToken != null); + return channel.invokeMethod( + 'reauthenticateWithGoogleCredential', + { + 'idToken': idToken, + 'accessToken': accessToken, + 'app': app.name + }, + ); + } + + /// Reauthenticates the current user with the Facebook Account specified by [accessToken]. + /// + /// This is used to prevent or resolve `ERROR_REQUIRES_RECENT_LOGIN` + /// response to operations that require a recent sign-in. + /// + /// Errors: + /// • `ERROR_INVALID_CREDENTIAL` - If the [accessToken] is malformed or has expired. + /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) + /// • `ERROR_USER_NOT_FOUND` - If the user has been deleted (for example, in the Firebase console) + /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that Email & Password accounts are not enabled. + Future reauthenticateWithFacebookCredential({ + @required String accessToken, + }) { + assert(accessToken != null); + return channel.invokeMethod( + 'reauthenticateWithFacebookCredential', + {'accessToken': accessToken, 'app': app.name}, + ); + } + + /// Reauthenticates the current user with the Twitter Account specified by [authToken] and [authTokenSecret]. + /// + /// This is used to prevent or resolve `ERROR_REQUIRES_RECENT_LOGIN` + /// response to operations that require a recent sign-in. + /// + /// Errors: + /// • `ERROR_INVALID_CREDENTIAL` - If the [authToken] or [authTokenSecret] is malformed or has expired. + /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) + /// • `ERROR_USER_NOT_FOUND` - If the user has been deleted (for example, in the Firebase console) + /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that Email & Password accounts are not enabled. + Future reauthenticateWithTwitterCredential({ + @required String authToken, + @required String authTokenSecret, + }) { + return channel.invokeMethod( + 'reauthenticateWithTwitterCredential', + { + 'app': app.name, + 'authToken': authToken, + 'authTokenSecret': authTokenSecret, + }, + ); + } + + /// Reauthenticates the current user with the Github Account specified by [token]. + /// + /// This is used to prevent or resolve `ERROR_REQUIRES_RECENT_LOGIN` + /// response to operations that require a recent sign-in. + /// + /// Errors: + /// • `ERROR_INVALID_CREDENTIAL` - If the [token] is malformed or has expired. + /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) + /// • `ERROR_USER_NOT_FOUND` - If the user has been deleted (for example, in the Firebase console) + /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that Email & Password accounts are not enabled. + Future reauthenticateWithGithubCredential({@required String token}) { + assert(token != null); + return channel.invokeMethod( + 'reauthenticateWithGithubCredential', + { + 'app': app.name, + 'token': token, + }, + ); + } + + /// Sets the user-facing language code for auth operations that can be + /// internationalized, such as [sendEmailVerification]. This language + /// code should follow the conventions defined by the IETF in BCP47. + Future setLanguageCode(String language) async { + assert(language != null); + await FirebaseAuth.channel.invokeMethod('setLanguageCode', { + 'language': language, + 'app': app.name, + }); + } + + Future _callHandler(MethodCall call) async { + switch (call.method) { + case 'onAuthStateChanged': + _onAuthStageChangedHandler(call); + break; + case 'phoneVerificationCompleted': + final int handle = call.arguments['handle']; + final PhoneVerificationCompleted verificationCompleted = + _phoneAuthCallbacks[handle]['PhoneVerificationCompleted']; + verificationCompleted(await currentUser()); + break; + case 'phoneVerificationFailed': + final int handle = call.arguments['handle']; + final PhoneVerificationFailed verificationFailed = + _phoneAuthCallbacks[handle]['PhoneVerificationFailed']; + final Map exception = call.arguments['exception']; + verificationFailed( + AuthException(exception['code'], exception['message'])); + break; + case 'phoneCodeSent': + final int handle = call.arguments['handle']; + final String verificationId = call.arguments['verificationId']; + final int forceResendingToken = call.arguments['forceResendingToken']; + + final PhoneCodeSent codeSent = + _phoneAuthCallbacks[handle]['PhoneCodeSent']; + if (forceResendingToken == null) { + codeSent(verificationId); + } else { + codeSent(verificationId, forceResendingToken); + } + break; + case 'phoneCodeAutoRetrievalTimeout': + final int handle = call.arguments['handle']; + final PhoneCodeAutoRetrievalTimeout codeAutoRetrievalTimeout = + _phoneAuthCallbacks[handle]['PhoneCodeAutoRetrievealTimeout']; + final String verificationId = call.arguments['verificationId']; + codeAutoRetrievalTimeout(verificationId); + break; + } + } + + void _onAuthStageChangedHandler(MethodCall call) { + final Map data = call.arguments["user"]; + final int id = call.arguments["id"]; + + final FirebaseUser currentUser = + data != null ? FirebaseUser._(data, app) : null; + _authStateChangedControllers[id].add(currentUser); + } +} diff --git a/packages/firebase_auth/lib/src/auth_credential.dart b/packages/firebase_auth/lib/src/auth_credential.dart deleted file mode 100644 index 7240b045cd80..000000000000 --- a/packages/firebase_auth/lib/src/auth_credential.dart +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2018, the Flutter project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of firebase_auth; - -/// Represents the credentials returned by calling the `getCredential` method of -/// an auth provider. -class AuthCredential { - AuthCredential._(this._provider, this._data); - final String _provider; - final Map _data; -} diff --git a/packages/firebase_auth/lib/src/auth_exception.dart b/packages/firebase_auth/lib/src/auth_exception.dart deleted file mode 100644 index bbdc746fe40c..000000000000 --- a/packages/firebase_auth/lib/src/auth_exception.dart +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -part of firebase_auth; - -/// Generic exception related to Firebase Authentication. -/// Check the error code and message for more details. -class AuthException implements Exception { - const AuthException(this.code, this.message); - - final String code; - final String message; -} diff --git a/packages/firebase_auth/lib/src/auth_provider/email_auth_provider.dart b/packages/firebase_auth/lib/src/auth_provider/email_auth_provider.dart deleted file mode 100644 index b458c7ae7d93..000000000000 --- a/packages/firebase_auth/lib/src/auth_provider/email_auth_provider.dart +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2018, the Flutter project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of firebase_auth; - -class EmailAuthProvider { - static final String providerId = 'password'; - - static AuthCredential getCredential({ - String email, - String password, - }) { - return AuthCredential._(providerId, { - 'email': email, - 'password': password, - }); - } -} diff --git a/packages/firebase_auth/lib/src/auth_provider/facebook_auth_provider.dart b/packages/firebase_auth/lib/src/auth_provider/facebook_auth_provider.dart deleted file mode 100644 index eb23403a13c6..000000000000 --- a/packages/firebase_auth/lib/src/auth_provider/facebook_auth_provider.dart +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2018, the Flutter project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of firebase_auth; - -class FacebookAuthProvider { - static final String providerId = 'facebook.com'; - - static AuthCredential getCredential({String accessToken}) { - return AuthCredential._( - providerId, - {'accessToken': accessToken}, - ); - } -} diff --git a/packages/firebase_auth/lib/src/auth_provider/github_auth_provider.dart b/packages/firebase_auth/lib/src/auth_provider/github_auth_provider.dart deleted file mode 100644 index 73e09d93d57c..000000000000 --- a/packages/firebase_auth/lib/src/auth_provider/github_auth_provider.dart +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2018, the Flutter project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of firebase_auth; - -class GithubAuthProvider { - static final String providerId = 'github.com'; - - static AuthCredential getCredential({@required String token}) { - return AuthCredential._(providerId, {'token': token}); - } -} diff --git a/packages/firebase_auth/lib/src/auth_provider/google_auth_provider.dart b/packages/firebase_auth/lib/src/auth_provider/google_auth_provider.dart deleted file mode 100644 index b61e04eb72de..000000000000 --- a/packages/firebase_auth/lib/src/auth_provider/google_auth_provider.dart +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2018, the Flutter project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of firebase_auth; - -class GoogleAuthProvider { - static final String providerId = 'google.com'; - - static AuthCredential getCredential({ - @required String idToken, - @required String accessToken, - }) { - return AuthCredential._(providerId, { - 'idToken': idToken, - 'accessToken': accessToken, - }); - } -} diff --git a/packages/firebase_auth/lib/src/auth_provider/phone_auth_provider.dart b/packages/firebase_auth/lib/src/auth_provider/phone_auth_provider.dart deleted file mode 100644 index 91e5bd2291a8..000000000000 --- a/packages/firebase_auth/lib/src/auth_provider/phone_auth_provider.dart +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2018, the Flutter project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of firebase_auth; - -class PhoneAuthProvider { - static final String providerId = 'phone'; - - static AuthCredential getCredential({ - @required String verificationId, - @required String smsCode, - }) { - return AuthCredential._(providerId, { - 'verificationId': verificationId, - 'smsCode': smsCode, - }); - } -} diff --git a/packages/firebase_auth/lib/src/auth_provider/twitter_auth_provider.dart b/packages/firebase_auth/lib/src/auth_provider/twitter_auth_provider.dart deleted file mode 100644 index a565a1e8bee6..000000000000 --- a/packages/firebase_auth/lib/src/auth_provider/twitter_auth_provider.dart +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2018, the Flutter project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of firebase_auth; - -class TwitterAuthProvider { - static final String providerId = 'twitter.com'; - - static AuthCredential getCredential({ - @required String authToken, - @required String authTokenSecret, - }) { - return AuthCredential._(providerId, { - 'authToken': authToken, - 'authTokenSecret': authTokenSecret, - }); - } -} diff --git a/packages/firebase_auth/lib/src/firebase_auth.dart b/packages/firebase_auth/lib/src/firebase_auth.dart deleted file mode 100644 index f56dd599c66a..000000000000 --- a/packages/firebase_auth/lib/src/firebase_auth.dart +++ /dev/null @@ -1,408 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -part of firebase_auth; - -typedef void PhoneVerificationCompleted(FirebaseUser firebaseUser); -typedef void PhoneVerificationFailed(AuthException error); -typedef void PhoneCodeSent(String verificationId, [int forceResendingToken]); -typedef void PhoneCodeAutoRetrievalTimeout(String verificationId); - -/// The entry point of the Firebase Authentication SDK. -class FirebaseAuth { - FirebaseAuth._(this.app) { - channel.setMethodCallHandler(_callHandler); - } - - /// Provides an instance of this class corresponding to `app`. - factory FirebaseAuth.fromApp(FirebaseApp app) { - assert(app != null); - return FirebaseAuth._(app); - } - - /// Provides an instance of this class corresponding to the default app. - static final FirebaseAuth instance = FirebaseAuth._(FirebaseApp.instance); - - @visibleForTesting - static const MethodChannel channel = MethodChannel( - 'plugins.flutter.io/firebase_auth', - ); - - final Map> _authStateChangedControllers = - >{}; - - static int nextHandle = 0; - final Map> _phoneAuthCallbacks = - >{}; - - final FirebaseApp app; - - /// Receive [FirebaseUser] each time the user signIn or signOut - Stream get onAuthStateChanged { - Future _handle; - - StreamController controller; - controller = StreamController.broadcast(onListen: () { - _handle = channel.invokeMethod('startListeningAuthState', - {"app": app.name}).then((dynamic v) => v); - _handle.then((int handle) { - _authStateChangedControllers[handle] = controller; - }); - }, onCancel: () { - _handle.then((int handle) async { - await channel.invokeMethod("stopListeningAuthState", - {"id": handle, "app": app.name}); - _authStateChangedControllers.remove(handle); - }); - }); - - return controller.stream; - } - - /// Asynchronously creates and becomes an anonymous user. - /// - /// If there is already an anonymous user signed in, that user will be - /// returned instead. If there is any other existing user signed in, that - /// user will be signed out. - /// - /// **Important**: You must enable Anonymous accounts in the Auth section - /// of the Firebase console before being able to use them. - /// - /// Errors: - /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that Anonymous accounts are not enabled. - Future signInAnonymously() async { - final Map data = await channel - .invokeMethod('signInAnonymously', {"app": app.name}); - final FirebaseUser currentUser = FirebaseUser._(data, app); - return currentUser; - } - - /// Tries to create a new user account with the given email address and password. - /// - /// If successful, it also signs the user in into the app and updates - /// the [onAuthStateChanged] stream. - /// - /// Errors: - /// • `ERROR_WEAK_PASSWORD` - If the password is not strong enough. - /// • `ERROR_INVALID_CREDENTIAL` - If the email address is malformed. - /// • `ERROR_EMAIL_ALREADY_IN_USE` - If the email is already in use by a different account. - Future createUserWithEmailAndPassword({ - @required String email, - @required String password, - }) async { - assert(email != null); - assert(password != null); - final Map data = await channel.invokeMethod( - 'createUserWithEmailAndPassword', - {'email': email, 'password': password, 'app': app.name}, - ); - final FirebaseUser currentUser = FirebaseUser._(data, app); - return currentUser; - } - - /// Returns a list of sign-in methods that can be used to sign in a given - /// user (identified by its main email address). - /// - /// This method is useful when you support multiple authentication mechanisms - /// if you want to implement an email-first authentication flow. - /// - /// Errors: - /// • `ERROR_INVALID_CREDENTIAL` - If the [email] address is malformed. - /// • `ERROR_USER_NOT_FOUND` - If there is no user corresponding to the given [email] address. - Future> fetchSignInMethodsForEmail({ - @required String email, - }) async { - assert(email != null); - final List providers = await channel.invokeMethod( - 'fetchSignInMethodsForEmail', - {'email': email, 'app': app.name}, - ); - return providers?.cast(); - } - - /// Triggers the Firebase Authentication backend to send a password-reset - /// email to the given email address, which must correspond to an existing - /// user of your app. - /// - /// Errors: - /// • `ERROR_INVALID_EMAIL` - If the [email] address is malformed. - /// • `ERROR_USER_NOT_FOUND` - If there is no user corresponding to the given [email] address. - Future sendPasswordResetEmail({ - @required String email, - }) async { - assert(email != null); - return await channel.invokeMethod( - 'sendPasswordResetEmail', - {'email': email, 'app': app.name}, - ); - } - - /// Tries to sign in a user with the given email address and password. - /// - /// If successful, it also signs the user in into the app and updates - /// the [onAuthStateChanged] stream. - /// - /// **Important**: You must enable Email & Password accounts in the Auth - /// section of the Firebase console before being able to use them. - /// - /// Errors: - /// • `ERROR_INVALID_EMAIL` - If the [email] address is malformed. - /// • `ERROR_WRONG_PASSWORD` - If the [password] is wrong. - /// • `ERROR_USER_NOT_FOUND` - If there is no user corresponding to the given [email] address, or if the user has been deleted. - /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) - /// • `ERROR_TOO_MANY_REQUESTS` - If there was too many attempts to sign in as this user. - /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that Email & Password accounts are not enabled. - Future signInWithEmailAndPassword({ - @required String email, - @required String password, - }) { - assert(email != null); - assert(password != null); - final AuthCredential credential = EmailAuthProvider.getCredential( - email: email, - password: password, - ); - return signInWithCredential(credential); - } - - /// Asynchronously signs in to Firebase with the given 3rd-party credentials - /// (e.g. a Facebook login Access Token, a Google ID Token/Access Token pair, - /// etc.) and returns additional identity provider data. - /// - /// If successful, it also signs the user in into the app and updates - /// the [onAuthStateChanged] stream. - /// - /// If the user doesn't have an account already, one will be created automatically. - /// - /// **Important**: You must enable the relevant accounts in the Auth section - /// of the Firebase console before being able to use them. - /// - /// Errors: - /// • `ERROR_INVALID_CREDENTIAL` - If the credential data is malformed or has expired. - /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) - /// • `ERROR_ACCOUNT_EXISTS_WITH_DIFFERENT_CREDENTIAL` - If there already exists an account with the email address asserted by Google. - /// Resolve this case by calling [fetchSignInMethodsForEmail] and then asking the user to sign in using one of them. - /// This error will only be thrown if the "One account per email address" setting is enabled in the Firebase console (recommended). - /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that Google accounts are not enabled. - Future signInWithCredential(AuthCredential credential) async { - assert(credential != null); - final Map data = await channel.invokeMethod( - 'signInWithCredential', - { - 'app': app.name, - 'provider': credential._provider, - 'data': credential._data, - }, - ); - final FirebaseUser currentUser = FirebaseUser._(data, app); - return currentUser; - } - - /// Starts the phone number verification process for the given phone number. - /// - /// Either sends an SMS with a 6 digit code to the phone number specified, - /// or sign's the user in and [verificationCompleted] is called. - /// - /// No duplicated SMS will be sent out upon re-entry (before timeout). - /// - /// Make sure to test all scenarios below: - /// • You directly get logged in if Google Play Services verified the phone - /// number instantly or helped you auto-retrieve the verification code. - /// • Auto-retrieve verification code timed out. - /// • Error cases when you receive [verificationFailed] callback. - /// - /// [phoneNumber] The phone number for the account the user is signing up - /// for or signing into. Make sure to pass in a phone number with country - /// code prefixed with plus sign ('+'). - /// - /// [timeout] The maximum amount of time you are willing to wait for SMS - /// auto-retrieval to be completed by the library. Maximum allowed value - /// is 2 minutes. Use 0 to disable SMS-auto-retrieval. Setting this to 0 - /// will also cause [codeAutoRetrievalTimeout] to be called immediately. - /// If you specified a positive value less than 30 seconds, library will - /// default to 30 seconds. - /// - /// [forceResendingToken] The [forceResendingToken] obtained from [codeSent] - /// callback to force re-sending another verification SMS before the - /// auto-retrieval timeout. - /// - /// [verificationCompleted] This callback must be implemented. - /// It will trigger when an SMS is auto-retrieved or the phone number has - /// been instantly verified. The callback will provide a [FirebaseUser]. - /// - /// [verificationFailed] This callback must be implemented. - /// Triggered when an error occurred during phone number verification. - /// - /// [codeSent] Optional callback. - /// It will trigger when an SMS has been sent to the users phone, - /// and will include a [verificationId] and [forceResendingToken]. - /// - /// [codeAutoRetrievalTimeout] Optional callback. - /// It will trigger when SMS auto-retrieval times out and provide a - /// [verificationId]. - Future verifyPhoneNumber({ - @required String phoneNumber, - @required Duration timeout, - int forceResendingToken, - @required PhoneVerificationCompleted verificationCompleted, - @required PhoneVerificationFailed verificationFailed, - @required PhoneCodeSent codeSent, - @required PhoneCodeAutoRetrievalTimeout codeAutoRetrievalTimeout, - }) async { - final Map callbacks = { - 'PhoneVerificationCompleted': verificationCompleted, - 'PhoneVerificationFailed': verificationFailed, - 'PhoneCodeSent': codeSent, - 'PhoneCodeAuthRetrievalTimeout': codeAutoRetrievalTimeout, - }; - nextHandle += 1; - _phoneAuthCallbacks[nextHandle] = callbacks; - - final Map params = { - 'handle': nextHandle, - 'phoneNumber': phoneNumber, - 'timeout': timeout.inMilliseconds, - 'forceResendingToken': forceResendingToken, - 'app': app.name, - }; - - await channel.invokeMethod('verifyPhoneNumber', params); - } - - /// Tries to sign in a user with a given Custom Token [token]. - /// - /// If successful, it also signs the user in into the app and updates - /// the [onAuthStateChanged] stream. - /// - /// Use this method after you retrieve a Firebase Auth Custom Token from your server. - /// - /// If the user identified by the [uid] specified in the token doesn't - /// have an account already, one will be created automatically. - /// - /// Read how to use Custom Token authentication and the cases where it is - /// useful in [the guides](https://firebase.google.com/docs/auth/android/custom-auth). - /// - /// Errors: - /// • `ERROR_INVALID_CUSTOM_TOKEN` - The custom token format is incorrect. - /// Please check the documentation. - /// • `ERROR_CUSTOM_TOKEN_MISMATCH` - Invalid configuration. - /// Ensure your app's SHA1 is correct in the Firebase console. - Future signInWithCustomToken({@required String token}) async { - assert(token != null); - final Map data = await channel.invokeMethod( - 'signInWithCustomToken', - {'token': token, 'app': app.name}, - ); - final FirebaseUser currentUser = FirebaseUser._(data, app); - return currentUser; - } - - /// Signs out the current user and clears it from the disk cache. - /// - /// If successful, it signs the user out of the app and updates - /// the [onAuthStateChanged] stream. - Future signOut() async { - return await channel - .invokeMethod("signOut", {'app': app.name}); - } - - /// Returns the currently signed-in [FirebaseUser] or [null] if there is none. - Future currentUser() async { - final Map data = await channel - .invokeMethod("currentUser", {'app': app.name}); - final FirebaseUser currentUser = - data == null ? null : FirebaseUser._(data, app); - return currentUser; - } - - /// Associates a user account from a third-party identity provider with this - /// user and returns additional identity provider data. - /// - /// This allows the user to sign in to this account in the future with - /// the given account. - /// - /// Errors: - /// • `ERROR_WEAK_PASSWORD` - If the password is not strong enough. - /// • `ERROR_INVALID_CREDENTIAL` - If the credential is malformed or has expired. - /// • `ERROR_CREDENTIAL_ALREADY_IN_USE` - If the account is already in use by a different account. - /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) - /// • `ERROR_REQUIRES_RECENT_LOGIN` - If the user's last sign-in time does not meet the security threshold. Use reauthenticate methods to resolve. - /// • `ERROR_PROVIDER_ALREADY_LINKED` - If the current user already has an account of this type linked. - /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that this type of account is not enabled. - Future linkWithCredential(AuthCredential credential) async { - assert(credential != null); - final Map data = await channel.invokeMethod( - 'linkWithCredential', - { - 'app': app.name, - 'provider': credential._provider, - 'data': credential._data, - }, - ); - final FirebaseUser currentUser = FirebaseUser._(data, app); - return currentUser; - } - - /// Sets the user-facing language code for auth operations that can be - /// internationalized, such as [sendEmailVerification]. This language - /// code should follow the conventions defined by the IETF in BCP47. - Future setLanguageCode(String language) async { - assert(language != null); - await FirebaseAuth.channel.invokeMethod('setLanguageCode', { - 'language': language, - 'app': app.name, - }); - } - - Future _callHandler(MethodCall call) async { - switch (call.method) { - case 'onAuthStateChanged': - _onAuthStageChangedHandler(call); - break; - case 'phoneVerificationCompleted': - final int handle = call.arguments['handle']; - final PhoneVerificationCompleted verificationCompleted = - _phoneAuthCallbacks[handle]['PhoneVerificationCompleted']; - verificationCompleted(await currentUser()); - break; - case 'phoneVerificationFailed': - final int handle = call.arguments['handle']; - final PhoneVerificationFailed verificationFailed = - _phoneAuthCallbacks[handle]['PhoneVerificationFailed']; - final Map exception = call.arguments['exception']; - verificationFailed( - AuthException(exception['code'], exception['message'])); - break; - case 'phoneCodeSent': - final int handle = call.arguments['handle']; - final String verificationId = call.arguments['verificationId']; - final int forceResendingToken = call.arguments['forceResendingToken']; - - final PhoneCodeSent codeSent = - _phoneAuthCallbacks[handle]['PhoneCodeSent']; - if (forceResendingToken == null) { - codeSent(verificationId); - } else { - codeSent(verificationId, forceResendingToken); - } - break; - case 'phoneCodeAutoRetrievalTimeout': - final int handle = call.arguments['handle']; - final PhoneCodeAutoRetrievalTimeout codeAutoRetrievalTimeout = - _phoneAuthCallbacks[handle]['PhoneCodeAutoRetrievealTimeout']; - final String verificationId = call.arguments['verificationId']; - codeAutoRetrievalTimeout(verificationId); - break; - } - } - - void _onAuthStageChangedHandler(MethodCall call) { - final Map data = call.arguments["user"]; - final int id = call.arguments["id"]; - - final FirebaseUser currentUser = - data != null ? FirebaseUser._(data, app) : null; - _authStateChangedControllers[id].add(currentUser); - } -} diff --git a/packages/firebase_auth/lib/src/firebase_user.dart b/packages/firebase_auth/lib/src/firebase_user.dart deleted file mode 100644 index 5d3a7f93fc2b..000000000000 --- a/packages/firebase_auth/lib/src/firebase_user.dart +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -part of firebase_auth; - -/// Represents a user. -class FirebaseUser extends UserInfo { - FirebaseUser._(Map data, FirebaseApp app) - : providerData = data['providerData'] - .map((dynamic item) => UserInfo._(item, app)) - .toList(), - _metadata = FirebaseUserMetadata._(data), - super._(data, app); - - final List providerData; - final FirebaseUserMetadata _metadata; - - // Returns true if the user is anonymous; that is, the user account was - // created with signInAnonymously() and has not been linked to another - // account. - FirebaseUserMetadata get metadata => _metadata; - - bool get isAnonymous => _data['isAnonymous']; - - /// Returns true if the user's email is verified. - bool get isEmailVerified => _data['isEmailVerified']; - - /// Obtains the id token for the current user, forcing a [refresh] if desired. - /// - /// Useful when authenticating against your own backend. Use our server - /// SDKs or follow the official documentation to securely verify the - /// integrity and validity of this token. - /// - /// Completes with an error if the user is signed out. - Future getIdToken({bool refresh = false}) async { - return await FirebaseAuth.channel - .invokeMethod('getIdToken', { - 'refresh': refresh, - 'app': _app.name, - }); - } - - /// Initiates email verification for the user. - Future sendEmailVerification() async { - await FirebaseAuth.channel.invokeMethod( - 'sendEmailVerification', {'app': _app.name}); - } - - /// Manually refreshes the data of the current user (for example, - /// attached providers, display name, and so on). - Future reload() async { - await FirebaseAuth.channel - .invokeMethod('reload', {'app': _app.name}); - } - - /// Deletes the user record from your Firebase project's database. - Future delete() async { - await FirebaseAuth.channel - .invokeMethod('delete', {'app': _app.name}); - } - - /// Updates the email address of the user. - /// - /// The original email address recipient will receive an email that allows - /// them to revoke the email address change, in order to protect them - /// from account hijacking. - /// - /// **Important**: This is a security sensitive operation that requires - /// the user to have recently signed in. - /// - /// Errors: - /// • `ERROR_INVALID_CREDENTIAL` - If the email address is malformed. - /// • `ERROR_EMAIL_ALREADY_IN_USE` - If the email is already in use by a different account. - /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) - /// • `ERROR_USER_NOT_FOUND` - If the user has been deleted (for example, in the Firebase console) - /// • `ERROR_REQUIRES_RECENT_LOGIN` - If the user's last sign-in time does not meet the security threshold. Use reauthenticate methods to resolve. - /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that Email & Password accounts are not enabled. - Future updateEmail(String email) async { - assert(email != null); - return await FirebaseAuth.channel.invokeMethod( - 'updateEmail', - {'email': email, 'app': _app.name}, - ); - } - - /// Updates the password of the user. - /// - /// Anonymous users who update both their email and password will no - /// longer be anonymous. They will be able to log in with these credentials. - /// - /// **Important**: This is a security sensitive operation that requires - /// the user to have recently signed in. - /// - /// Errors: - /// • `ERROR_WEAK_PASSWORD` - If the password is not strong enough. - /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) - /// • `ERROR_USER_NOT_FOUND` - If the user has been deleted (for example, in the Firebase console) - /// • `ERROR_REQUIRES_RECENT_LOGIN` - If the user's last sign-in time does not meet the security threshold. Use reauthenticate methods to resolve. - /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that Email & Password accounts are not enabled. - Future updatePassword(String password) async { - assert(password != null); - return await FirebaseAuth.channel.invokeMethod( - 'updatePassword', - {'password': password, 'app': _app.name}, - ); - } - - /// Updates the user profile information. - /// - /// Errors: - /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) - /// • `ERROR_USER_NOT_FOUND` - If the user has been deleted (for example, in the Firebase console) - Future updateProfile(UserUpdateInfo userUpdateInfo) async { - assert(userUpdateInfo != null); - final Map data = userUpdateInfo._updateData; - data['app'] = _app.name; - return await FirebaseAuth.channel.invokeMethod( - 'updateProfile', - data, - ); - } - - /// Renews the user’s authentication tokens by validating a fresh set of - /// [credential]s supplied by the user and returns additional identity provider - /// data. - /// - /// This is used to prevent or resolve `ERROR_REQUIRES_RECENT_LOGIN` - /// response to operations that require a recent sign-in. - /// - /// If the user associated with the supplied credential is different from the - /// current user, or if the validation of the supplied credentials fails; an - /// error is returned and the current user remains signed in. - /// - /// Errors: - /// • `ERROR_INVALID_CREDENTIAL` - If the [authToken] or [authTokenSecret] is malformed or has expired. - /// • `ERROR_USER_DISABLED` - If the user has been disabled (for example, in the Firebase console) - /// • `ERROR_USER_NOT_FOUND` - If the user has been deleted (for example, in the Firebase console) - /// • `ERROR_OPERATION_NOT_ALLOWED` - Indicates that Email & Password accounts are not enabled. - Future reauthenticateWithCredential( - AuthCredential credential) async { - assert(credential != null); - await FirebaseAuth.channel.invokeMethod( - 'reauthenticateWithCredential', - { - 'app': _app.name, - 'provider': credential._provider, - 'data': credential._data, - }, - ); - return this; - } - - /// Detaches the [provider] account from the current user. - /// - /// This will prevent the user from signing in to this account with those - /// credentials. - /// - /// **Important**: This is a security sensitive operation that requires - /// the user to have recently signed in. - /// - /// Use the `providerId` method of an auth provider for [provider]. - /// - /// Errors: - /// • `ERROR_NO_SUCH_PROVIDER` - If the user does not have a Github Account linked to their account. - /// • `ERROR_REQUIRES_RECENT_LOGIN` - If the user's last sign-in time does not meet the security threshold. Use reauthenticate methods to resolve. - Future unlinkFromProvider(String provider) async { - assert(provider != null); - return await FirebaseAuth.channel.invokeMethod( - 'unlinkFromProvider', - {'provider': provider, 'app': _app.name}, - ); - } - - @override - String toString() { - return '$runtimeType($_data)'; - } -} diff --git a/packages/firebase_auth/lib/src/user_info.dart b/packages/firebase_auth/lib/src/user_info.dart deleted file mode 100644 index d7e440aaeee0..000000000000 --- a/packages/firebase_auth/lib/src/user_info.dart +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -part of firebase_auth; - -/// Represents user data returned from an identity provider. -class UserInfo { - UserInfo._(this._data, this._app); - - final FirebaseApp _app; - - final Map _data; - - /// The provider identifier. - String get providerId => _data['providerId']; - - /// The provider’s user ID for the user. - String get uid => _data['uid']; - - /// The name of the user. - String get displayName => _data['displayName']; - - /// The URL of the user’s profile photo. - String get photoUrl => _data['photoUrl']; - - /// The user’s email address. - String get email => _data['email']; - - /// The user's phone number. - String get phoneNumber => _data['phoneNumber']; - - @override - String toString() { - return '$runtimeType($_data)'; - } -} diff --git a/packages/firebase_auth/lib/src/user_metadata.dart b/packages/firebase_auth/lib/src/user_metadata.dart deleted file mode 100644 index 11f9076bc61b..000000000000 --- a/packages/firebase_auth/lib/src/user_metadata.dart +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -part of firebase_auth; - -/// Interface representing a user's metadata. -class FirebaseUserMetadata { - FirebaseUserMetadata._(this._data); - - final Map _data; - - int get creationTimestamp => _data['creationTimestamp']; - - int get lastSignInTimestamp => _data['lastSignInTimestamp']; -} diff --git a/packages/firebase_auth/lib/src/user_update_info.dart b/packages/firebase_auth/lib/src/user_update_info.dart deleted file mode 100644 index 0b290b912970..000000000000 --- a/packages/firebase_auth/lib/src/user_update_info.dart +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -part of firebase_auth; - -/// Represents user profile data that can be updated by [updateProfile] -/// -/// The purpose of having separate class with a map is to give possibility -/// to check if value was set to null or not provided -class UserUpdateInfo { - /// Container of data that will be send in update request - final Map _updateData = {}; - - set displayName(String displayName) => - _updateData['displayName'] = displayName; - - String get displayName => _updateData['displayName']; - - set photoUrl(String photoUri) => _updateData['photoUrl'] = photoUri; - - String get photoUrl => _updateData['photoUrl']; -} diff --git a/packages/firebase_auth/pubspec.yaml b/packages/firebase_auth/pubspec.yaml index 04ab6acfffac..b6da2330f184 100755 --- a/packages/firebase_auth/pubspec.yaml +++ b/packages/firebase_auth/pubspec.yaml @@ -4,7 +4,7 @@ description: Flutter plugin for Firebase Auth, enabling Android and iOS like Google, Facebook and Twitter. author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/firebase_auth -version: 0.7.0 +version: 0.6.6 flutter: plugin: diff --git a/packages/firebase_auth/test/firebase_auth_test.dart b/packages/firebase_auth/test/firebase_auth_test.dart index 3eb3db28a7a4..ae83be64e65e 100755 --- a/packages/firebase_auth/test/firebase_auth_test.dart +++ b/packages/firebase_auth/test/firebase_auth_test.dart @@ -154,166 +154,136 @@ void main() { ); }); - test('TwitterAuthProvider linkWithCredential', () async { - final AuthCredential credential = TwitterAuthProvider.getCredential( + test('linkWithTwitterCredential', () async { + final FirebaseUser user = await auth.linkWithTwitterCredential( authToken: kMockIdToken, authTokenSecret: kMockAccessToken, ); - final FirebaseUser user = await auth.linkWithCredential(credential); verifyUser(user); expect( log, [ isMethodCall( - 'linkWithCredential', - arguments: { + 'linkWithTwitterCredential', + arguments: { + 'authToken': kMockIdToken, + 'authTokenSecret': kMockAccessToken, 'app': auth.app.name, - 'provider': 'twitter.com', - 'data': { - 'authToken': kMockIdToken, - 'authTokenSecret': kMockAccessToken, - }, }, ), ], ); }); - test('TwitterAuthProvider signInWithCredential', () async { - final AuthCredential credential = TwitterAuthProvider.getCredential( + test('signInWithTwitter', () async { + final FirebaseUser user = await auth.signInWithTwitter( authToken: kMockIdToken, authTokenSecret: kMockAccessToken, ); - final FirebaseUser user = await auth.signInWithCredential(credential); verifyUser(user); expect( log, [ isMethodCall( - 'signInWithCredential', - arguments: { + 'signInWithTwitter', + arguments: { + 'authToken': kMockIdToken, + 'authTokenSecret': kMockAccessToken, 'app': auth.app.name, - 'provider': 'twitter.com', - 'data': { - 'authToken': kMockIdToken, - 'authTokenSecret': kMockAccessToken, - }, }, ), ], ); }); - test('GithubAuthProvider linkWithCredential', () async { - final AuthCredential credential = GithubAuthProvider.getCredential( + test('linkWithGithubCredential', () async { + final FirebaseUser user = await auth.linkWithGithubCredential( token: kMockGithubToken, ); - final FirebaseUser user = await auth.linkWithCredential(credential); verifyUser(user); expect( log, [ isMethodCall( - 'linkWithCredential', - arguments: { + 'linkWithGithubCredential', + arguments: { + 'token': kMockGithubToken, 'app': auth.app.name, - 'provider': 'github.com', - 'data': { - 'token': kMockGithubToken, - } }, ), ], ); }); - test('GitHubAuthProvider signInWithCredential', () async { - final AuthCredential credential = GithubAuthProvider.getCredential( + test('signInWithGithub', () async { + final FirebaseUser user = await auth.signInWithGithub( token: kMockGithubToken, ); - final FirebaseUser user = await auth.signInWithCredential(credential); verifyUser(user); expect( log, [ isMethodCall( - 'signInWithCredential', - arguments: { + 'signInWithGithub', + arguments: { + 'token': kMockGithubToken, 'app': auth.app.name, - 'provider': 'github.com', - 'data': { - 'token': kMockGithubToken, - }, }, ), ], ); }); - test('EmailAuthProvider linkWithCredential', () async { - final AuthCredential credential = EmailAuthProvider.getCredential( + test('linkWithEmailAndPassword', () async { + final FirebaseUser user = await auth.linkWithEmailAndPassword( email: kMockEmail, password: kMockPassword, ); - final FirebaseUser user = await auth.linkWithCredential(credential); verifyUser(user); expect( log, [ isMethodCall( - 'linkWithCredential', - arguments: { - 'app': auth.app.name, - 'provider': 'password', - 'data': { - 'email': kMockEmail, - 'password': kMockPassword, - }, + 'linkWithEmailAndPassword', + arguments: { + 'email': kMockEmail, + 'password': kMockPassword, + 'app': auth.app.name }, ), ], ); }); - test('GoogleAuthProvider signInWithCredential', () async { - final AuthCredential credential = GoogleAuthProvider.getCredential( + test('signInWithGoogle', () async { + final FirebaseUser user = await auth.signInWithGoogle( idToken: kMockIdToken, accessToken: kMockAccessToken, ); - final FirebaseUser user = await auth.signInWithCredential(credential); verifyUser(user); expect( log, [ isMethodCall( - 'signInWithCredential', - arguments: { - 'app': auth.app.name, - 'provider': 'google.com', - 'data': { - 'idToken': kMockIdToken, - 'accessToken': kMockAccessToken, - }, + 'signInWithGoogle', + arguments: { + 'idToken': kMockIdToken, + 'accessToken': kMockAccessToken, + 'app': auth.app.name }, ), ], ); }); - test('PhoneAuthProvider signInWithCredential', () async { - final AuthCredential credential = PhoneAuthProvider.getCredential( - verificationId: kMockVerificationId, - smsCode: kMockSmsCode, - ); - await auth.signInWithCredential(credential); + test('signInWithPhoneNumber', () async { + await auth.signInWithPhoneNumber( + verificationId: kMockVerificationId, smsCode: kMockSmsCode); expect(log, [ - isMethodCall('signInWithCredential', arguments: { + isMethodCall('signInWithPhoneNumber', arguments: { + 'verificationId': kMockVerificationId, + 'smsCode': kMockSmsCode, 'app': auth.app.name, - 'provider': 'phone', - 'data': { - 'verificationId': kMockVerificationId, - 'smsCode': kMockSmsCode, - }, }) ]); }); @@ -337,317 +307,276 @@ void main() { ]); }); - test('EmailAuthProvider reauthenticateWithCredential', () async { - final FirebaseUser user = await auth.currentUser(); - log.clear(); - final AuthCredential credential = EmailAuthProvider.getCredential( + test('reauthenticateWithEmailAndPassword', () async { + await auth.reauthenticateWithEmailAndPassword( email: kMockEmail, password: kMockPassword, ); - await user.reauthenticateWithCredential(credential); expect( log, [ isMethodCall( - 'reauthenticateWithCredential', - arguments: { + 'reauthenticateWithEmailAndPassword', + arguments: { + 'email': kMockEmail, + 'password': kMockPassword, 'app': auth.app.name, - 'provider': 'password', - 'data': { - 'email': kMockEmail, - 'password': kMockPassword, - } }, ), ], ); }); - test('GoogleAuthProvider reauthenticateWithCredential', () async { - final FirebaseUser user = await auth.currentUser(); - log.clear(); - final AuthCredential credential = GoogleAuthProvider.getCredential( + test('reauthenticateWithGoogleCredential', () async { + await auth.reauthenticateWithGoogleCredential( idToken: kMockIdToken, accessToken: kMockAccessToken, ); - await user.reauthenticateWithCredential(credential); expect( log, [ isMethodCall( - 'reauthenticateWithCredential', - arguments: { + 'reauthenticateWithGoogleCredential', + arguments: { + 'idToken': kMockIdToken, + 'accessToken': kMockAccessToken, 'app': auth.app.name, - 'provider': 'google.com', - 'data': { - 'idToken': kMockIdToken, - 'accessToken': kMockAccessToken, - }, }, ), ], ); }); - test('FacebookAuthProvider reauthenticateWithCredential', () async { - final FirebaseUser user = await auth.currentUser(); - log.clear(); - final AuthCredential credential = FacebookAuthProvider.getCredential( + test('reauthenticateWithFacebookCredential', () async { + await auth.reauthenticateWithFacebookCredential( accessToken: kMockAccessToken, ); - await user.reauthenticateWithCredential(credential); expect( log, [ isMethodCall( - 'reauthenticateWithCredential', - arguments: { + 'reauthenticateWithFacebookCredential', + arguments: { + 'accessToken': kMockAccessToken, 'app': auth.app.name, - 'provider': 'facebook.com', - 'data': { - 'accessToken': kMockAccessToken, - }, }, ), ], ); }); - test('TwitterAuthProvider reauthenticateWithCredential', () async { - final FirebaseUser user = await auth.currentUser(); - log.clear(); - final AuthCredential credential = TwitterAuthProvider.getCredential( + test('reauthenticateWithTwitterCredential', () async { + await auth.reauthenticateWithTwitterCredential( authToken: kMockAuthToken, authTokenSecret: kMockAuthTokenSecret, ); - await user.reauthenticateWithCredential(credential); expect( log, [ isMethodCall( - 'reauthenticateWithCredential', - arguments: { + 'reauthenticateWithTwitterCredential', + arguments: { + 'authToken': kMockAuthToken, + 'authTokenSecret': kMockAuthTokenSecret, 'app': auth.app.name, - 'provider': 'twitter.com', - 'data': { - 'authToken': kMockAuthToken, - 'authTokenSecret': kMockAuthTokenSecret, - }, }, ), ], ); }); - test('GithubAuthProvider reauthenticateWithCredential', () async { - final FirebaseUser user = await auth.currentUser(); - log.clear(); - final AuthCredential credential = GithubAuthProvider.getCredential( + test('reauthenticateWithGithubCredential', () async { + await auth.reauthenticateWithGithubCredential( token: kMockGithubToken, ); - await user.reauthenticateWithCredential(credential); expect( log, [ isMethodCall( - 'reauthenticateWithCredential', - arguments: { + 'reauthenticateWithGithubCredential', + arguments: { 'app': auth.app.name, - 'provider': 'github.com', - 'data': { - 'token': kMockGithubToken, - }, + 'token': kMockGithubToken, }, ), ], ); }); - test('GoogleAuthProvider linkWithCredential', () async { - final AuthCredential credential = GoogleAuthProvider.getCredential( + test('linkWithGoogleCredential', () async { + final FirebaseUser user = await auth.linkWithGoogleCredential( idToken: kMockIdToken, accessToken: kMockAccessToken, ); - final FirebaseUser user = await auth.linkWithCredential(credential); verifyUser(user); expect( log, [ isMethodCall( - 'linkWithCredential', - arguments: { + 'linkWithGoogleCredential', + arguments: { + 'idToken': kMockIdToken, + 'accessToken': kMockAccessToken, 'app': auth.app.name, - 'provider': 'google.com', - 'data': { - 'idToken': kMockIdToken, - 'accessToken': kMockAccessToken, - }, }, ), ], ); }); - test('FacebookAuthProvider linkWithCredential', () async { - final AuthCredential credential = FacebookAuthProvider.getCredential( + test('linkWithFacebookCredential', () async { + final FirebaseUser user = await auth.linkWithFacebookCredential( accessToken: kMockAccessToken, ); - final FirebaseUser user = await auth.linkWithCredential(credential); verifyUser(user); expect( log, [ isMethodCall( - 'linkWithCredential', - arguments: { + 'linkWithFacebookCredential', + arguments: { + 'accessToken': kMockAccessToken, 'app': auth.app.name, - 'provider': 'facebook.com', - 'data': { - 'accessToken': kMockAccessToken, - }, }, ), ], ); }); - test('FacebookAuthProvider signInWithCredential', () async { - final AuthCredential credential = FacebookAuthProvider.getCredential( + test('linkWithTwitterCredential', () async { + final FirebaseUser user = await auth.linkWithTwitterCredential( + authToken: kMockAuthToken, + authTokenSecret: kMockAuthTokenSecret, + ); + verifyUser(user); + expect( + log, + [ + isMethodCall( + 'linkWithTwitterCredential', + arguments: { + 'authToken': kMockAuthToken, + 'authTokenSecret': kMockAuthTokenSecret, + 'app': auth.app.name, + }, + ), + ], + ); + }); + + test('signInWithFacebook', () async { + final FirebaseUser user = await auth.signInWithFacebook( accessToken: kMockAccessToken, ); - final FirebaseUser user = await auth.signInWithCredential(credential); verifyUser(user); expect( log, [ isMethodCall( - 'signInWithCredential', - arguments: { + 'signInWithFacebook', + arguments: { + 'accessToken': kMockAccessToken, 'app': auth.app.name, - 'provider': 'facebook.com', - 'data': { - 'accessToken': kMockAccessToken, - } }, ), ], ); }); - test('TwitterAuthProvider linkWithCredential', () async { - final AuthCredential credential = TwitterAuthProvider.getCredential( + test('linkWithTwitterCredential', () async { + final FirebaseUser user = await auth.linkWithTwitterCredential( authToken: kMockAuthToken, authTokenSecret: kMockAuthTokenSecret, ); - final FirebaseUser user = await auth.linkWithCredential(credential); verifyUser(user); expect( log, [ isMethodCall( - 'linkWithCredential', - arguments: { + 'linkWithTwitterCredential', + arguments: { 'app': auth.app.name, - 'provider': 'twitter.com', - 'data': { - 'authToken': kMockAuthToken, - 'authTokenSecret': kMockAuthTokenSecret, - }, + 'authToken': kMockAuthToken, + 'authTokenSecret': kMockAuthTokenSecret, }, ), ], ); }); - test('TwitterAuthProvider signInWithCredential', () async { - final AuthCredential credential = TwitterAuthProvider.getCredential( + test('signInWithTwitter', () async { + final FirebaseUser user = await auth.signInWithTwitter( authToken: kMockAuthToken, authTokenSecret: kMockAuthTokenSecret, ); - final FirebaseUser user = await auth.signInWithCredential(credential); verifyUser(user); expect( log, [ isMethodCall( - 'signInWithCredential', - arguments: { + 'signInWithTwitter', + arguments: { 'app': auth.app.name, - 'provider': 'twitter.com', - 'data': { - 'authToken': kMockAuthToken, - 'authTokenSecret': kMockAuthTokenSecret, - }, + 'authToken': kMockAuthToken, + 'authTokenSecret': kMockAuthTokenSecret, }, ), ], ); }); - test('GithubAuthProvider linkWithCredential', () async { - final AuthCredential credential = GithubAuthProvider.getCredential( + test('linkWithGithubCredential', () async { + final FirebaseUser user = await auth.linkWithGithubCredential( token: kMockGithubToken, ); - final FirebaseUser user = await auth.linkWithCredential(credential); verifyUser(user); expect( log, [ isMethodCall( - 'linkWithCredential', - arguments: { + 'linkWithGithubCredential', + arguments: { 'app': auth.app.name, - 'provider': 'github.com', - 'data': { - 'token': kMockGithubToken, - }, + 'token': kMockGithubToken, }, ), ], ); }); - test('GithubAuthProvider signInWithCredential', () async { - final AuthCredential credential = GithubAuthProvider.getCredential( + test('signInWithGithub', () async { + final FirebaseUser user = await auth.signInWithGithub( token: kMockGithubToken, ); - final FirebaseUser user = await auth.signInWithCredential(credential); verifyUser(user); expect( log, [ isMethodCall( - 'signInWithCredential', - arguments: { + 'signInWithGithub', + arguments: { 'app': auth.app.name, - 'provider': 'github.com', - 'data': { - 'token': kMockGithubToken, - }, + 'token': kMockGithubToken, }, ), ], ); }); - test('EmailAuthProvider linkWithCredential', () async { - final AuthCredential credential = EmailAuthProvider.getCredential( + test('linkWithEmailAndPassword', () async { + final FirebaseUser user = await auth.linkWithEmailAndPassword( email: kMockEmail, password: kMockPassword, ); - final FirebaseUser user = await auth.linkWithCredential(credential); verifyUser(user); expect( log, [ isMethodCall( - 'linkWithCredential', - arguments: { + 'linkWithEmailAndPassword', + arguments: { + 'email': kMockEmail, + 'password': kMockPassword, 'app': auth.app.name, - 'provider': 'password', - 'data': { - 'email': kMockEmail, - 'password': kMockPassword, - }, }, ), ], @@ -788,16 +717,16 @@ void main() { ]); }); - test('EmailAuthProvider unlinkFromProvider', () async { + test('unlinkEmailAndPassword', () async { final FirebaseUser user = await auth.currentUser(); - await user.unlinkFromProvider(EmailAuthProvider.providerId); + await user.unlinkEmailAndPassword(); expect(log, [ isMethodCall( 'currentUser', arguments: {'app': auth.app.name}, ), isMethodCall( - 'unlinkFromProvider', + 'unlinkCredential', arguments: { 'app': auth.app.name, 'provider': 'password', @@ -806,16 +735,16 @@ void main() { ]); }); - test('GoogleAuthProvider unlinkFromProvider', () async { + test('unlinkGoogleCredential', () async { final FirebaseUser user = await auth.currentUser(); - await user.unlinkFromProvider(GoogleAuthProvider.providerId); + await user.unlinkGoogleCredential(); expect(log, [ isMethodCall( 'currentUser', arguments: {'app': auth.app.name}, ), isMethodCall( - 'unlinkFromProvider', + 'unlinkCredential', arguments: { 'app': auth.app.name, 'provider': 'google.com', @@ -824,16 +753,16 @@ void main() { ]); }); - test('FacebookAuthProvider unlinkFromProvider', () async { + test('unlinkFacebookCredential', () async { final FirebaseUser user = await auth.currentUser(); - await user.unlinkFromProvider(FacebookAuthProvider.providerId); + await user.unlinkFacebookCredential(); expect(log, [ isMethodCall( 'currentUser', arguments: {'app': auth.app.name}, ), isMethodCall( - 'unlinkFromProvider', + 'unlinkCredential', arguments: { 'app': auth.app.name, 'provider': 'facebook.com', @@ -842,34 +771,16 @@ void main() { ]); }); - test('PhoneAuthProvider unlinkFromProvider', () async { - final FirebaseUser user = await auth.currentUser(); - await user.unlinkFromProvider(PhoneAuthProvider.providerId); - expect(log, [ - isMethodCall( - 'currentUser', - arguments: {'app': auth.app.name}, - ), - isMethodCall( - 'unlinkFromProvider', - arguments: { - 'app': auth.app.name, - 'provider': 'phone', - }, - ), - ]); - }); - - test('TwitterAuthProvider unlinkFromProvider', () async { + test('unlinkTwitterCredential', () async { final FirebaseUser user = await auth.currentUser(); - await user.unlinkFromProvider(TwitterAuthProvider.providerId); + await user.unlinkTwitterCredential(); expect(log, [ isMethodCall( 'currentUser', arguments: {'app': auth.app.name}, ), isMethodCall( - 'unlinkFromProvider', + 'unlinkCredential', arguments: { 'app': auth.app.name, 'provider': 'twitter.com', @@ -878,16 +789,16 @@ void main() { ]); }); - test('GithubAuthProvider unlinkFromProvider', () async { + test('unlinkGithubCredential', () async { final FirebaseUser user = await auth.currentUser(); - await user.unlinkFromProvider(GithubAuthProvider.providerId); + await user.unlinkGithubCredential(); expect(log, [ isMethodCall( 'currentUser', arguments: {'app': auth.app.name}, ), isMethodCall( - 'unlinkFromProvider', + 'unlinkCredential', arguments: { 'app': auth.app.name, 'provider': 'github.com',