Skip to content

Commit

Permalink
feat(auth): expose the missing MultiFactor classes through the univer…
Browse files Browse the repository at this point in the history
…sal package (#9194)

* feat(auth): expose the missing MutliFactor classes through the universal package

* feat(auth): add documentation
  • Loading branch information
Lyokone committed Jul 26, 2022
1 parent 96d35df commit d8bf818
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 34 deletions.
Expand Up @@ -14,8 +14,8 @@ import 'package:flutter/foundation.dart';
export 'package:firebase_auth_platform_interface/firebase_auth_platform_interface.dart'
show
FirebaseAuthException,
FirebaseAuthMultiFactorException,
MultiFactorInfo,
MultiFactorSession,
PhoneMultiFactorInfo,
IdTokenResult,
UserMetadata,
Expand Down
81 changes: 62 additions & 19 deletions packages/firebase_auth/firebase_auth/lib/src/firebase_auth.dart
Expand Up @@ -492,10 +492,16 @@ class FirebaseAuth extends FirebasePluginPlatform {
/// - Thrown if the credential is a [PhoneAuthProvider.credential] and the
/// verification ID of the credential is not valid.id.
Future<UserCredential> signInWithCredential(AuthCredential credential) async {
return UserCredential._(
this,
await _delegate.signInWithCredential(credential),
);
try {
return UserCredential._(
this,
await _delegate.signInWithCredential(credential),
);
} on FirebaseAuthMultiFactorExceptionPlatform catch (e) {
throw FirebaseAuthMultiFactorException._(this, e);
} catch (e) {
rethrow;
}
}

/// Tries to sign in a user with a given custom token.
Expand All @@ -519,7 +525,14 @@ class FirebaseAuth extends FirebasePluginPlatform {
/// - **invalid-custom-token**:
/// - Thrown if the custom token format is incorrect.
Future<UserCredential> signInWithCustomToken(String token) async {
return UserCredential._(this, await _delegate.signInWithCustomToken(token));
try {
return UserCredential._(
this, await _delegate.signInWithCustomToken(token));
} on FirebaseAuthMultiFactorExceptionPlatform catch (e) {
throw FirebaseAuthMultiFactorException._(this, e);
} catch (e) {
rethrow;
}
}

/// Attempts to sign in a user with the given email address and password.
Expand All @@ -545,10 +558,16 @@ class FirebaseAuth extends FirebasePluginPlatform {
required String email,
required String password,
}) async {
return UserCredential._(
this,
await _delegate.signInWithEmailAndPassword(email, password),
);
try {
return UserCredential._(
this,
await _delegate.signInWithEmailAndPassword(email, password),
);
} on FirebaseAuthMultiFactorExceptionPlatform catch (e) {
throw FirebaseAuthMultiFactorException._(this, e);
} catch (e) {
rethrow;
}
}

/// Signs in using an email address and email sign-in link.
Expand All @@ -570,10 +589,16 @@ class FirebaseAuth extends FirebasePluginPlatform {
required String email,
required String emailLink,
}) async {
return UserCredential._(
this,
await _delegate.signInWithEmailLink(email, emailLink),
);
try {
return UserCredential._(
this,
await _delegate.signInWithEmailLink(email, emailLink),
);
} on FirebaseAuthMultiFactorExceptionPlatform catch (e) {
throw FirebaseAuthMultiFactorException._(this, e);
} catch (e) {
rethrow;
}
}

/// Signs in with an AuthProvider using native authentication flow.
Expand All @@ -584,10 +609,16 @@ class FirebaseAuth extends FirebasePluginPlatform {
Future<UserCredential> signInWithAuthProvider(
AuthProvider provider,
) async {
return UserCredential._(
this,
await _delegate.signInWithAuthProvider(provider),
);
try {
return UserCredential._(
this,
await _delegate.signInWithAuthProvider(provider),
);
} on FirebaseAuthMultiFactorExceptionPlatform catch (e) {
throw FirebaseAuthMultiFactorException._(this, e);
} catch (e) {
rethrow;
}
}

/// Starts a sign-in flow for a phone number.
Expand Down Expand Up @@ -624,15 +655,27 @@ class FirebaseAuth extends FirebasePluginPlatform {
///
/// This method is only available on web based platforms.
Future<UserCredential> signInWithPopup(AuthProvider provider) async {
return UserCredential._(this, await _delegate.signInWithPopup(provider));
try {
return UserCredential._(this, await _delegate.signInWithPopup(provider));
} on FirebaseAuthMultiFactorExceptionPlatform catch (e) {
throw FirebaseAuthMultiFactorException._(this, e);
} catch (e) {
rethrow;
}
}

/// Authenticates a Firebase client using a full-page redirect flow.
///
/// To handle the results and errors for this operation, refer to
/// [getRedirectResult].
Future<void> signInWithRedirect(AuthProvider provider) {
return _delegate.signInWithRedirect(provider);
try {
return _delegate.signInWithRedirect(provider);
} on FirebaseAuthMultiFactorExceptionPlatform catch (e) {
throw FirebaseAuthMultiFactorException._(this, e);
} catch (e) {
rethrow;
}
}

/// Signs out the current user.
Expand Down
67 changes: 63 additions & 4 deletions packages/firebase_auth/firebase_auth/lib/src/multi_factor.dart
Expand Up @@ -17,10 +17,10 @@ class MultiFactor {
///
/// [displayName] can be used to provide a display name for the second factor.
Future<void> enroll(
MultiFactorAssertionPlatform assertion, {
MultiFactorAssertion assertion, {
String? displayName,
}) async {
return _delegate.enroll(assertion, displayName: displayName);
return _delegate.enroll(assertion._delegate, displayName: displayName);
}

/// Unenrolls a second factor from this user.
Expand All @@ -45,9 +45,68 @@ class MultiFactor {
class PhoneMultiFactorGenerator {
/// Transforms a PhoneAuthCredential into a [MultiFactorAssertion]
/// which can be used to confirm ownership of a phone second factor.
static MultiFactorAssertionPlatform getAssertion(
static MultiFactorAssertion getAssertion(
PhoneAuthCredential credential,
) {
return PhoneMultiFactorGeneratorPlatform.instance.getAssertion(credential);
final assertion =
PhoneMultiFactorGeneratorPlatform.instance.getAssertion(credential);
return MultiFactorAssertion._(assertion);
}
}

/// Represents an assertion that the Firebase Authentication server
/// can use to authenticate a user as part of a multi-factor flow.
class MultiFactorAssertion {
final MultiFactorAssertionPlatform _delegate;

MultiFactorAssertion._(this._delegate) {
MultiFactorAssertionPlatform.verifyExtends(_delegate);
}
}

/// Utility class that contains methods to resolve second factor
/// requirements on users that have opted into two-factor authentication.
class MultiFactorResolver {
final FirebaseAuth _auth;
final MultiFactorResolverPlatform _delegate;

MultiFactorResolver._(this._auth, this._delegate) {
MultiFactorResolverPlatform.verifyExtends(_delegate);
}

/// List of [MultiFactorInfo] which represents the available
/// second factors that can be used to complete the sign-in for the current session.
List<MultiFactorInfo> get hints => _delegate.hints;

/// A MultiFactorSession, an opaque session identifier for the current sign-in flow.
MultiFactorSession get session => _delegate.session;

/// Completes sign in with a second factor using an MultiFactorAssertion which
/// confirms that the user has successfully completed the second factor challenge.
Future<UserCredential> resolveSignIn(
MultiFactorAssertion assertion,
) async {
final credential = await _delegate.resolveSignIn(assertion._delegate);
return UserCredential._(_auth, credential);
}
}

/// MultiFactor exception related to Firebase Authentication. Check the error code
/// and message for more details.
class FirebaseAuthMultiFactorException extends FirebaseAuthException {
final FirebaseAuth _auth;
final FirebaseAuthMultiFactorExceptionPlatform _delegate;

FirebaseAuthMultiFactorException._(this._auth, this._delegate)
: super(
code: _delegate.code,
message: _delegate.message,
email: _delegate.email,
credential: _delegate.credential,
phoneNumber: _delegate.phoneNumber,
tenantId: _delegate.tenantId,
);

MultiFactorResolver get resolver =>
MultiFactorResolver._(_auth, _delegate.resolver);
}
Expand Up @@ -8,11 +8,11 @@ import 'package:meta/meta.dart';

/// MultiFactor exception related to Firebase Authentication. Check the error code
/// and message for more details.
class FirebaseAuthMultiFactorException extends FirebaseAuthException
class FirebaseAuthMultiFactorExceptionPlatform extends FirebaseAuthException
implements Exception {
// ignore: public_member_api_docs
@protected
FirebaseAuthMultiFactorException({
FirebaseAuthMultiFactorExceptionPlatform({
String? message,
required String code,
String? email,
Expand Down
Expand Up @@ -74,7 +74,7 @@ FirebaseException platformExceptionToFirebaseAuthException(
);
}

FirebaseAuthMultiFactorException parseMultiFactorError(
FirebaseAuthMultiFactorExceptionPlatform parseMultiFactorError(
Map<String, Object?> details) {
final code = details['code'] as String?;
final message = details['message'] as String?;
Expand Down Expand Up @@ -124,7 +124,7 @@ FirebaseAuthMultiFactorException parseMultiFactorError(
auth,
);

return FirebaseAuthMultiFactorException(
return FirebaseAuthMultiFactorExceptionPlatform(
code: code ?? 'Unknown',
message: message,
resolver: multiFactorResolver,
Expand Down
Expand Up @@ -56,20 +56,39 @@ class MultiFactorSession {
final String id;
}

/// {@template .multiFactorAssertion}
/// Represents an assertion that the Firebase Authentication server
/// can use to authenticate a user as part of a multi-factor flow.
class MultiFactorAssertionPlatform {}
/// {@endtemplate}
class MultiFactorAssertionPlatform extends PlatformInterface {
/// {@macro .multiFactorAssertion}
MultiFactorAssertionPlatform() : super(token: _token);

static final Object _token = Object();

/// Ensures that any delegate class has extended a [MultiFactorResolverPlatform].
static void verifyExtends(MultiFactorAssertionPlatform instance) {
PlatformInterface.verifyToken(instance, _token);
}
}

/// {@macro .platformInterfaceMultiFactorResolverPlatform}
/// {@template .platformInterfaceMultiFactorResolverPlatform}
/// Utility class that contains methods to resolve second factor
/// requirements on users that have opted into two-factor authentication.
/// {@endtemplate}
class MultiFactorResolverPlatform {
class MultiFactorResolverPlatform extends PlatformInterface {
/// {@macro .platformInterfaceMultiFactorResolverPlatform}
const MultiFactorResolverPlatform(
MultiFactorResolverPlatform(
this.hints,
this.session,
);
) : super(token: _token);

static final Object _token = Object();

/// Ensures that any delegate class has extended a [MultiFactorResolverPlatform].
static void verifyExtends(MultiFactorResolverPlatform instance) {
PlatformInterface.verifyToken(instance, _token);
}

/// List of [MultiFactorInfo] which represents the available
/// second factors that can be used to complete the sign-in for the current session.
Expand Down
Expand Up @@ -50,7 +50,7 @@ FirebaseAuthException getFirebaseAuthException(
firebaseError as auth_interop.MultiFactorError,
);

return FirebaseAuthMultiFactorException(
return FirebaseAuthMultiFactorExceptionPlatform(
code: code,
message: message,
email: firebaseError.email,
Expand Down

0 comments on commit d8bf818

Please sign in to comment.