diff --git a/packages/wyatt_authentication_bloc/lib/src/core/constants/form_name.dart b/packages/wyatt_authentication_bloc/lib/src/core/constants/form_name.dart
index 5a788715..af623e70 100644
--- a/packages/wyatt_authentication_bloc/lib/src/core/constants/form_name.dart
+++ b/packages/wyatt_authentication_bloc/lib/src/core/constants/form_name.dart
@@ -17,4 +17,5 @@
abstract class AuthFormName {
static const String signUpForm = 'wyattSignUpForm';
static const String signInForm = 'wyattSignInForm';
+ static const String passwordResetForm = 'wyattPasswordResetForm';
}
diff --git a/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions.dart b/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions.dart
index 11e7835d..5ef49c83 100644
--- a/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions.dart
+++ b/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions.dart
@@ -246,3 +246,10 @@ abstract class SignOutFailureInterface extends AuthenticationFailureInterface {
/// {@macro sign_out_failure}
SignOutFailureInterface.fromCode(super.code) : super.fromCode();
}
+
+abstract class GetIdTokenFailureInterface
+ extends AuthenticationFailureInterface {
+ GetIdTokenFailureInterface(super.code, super.msg);
+
+ GetIdTokenFailureInterface.fromCode(super.code) : super.fromCode();
+}
diff --git a/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions_firebase.dart b/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions_firebase.dart
index 42f410a2..7a6e37b4 100644
--- a/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions_firebase.dart
+++ b/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions_firebase.dart
@@ -270,3 +270,10 @@ class SignOutFailureFirebase extends SignOutFailureInterface {
SignOutFailureFirebase.fromCode(super.code) : super.fromCode();
}
+
+class GetIdTokenFailureFirebase extends GetIdTokenFailureInterface {
+ GetIdTokenFailureFirebase([String? code, String? msg])
+ : super(code ?? 'unknown', msg ?? 'An unknown error occurred.');
+
+ GetIdTokenFailureFirebase.fromCode(super.code) : super.fromCode();
+}
diff --git a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_firebase_data_source_impl.dart b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_firebase_data_source_impl.dart
index f0c55b8d..565b76cc 100644
--- a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_firebase_data_source_impl.dart
+++ b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_firebase_data_source_impl.dart
@@ -15,7 +15,6 @@
// along with this program. If not, see .
import 'package:firebase_auth/firebase_auth.dart';
-import 'package:wyatt_architecture/wyatt_architecture.dart';
import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart';
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
@@ -28,7 +27,18 @@ class AuthenticationFirebaseDataSourceImpl
Account _mapper(User user) => AccountModel(
uid: user.uid,
+ emailVerified: user.emailVerified,
+ isAnonymous: user.isAnonymous,
+ providerId: user.providerData.first.providerId,
+ creationTime: user.metadata.creationTime,
+ lastSignInTime: user.metadata.lastSignInTime,
+ isNewUser: (user.metadata.creationTime != null &&
+ user.metadata.lastSignInTime != null)
+ ? user.metadata.lastSignInTime! == user.metadata.creationTime!
+ : null,
email: user.email,
+ phoneNumber: user.phoneNumber,
+ photoURL: user.photoURL,
);
@override
@@ -55,6 +65,8 @@ class AuthenticationFirebaseDataSourceImpl
}
@override
+
+ /// {@macro signup}
Future signUp({
required String email,
required String password,
@@ -95,9 +107,10 @@ class AuthenticationFirebaseDataSourceImpl
} else {
throw Exception(); // Get caught just after.
}
+ } on FirebaseAuthException catch (e) {
+ throw GetIdTokenFailureFirebase.fromCode(e.code);
} catch (_) {
- // TODO(hpcl): implement a non ambiguous exception for this case
- throw ServerException();
+ throw GetIdTokenFailureFirebase();
}
}
@@ -107,4 +120,83 @@ class AuthenticationFirebaseDataSourceImpl
final Account? account = (user.isNotNull) ? _mapper(user!) : null;
return account;
});
+
+ @override
+ Future confirmPasswordReset({
+ required String code,
+ required String newPassword,
+ }) async {
+ try {
+ await _firebaseAuth.confirmPasswordReset(
+ code: code,
+ newPassword: newPassword,
+ );
+ } on FirebaseAuthException catch (e) {
+ throw ConfirmPasswordResetFailureFirebase.fromCode(e.code);
+ } catch (_) {
+ throw ConfirmPasswordResetFailureFirebase();
+ }
+ }
+
+ @override
+ Future sendEmailVerification() async {
+ try {
+ await _firebaseAuth.currentUser!.sendEmailVerification();
+ } on FirebaseAuthException catch (e) {
+ throw SendEmailVerificationFailureFirebase.fromCode(e.code);
+ } catch (_) {
+ throw SendEmailVerificationFailureFirebase();
+ }
+ }
+
+ @override
+ Future sendPasswordResetEmail({required String email}) async {
+ try {
+ await _firebaseAuth.sendPasswordResetEmail(email: email);
+ } on FirebaseAuthException catch (e) {
+ throw SendPasswordResetEmailFailureFirebase.fromCode(e.code);
+ } catch (_) {
+ throw SendPasswordResetEmailFailureFirebase();
+ }
+ }
+
+ @override
+ Future signInAnonymously() async {
+ try {
+ final userCredential = await _firebaseAuth.signInAnonymously();
+ final user = userCredential.user;
+ if (user.isNotNull) {
+ return _mapper(user!);
+ } else {
+ throw Exception(); // Get caught just after.
+ }
+ } on FirebaseAuthException catch (e) {
+ throw SignInAnonymouslyFailureFirebase.fromCode(e.code);
+ } catch (_) {
+ throw SignInAnonymouslyFailureFirebase();
+ }
+ }
+
+ @override
+ Future verifyPasswordResetCode({required String code}) async {
+ try {
+ final email = await _firebaseAuth.verifyPasswordResetCode(code);
+ return email.isNotNullOrEmpty;
+ } on FirebaseAuthException catch (e) {
+ throw VerifyPasswordResetCodeFailureFirebase.fromCode(e.code);
+ } catch (_) {
+ throw VerifyPasswordResetCodeFailureFirebase();
+ }
+ }
+
+ @override
+ Future refresh() async {
+ try {
+ await _firebaseAuth.currentUser!.reload();
+ } on FirebaseAuthException catch (e) {
+ throw RefreshFailureFirebase.fromCode(e.code);
+ } catch (_) {
+ throw RefreshFailureFirebase();
+ }
+ }
}
diff --git a/packages/wyatt_authentication_bloc/lib/src/data/models/account_model.dart b/packages/wyatt_authentication_bloc/lib/src/data/models/account_model.dart
index 0d1d6b65..2405747d 100644
--- a/packages/wyatt_authentication_bloc/lib/src/data/models/account_model.dart
+++ b/packages/wyatt_authentication_bloc/lib/src/data/models/account_model.dart
@@ -1,3 +1,4 @@
+// ignore_for_file: public_member_api_docs, sort_constructors_first
// Copyright (C) 2022 WYATT GROUP
// Please see the AUTHORS file for details.
//
@@ -16,12 +17,47 @@
import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart';
-class AccountModel implements Account {
+class AccountModel extends Account {
@override
final String uid;
@override
final String? email;
- AccountModel({required this.uid, required this.email});
+ @override
+ final DateTime? creationTime;
+
+ @override
+ final bool emailVerified;
+
+ @override
+ final bool isAnonymous;
+
+ @override
+ final bool? isNewUser;
+
+ @override
+ final DateTime? lastSignInTime;
+
+ @override
+ final String? phoneNumber;
+
+ @override
+ final String? photoURL;
+
+ @override
+ final String providerId;
+
+ AccountModel({
+ required this.uid,
+ required this.emailVerified,
+ required this.isAnonymous,
+ required this.providerId,
+ this.lastSignInTime,
+ this.creationTime,
+ this.isNewUser,
+ this.email,
+ this.phoneNumber,
+ this.photoURL,
+ });
}
diff --git a/packages/wyatt_authentication_bloc/lib/src/data/repositories/authentication_repository_impl.dart b/packages/wyatt_authentication_bloc/lib/src/data/repositories/authentication_repository_impl.dart
index 00bf067c..a3ecfb6f 100644
--- a/packages/wyatt_authentication_bloc/lib/src/data/repositories/authentication_repository_impl.dart
+++ b/packages/wyatt_authentication_bloc/lib/src/data/repositories/authentication_repository_impl.dart
@@ -208,4 +208,70 @@ class AuthenticationRepositoryImpl
AccountWrapperModel(account, null),
);
});
+
+ @override
+ FutureResult confirmPasswordReset({
+ required String code,
+ required String newPassword,
+ }) =>
+ Result.tryCatchAsync(
+ () async {
+ await _authenticationRemoteDataSource.confirmPasswordReset(
+ code: code,
+ newPassword: newPassword,
+ );
+ },
+ (error) => error,
+ );
+
+ @override
+ FutureResult sendEmailVerification() =>
+ Result.tryCatchAsync(
+ () async {
+ await _authenticationRemoteDataSource.sendEmailVerification();
+ },
+ (error) => error,
+ );
+
+ @override
+ FutureResult sendPasswordResetEmail({required String email}) =>
+ Result.tryCatchAsync(
+ () async {
+ await _authenticationRemoteDataSource.sendPasswordResetEmail(
+ email: email,
+ );
+ },
+ (error) => error,
+ );
+
+ @override
+ FutureResult signInAnonymously() =>
+ Result.tryCatchAsync(
+ () async {
+ final account =
+ await _authenticationRemoteDataSource.signInAnonymously();
+ return account;
+ },
+ (error) => error,
+ );
+
+ @override
+ FutureResult verifyPasswordResetCode({required String code}) =>
+ Result.tryCatchAsync(
+ () async {
+ final response = await _authenticationRemoteDataSource
+ .verifyPasswordResetCode(code: code);
+ return response;
+ },
+ (error) => error,
+ );
+
+ @override
+ FutureResult refresh() =>
+ Result.tryCatchAsync(
+ () async {
+ await _authenticationRemoteDataSource.refresh();
+ },
+ (error) => error,
+ );
}
diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/remote/authentication_remote_data_source.dart b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/remote/authentication_remote_data_source.dart
index 3bd615e1..755aa157 100644
--- a/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/remote/authentication_remote_data_source.dart
+++ b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/remote/authentication_remote_data_source.dart
@@ -30,7 +30,22 @@ abstract class AuthenticationRemoteDataSource extends BaseRemoteDataSource {
Future signOut();
+ Future refresh();
+
Stream streamAccount();
Future getIdentityToken();
+
+ Future sendEmailVerification();
+
+ Future sendPasswordResetEmail({required String email});
+
+ Future confirmPasswordReset({
+ required String code,
+ required String newPassword,
+ });
+
+ Future verifyPasswordResetCode({required String code});
+
+ Future signInAnonymously();
}
diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/account.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/account.dart
index 97d5deeb..976be6be 100644
--- a/packages/wyatt_authentication_bloc/lib/src/domain/entities/account.dart
+++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/account.dart
@@ -14,9 +14,10 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
+import 'package:equatable/equatable.dart';
import 'package:wyatt_architecture/wyatt_architecture.dart';
-abstract class Account extends Entity {
+abstract class Account extends Equatable implements Entity {
/// The user's unique ID.
String get uid;
@@ -24,4 +25,52 @@ abstract class Account extends Entity {
///
/// Will be `null` if signing in anonymously.
String? get email;
+
+ /// Returns whether the users email address has been verified.
+ ///
+ /// To send a verification email, see `SendEmailVerification`.
+ bool get emailVerified;
+
+ /// Returns whether the user is a anonymous.
+ bool get isAnonymous;
+
+ /// Returns the users account creation time.
+ ///
+ /// When this account was created as dictated by the server clock.
+ DateTime? get creationTime;
+
+ /// When the user last signed in as dictated by the server clock.
+ DateTime? get lastSignInTime;
+
+ /// Returns the users phone number.
+ ///
+ /// This property will be `null` if the user has not signed in or been has
+ /// their phone number linked.
+ String? get phoneNumber;
+
+ /// Returns a photo URL for the user.
+ ///
+ /// This property will be populated if the user has signed in or been linked
+ /// with a 3rd party OAuth provider (such as Google).
+ String? get photoURL;
+
+ /// The provider ID for the user.
+ String get providerId;
+
+ /// Whether the user account has been recently created.
+ bool? get isNewUser;
+
+ @override
+ List