diff --git a/melos.yaml b/melos.yaml index 6b868b96..0dd52481 100644 --- a/melos.yaml +++ b/melos.yaml @@ -21,13 +21,10 @@ scripts: run: dart analyze . --fatal-infos test: - description: Run tests in a specific package. - run: dart test - exec: - concurrency: 1 - packageFilters: - dirExists: - - test + description: Run tests in all packages. + run: | + melos exec -c 1 --flutter --dir-exists="test" -- "flutter test" + melos exec -c 1 --no-flutter --dir-exists="test" -- "dart test" example-passkeys-web: description: Run passkeys example on web. diff --git a/packages/corbado_api_client/lib/frontendapi/lib/src/model/auth_type.g.dart b/packages/corbado_api_client/lib/frontendapi/lib/src/model/auth_type.g.dart index c5502f2e..548aecb3 100644 --- a/packages/corbado_api_client/lib/frontendapi/lib/src/model/auth_type.g.dart +++ b/packages/corbado_api_client/lib/frontendapi/lib/src/model/auth_type.g.dart @@ -33,7 +33,7 @@ class _$AuthTypeMeta { BuiltSet get values => _$values; } -abstract class _$AuthTypeMixin { +mixin _$AuthTypeMixin { // ignore: non_constant_identifier_names _$AuthTypeMeta get AuthType => const _$AuthTypeMeta(); } diff --git a/packages/corbado_api_client/lib/frontendapi/lib/src/model/block_type.g.dart b/packages/corbado_api_client/lib/frontendapi/lib/src/model/block_type.g.dart index 0d6515a4..50abe29f 100644 --- a/packages/corbado_api_client/lib/frontendapi/lib/src/model/block_type.g.dart +++ b/packages/corbado_api_client/lib/frontendapi/lib/src/model/block_type.g.dart @@ -89,7 +89,7 @@ class _$BlockTypeMeta { BuiltSet get values => _$values; } -abstract class _$BlockTypeMixin { +mixin _$BlockTypeMixin { // ignore: non_constant_identifier_names _$BlockTypeMeta get BlockType => const _$BlockTypeMeta(); } diff --git a/packages/corbado_api_client/lib/frontendapi/lib/src/model/login_identifier_type.g.dart b/packages/corbado_api_client/lib/frontendapi/lib/src/model/login_identifier_type.g.dart index 0c0f2de5..f85d8e82 100644 --- a/packages/corbado_api_client/lib/frontendapi/lib/src/model/login_identifier_type.g.dart +++ b/packages/corbado_api_client/lib/frontendapi/lib/src/model/login_identifier_type.g.dart @@ -39,7 +39,7 @@ class _$LoginIdentifierTypeMeta { BuiltSet get values => _$values; } -abstract class _$LoginIdentifierTypeMixin { +mixin _$LoginIdentifierTypeMixin { // ignore: non_constant_identifier_names _$LoginIdentifierTypeMeta get LoginIdentifierType => const _$LoginIdentifierTypeMeta(); diff --git a/packages/corbado_api_client/lib/frontendapi/lib/src/model/passkey_event_type.g.dart b/packages/corbado_api_client/lib/frontendapi/lib/src/model/passkey_event_type.g.dart index 096cb729..610391f1 100644 --- a/packages/corbado_api_client/lib/frontendapi/lib/src/model/passkey_event_type.g.dart +++ b/packages/corbado_api_client/lib/frontendapi/lib/src/model/passkey_event_type.g.dart @@ -83,7 +83,7 @@ class _$PasskeyEventTypeMeta { BuiltSet get values => _$values; } -abstract class _$PasskeyEventTypeMixin { +mixin _$PasskeyEventTypeMixin { // ignore: non_constant_identifier_names _$PasskeyEventTypeMeta get PasskeyEventType => const _$PasskeyEventTypeMeta(); } diff --git a/packages/corbado_api_client/lib/frontendapi/lib/src/model/passkey_icon_set.g.dart b/packages/corbado_api_client/lib/frontendapi/lib/src/model/passkey_icon_set.g.dart index f5c551a3..26c05df8 100644 --- a/packages/corbado_api_client/lib/frontendapi/lib/src/model/passkey_icon_set.g.dart +++ b/packages/corbado_api_client/lib/frontendapi/lib/src/model/passkey_icon_set.g.dart @@ -40,7 +40,7 @@ class _$PasskeyIconSetMeta { BuiltSet get values => _$values; } -abstract class _$PasskeyIconSetMixin { +mixin _$PasskeyIconSetMixin { // ignore: non_constant_identifier_names _$PasskeyIconSetMeta get PasskeyIconSet => const _$PasskeyIconSetMeta(); } diff --git a/packages/corbado_api_client/lib/frontendapi/lib/src/model/social_provider_type.g.dart b/packages/corbado_api_client/lib/frontendapi/lib/src/model/social_provider_type.g.dart index 4fc48bcb..53fbb5f9 100644 --- a/packages/corbado_api_client/lib/frontendapi/lib/src/model/social_provider_type.g.dart +++ b/packages/corbado_api_client/lib/frontendapi/lib/src/model/social_provider_type.g.dart @@ -36,7 +36,7 @@ class _$SocialProviderTypeMeta { BuiltSet get values => _$values; } -abstract class _$SocialProviderTypeMixin { +mixin _$SocialProviderTypeMixin { // ignore: non_constant_identifier_names _$SocialProviderTypeMeta get SocialProviderType => const _$SocialProviderTypeMeta(); diff --git a/packages/corbado_api_client/lib/frontendapi/lib/src/model/verification_method.g.dart b/packages/corbado_api_client/lib/frontendapi/lib/src/model/verification_method.g.dart index bab66d3c..697de150 100644 --- a/packages/corbado_api_client/lib/frontendapi/lib/src/model/verification_method.g.dart +++ b/packages/corbado_api_client/lib/frontendapi/lib/src/model/verification_method.g.dart @@ -36,7 +36,7 @@ class _$VerificationMethodMeta { BuiltSet get values => _$values; } -abstract class _$VerificationMethodMixin { +mixin _$VerificationMethodMixin { // ignore: non_constant_identifier_names _$VerificationMethodMeta get VerificationMethod => const _$VerificationMethodMeta(); diff --git a/packages/corbado_auth/lib/src/corbado_auth.dart b/packages/corbado_auth/lib/src/corbado_auth.dart index c002bccd..47b74bc9 100644 --- a/packages/corbado_auth/lib/src/corbado_auth.dart +++ b/packages/corbado_auth/lib/src/corbado_auth.dart @@ -97,6 +97,7 @@ class CorbadoAuth { _corbadoService = await createClient( projectId, passkeyAuthenticator: passkeyAuthenticator, + // ignore: deprecated_member_use_from_same_package customDomain: customDomain, ); _sessionService = _buildSessionService( diff --git a/packages/corbado_auth/lib/src/services/corbado/corbado_native.dart b/packages/corbado_auth/lib/src/services/corbado/corbado_native.dart index 1c054854..0c1dae0f 100644 --- a/packages/corbado_auth/lib/src/services/corbado/corbado_native.dart +++ b/packages/corbado_auth/lib/src/services/corbado/corbado_native.dart @@ -15,6 +15,7 @@ Future createClient( }) async { final basePath = CorbadoService.getFrontendAPIDomain( projectId, + // ignore: deprecated_member_use_from_same_package customDomain: customDomain, ); diff --git a/packages/corbado_auth/lib/src/services/corbado/corbado_web.dart b/packages/corbado_auth/lib/src/services/corbado/corbado_web.dart index 7ab40061..d81e4ffd 100644 --- a/packages/corbado_auth/lib/src/services/corbado/corbado_web.dart +++ b/packages/corbado_auth/lib/src/services/corbado/corbado_web.dart @@ -12,6 +12,7 @@ Future createClient( }) async { final basePath = CorbadoService.getFrontendAPIDomain( projectId, + // ignore: deprecated_member_use_from_same_package customDomain: customDomain, ); diff --git a/packages/corbado_auth_firebase/analysis_options.yaml b/packages/corbado_auth_firebase/analysis_options.yaml index afce6018..03d355b0 100644 --- a/packages/corbado_auth_firebase/analysis_options.yaml +++ b/packages/corbado_auth_firebase/analysis_options.yaml @@ -1,4 +1,8 @@ include: package:very_good_analysis/analysis_options.5.0.0.yaml +analyzer: + exclude: + - "**/*.g.dart" + formatter: trailing_commas: preserve diff --git a/packages/corbado_auth_firebase/example/lib/auth_service.dart b/packages/corbado_auth_firebase/example/lib/auth_service.dart index 721ef49c..dc11bc10 100644 --- a/packages/corbado_auth_firebase/example/lib/auth_service.dart +++ b/packages/corbado_auth_firebase/example/lib/auth_service.dart @@ -42,7 +42,7 @@ class AuthService { required String password, }) async { try { - final credential = await _firebaseAuth.createUserWithEmailAndPassword( + await _firebaseAuth.createUserWithEmailAndPassword( email: email, password: password, ); diff --git a/packages/corbado_auth_firebase/example/lib/pages/sign_up_page.dart b/packages/corbado_auth_firebase/example/lib/pages/sign_up_page.dart index a83e2c3d..71d19308 100644 --- a/packages/corbado_auth_firebase/example/lib/pages/sign_up_page.dart +++ b/packages/corbado_auth_firebase/example/lib/pages/sign_up_page.dart @@ -105,7 +105,7 @@ class SignUpPage extends HookConsumerWidget { children: [ Switch( value: usePasskeys.value, - activeThumbColor: Theme.of(context).primaryColor, + activeColor: Theme.of(context).primaryColor, onChanged: (bool value) { usePasskeys.value = value; }, diff --git a/packages/corbado_auth_firebase/example/lib/widgets/passkey_list_item.dart b/packages/corbado_auth_firebase/example/lib/widgets/passkey_list_item.dart index 809a78bb..b4f99cfb 100644 --- a/packages/corbado_auth_firebase/example/lib/widgets/passkey_list_item.dart +++ b/packages/corbado_auth_firebase/example/lib/widgets/passkey_list_item.dart @@ -31,7 +31,7 @@ class PasskeyListItem extends HookWidget { style: Theme.of(context).textTheme.bodySmall, ), Text( - 'Device: ${passkeyInfo.userAgent}', + 'Device: ${passkeyInfo.sourceBrowser} on ${passkeyInfo.sourceOS}', style: Theme.of(context).textTheme.bodySmall, ), Text( diff --git a/packages/corbado_auth_firebase/example/test/widget_test.dart b/packages/corbado_auth_firebase/example/test/widget_test.dart deleted file mode 100644 index 092d222f..00000000 --- a/packages/corbado_auth_firebase/example/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:example/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -} diff --git a/packages/corbado_auth_firebase/lib/src/corbado_auth_firebase.dart b/packages/corbado_auth_firebase/lib/src/corbado_auth_firebase.dart index 69b1e692..1454ac07 100644 --- a/packages/corbado_auth_firebase/lib/src/corbado_auth_firebase.dart +++ b/packages/corbado_auth_firebase/lib/src/corbado_auth_firebase.dart @@ -6,6 +6,7 @@ import 'package:corbado_auth_firebase/src/services/corbado.dart'; import 'package:passkeys/authenticator.dart'; import 'package:ua_client_hints/ua_client_hints.dart'; +/// Entry point that connects Firebase Functions with Corbado passkey flows. class CorbadoAuthFirebase { /// Constructor CorbadoAuthFirebase(); @@ -20,6 +21,7 @@ class CorbadoAuthFirebase { _corbadoService = CorbadoService(functions); } + /// Registers a new user with a passkey and returns a Firebase auth token. Future signUpWithPasskey({ required String email, String? fullName, @@ -38,6 +40,7 @@ class CorbadoAuthFirebase { } } + /// Adds an additional passkey to the already signed in user. Future appendPasskey(String firebaseToken) async { final ua = await userAgent(); final challenge = await _corbadoService.startPasskeyAppend( @@ -53,6 +56,7 @@ class CorbadoAuthFirebase { ); } + /// Cancels any passkey ceremony that is currently in progress. Future cancelAuthenticatorOperation() { return _authenticator.cancelCurrentAuthenticatorOperation(); } @@ -77,22 +81,28 @@ class CorbadoAuthFirebase { return _loginWithPasskey(email); } + /// Starts an email one-time-password login by sending a code to [email]. Future startLoginWithEmailOTP(String email) async { return _corbadoService.startLoginWithEmailOTP(email); } + /// Completes an email one-time-password login using the received [code] and + /// returns a Firebase auth token. Future finishLoginWithEmailOTP(String code) async { return _corbadoService.finishLoginWithEmailOTP(code); } + /// Returns all passkeys registered for the signed in user. Future> getPasskeys(String firebaseToken) async { return _corbadoService.getPasskeys(firebaseToken); } + /// Deletes the passkey identified by [passkeyId] for the signed in user. Future deletePasskey(String firebaseToken, String passkeyId) async { return _corbadoService.deletePasskey(firebaseToken, passkeyId); } + /// Deletes the signed in user and all of their associated passkeys. Future deleteUser(String firebaseToken) async { try { return await _corbadoService.deleteUser(firebaseToken); diff --git a/packages/corbado_auth_firebase/lib/src/exceptions.dart b/packages/corbado_auth_firebase/lib/src/exceptions.dart index 5f7cb75c..4d3c846d 100644 --- a/packages/corbado_auth_firebase/lib/src/exceptions.dart +++ b/packages/corbado_auth_firebase/lib/src/exceptions.dart @@ -1,11 +1,17 @@ import 'package:cloud_functions/cloud_functions.dart'; import 'package:flutter/material.dart'; +/// Thrown when the Firebase auth token provided to the backend is invalid. class InvalidAuthTokenException implements Exception {} +/// Thrown when the backend returns an error that cannot be mapped to a +/// more specific exception. class UnknownErrorException implements Exception { + /// Creates an [UnknownErrorException] with a human readable [message]. UnknownErrorException(this.message); + /// Builds an [UnknownErrorException] from a [FirebaseFunctionsException], + /// extracting its details as the message when possible. factory UnknownErrorException.fromFirebaseFunctionsException( FirebaseFunctionsException e, ) { @@ -18,5 +24,6 @@ class UnknownErrorException implements Exception { return UnknownErrorException(message); } + /// The error message describing what went wrong. final String message; } diff --git a/packages/corbado_auth_firebase/lib/src/services/corbado.dart b/packages/corbado_auth_firebase/lib/src/services/corbado.dart index 8cf73a18..929b96fe 100644 --- a/packages/corbado_auth_firebase/lib/src/services/corbado.dart +++ b/packages/corbado_auth_firebase/lib/src/services/corbado.dart @@ -1,3 +1,5 @@ +// ignore_for_file: prefer_constructors_over_static_methods + import 'dart:convert'; import 'package:cloud_functions/cloud_functions.dart'; @@ -5,7 +7,9 @@ import 'package:corbado_auth/corbado_auth.dart'; import 'package:corbado_auth_firebase/src/exceptions.dart'; import 'package:passkeys/types.dart'; +/// Wraps the Corbado Firebase Functions used for passkey and OTP flows. class CorbadoService { + /// Creates a [CorbadoService] backed by the given [functions] instance. CorbadoService(FirebaseFunctions functions) : _functions = functions; final FirebaseFunctions _functions; static final _functionOptions = HttpsCallableOptions( @@ -16,11 +20,14 @@ class CorbadoService { static CorbadoService? _instance; + /// Returns a lazily created singleton backed by the default Firebase + /// Functions instance. static CorbadoService getInstance() { _instance ??= CorbadoService(FirebaseFunctions.instance); return _instance!; } + /// Starts a passkey sign up and returns the registration challenge. Future startSignUpWithPasskey( String email, String userAgent, @@ -42,6 +49,7 @@ class CorbadoService { } } + /// Completes a passkey sign up and returns a Firebase auth token. Future finishSignUpWithPasskey( RegisterResponseType platformResponse, String userAgent, @@ -70,6 +78,7 @@ class CorbadoService { } } + /// Starts a passkey login and returns the authentication challenge. Future startLoginWithPasskey( String email, String userAgent, { @@ -94,6 +103,7 @@ class CorbadoService { } } + /// Completes a passkey login and returns a Firebase auth token. Future finishLoginWithPasskey( AuthenticateResponseType platformResponse, String userAgent, @@ -121,6 +131,7 @@ class CorbadoService { } } + /// Starts an email one-time-password login by sending a code to [email]. Future startLoginWithEmailOTP(String email) async { try { final startResponse = await _functions @@ -140,6 +151,8 @@ class CorbadoService { } } + /// Completes an email one-time-password login using [code] and returns a + /// Firebase auth token. Future finishLoginWithEmailOTP(String code) async { try { final finishResponse = await _functions @@ -157,6 +170,8 @@ class CorbadoService { } } + /// Starts appending a passkey to an existing user and returns the + /// registration challenge. Future startPasskeyAppend( String firebaseToken, String userAgent, @@ -181,6 +196,7 @@ class CorbadoService { } } + /// Completes appending a passkey and returns whether it succeeded. Future finishPasskeyAppend( String firebaseToken, RegisterResponseType platformResponse, @@ -211,6 +227,7 @@ class CorbadoService { } } + /// Returns all passkeys registered for the given user. Future> getPasskeys(String firebaseToken) async { try { final res = await _functions @@ -231,6 +248,7 @@ class CorbadoService { } } + /// Deletes the passkey identified by [passkeyId] for the given user. Future deletePasskey(String firebaseToken, String passkeyId) async { try { await _functions @@ -248,6 +266,7 @@ class CorbadoService { } } + /// Deletes the given user and all of their associated passkeys. Future deleteUser(String firebaseToken) async { try { await _functions diff --git a/packages/passkeys/passkeys/lib/authenticator.dart b/packages/passkeys/passkeys/lib/authenticator.dart index efba3a00..73cb691f 100644 --- a/packages/passkeys/passkeys/lib/authenticator.dart +++ b/packages/passkeys/passkeys/lib/authenticator.dart @@ -42,6 +42,7 @@ class PasskeyAuthenticator implements PasskeyAuthenticatorInterface { /// Creates a new passkey and stores it on the device. /// Returns [RegisterResponseType] which must be sent to the relying party /// server. + @override Future register(RegisterRequestType request) async { if (debugMode) { await _doctor.check(request.relyingParty.id); @@ -102,6 +103,7 @@ class PasskeyAuthenticator implements PasskeyAuthenticatorInterface { /// Authenticates a user with a passkey. /// Returns [AuthenticateResponseType] which must be sent to the relying party /// server. + @override Future authenticate( AuthenticateRequestType request, ) async {