diff --git a/packages/firebase_auth/firebase_auth_dart/lib/firebase_auth_dart.dart b/packages/firebase_auth/firebase_auth_dart/lib/firebase_auth_dart.dart index 49f5b0fd..73637de6 100644 --- a/packages/firebase_auth/firebase_auth_dart/lib/firebase_auth_dart.dart +++ b/packages/firebase_auth/firebase_auth_dart/lib/firebase_auth_dart.dart @@ -7,13 +7,13 @@ library firebase_auth_dart; import 'dart:async'; -import 'dart:convert'; import 'dart:developer'; import 'dart:io'; import 'package:firebase_core_dart/firebase_core_dart.dart'; import 'package:http/http.dart' as http; import 'package:meta/meta.dart'; +import 'package:storagebox/storagebox.dart'; import 'src/api/api.dart'; import 'src/api/errors.dart'; @@ -46,4 +46,3 @@ part 'src/user.dart'; part 'src/user_credential.dart'; part 'src/user_info.dart'; part 'src/user_metadata.dart'; -part 'src/utils/persistence.dart'; diff --git a/packages/firebase_auth/firebase_auth_dart/lib/src/api/api.dart b/packages/firebase_auth/firebase_auth_dart/lib/src/api/api.dart index 2c61f7ad..86a91060 100644 --- a/packages/firebase_auth/firebase_auth_dart/lib/src/api/api.dart +++ b/packages/firebase_auth/firebase_auth_dart/lib/src/api/api.dart @@ -38,7 +38,7 @@ part 'authentication/sms.dart'; part 'authentication/token.dart'; part 'emulator.dart'; -/// All API classes calling to IDP API must extend this template. +/// All API classes calling to Identity Toolkit API must extend this template. abstract class APIDelegate { /// Construct a new [APIDelegate]. const APIDelegate(this.api); @@ -46,7 +46,7 @@ abstract class APIDelegate { /// The [API] instance containing required configurations to make the requests. final API api; - /// Convert [DetailedApiRequestError] thrown by idp to [FirebaseAuthException]. + /// Convert [DetailedApiRequestError] thrown by Identity Toolkit to [FirebaseAuthException]. FirebaseAuthException makeAuthException(DetailedApiRequestError apiError) { try { final json = apiError.jsonResponse; @@ -83,7 +83,7 @@ abstract class APIDelegate { } } -/// Configurations necessary for making all idp requests. +/// Configurations necessary for making all Identity Toolkit requests. @protected class APIConfig { /// Construct [APIConfig]. @@ -133,7 +133,7 @@ abstract class SignInResponse { } } -/// A return type from Idp authentication requests, must be extended by any other response +/// A return type from Identity Toolkit authentication requests, must be extended by any other response /// type for any operation that requires idToken. @protected abstract class IdTokenResponse { diff --git a/packages/firebase_auth/firebase_auth_dart/lib/src/api/authentication/sms.dart b/packages/firebase_auth/firebase_auth_dart/lib/src/api/authentication/sms.dart index 68288a7e..539cc94b 100644 --- a/packages/firebase_auth/firebase_auth_dart/lib/src/api/authentication/sms.dart +++ b/packages/firebase_auth/firebase_auth_dart/lib/src/api/authentication/sms.dart @@ -3,7 +3,7 @@ part of api; /// A return type from Idp phone authentication requests. @internal class SignInWithPhoneNumberResponse extends SignInResponse { - /// Construct a new [IdTokenResponse]. + /// Construct a new [SignInWithPhoneNumberResponse]. SignInWithPhoneNumberResponse._({ required String idToken, required String refreshToken, diff --git a/packages/firebase_auth/firebase_auth_dart/lib/src/api/authentication/token.dart b/packages/firebase_auth/firebase_auth_dart/lib/src/api/authentication/token.dart index 34304b90..f6d9d45b 100644 --- a/packages/firebase_auth/firebase_auth_dart/lib/src/api/authentication/token.dart +++ b/packages/firebase_auth/firebase_auth_dart/lib/src/api/authentication/token.dart @@ -7,14 +7,20 @@ class IdToken extends APIDelegate { // ignore: public_member_api_docs IdToken(API api) : super(api); - /// Refresh a user ID token using the refreshToken, + /// Refresh a user's IdToken using a `refreshToken`, /// will refresh even if the token hasn't expired. /// + /// Common error codes: + /// - `TOKEN_EXPIRED`: The user's credential is no longer valid. The user must sign in again. + /// - `USER_DISABLED`: The user account has been disabled by an administrator. + /// - `USER_NOT_FOUND`: The user corresponding to the refresh token was not found. It is likely the user was deleted. + /// - `INVALID_REFRESH_TOKEN`: An invalid refresh token is provided. + /// - `INVALID_GRANT_TYPE`: the grant type specified is invalid. + /// - `MISSING_REFRESH_TOKEN`: no refresh token provided. + /// - API key not valid. Please pass a valid API key. (invalid API key provided) Future refreshIdToken(String? refreshToken) async { try { return await _exchangeRefreshWithIdToken(refreshToken); - } on HttpException catch (_) { - rethrow; } catch (_) { rethrow; } diff --git a/packages/firebase_auth/firebase_auth_dart/lib/src/firebase_auth.dart b/packages/firebase_auth/firebase_auth_dart/lib/src/firebase_auth.dart index 4df0f3b3..bfae069a 100644 --- a/packages/firebase_auth/firebase_auth_dart/lib/src/firebase_auth.dart +++ b/packages/firebase_auth/firebase_auth_dart/lib/src/firebase_auth.dart @@ -55,13 +55,15 @@ class FirebaseAuth { _api.client = client; } - StorageBox get _userStorage => - StorageBox.instanceOf(app.options.projectId); + StorageBox get _userStorage => StorageBox( + app.options.projectId, + configPathPrefix: '.firebase-auth', + ); Map? _localUser() { try { - return (_userStorage.getValue('${app.options.apiKey}:${app.name}') - as Map)['currentUser']; + return (_userStorage['${app.options.apiKey}:${app.name}'] + as Map?)?['currentUser']; } catch (e) { return null; } @@ -109,10 +111,11 @@ class FirebaseAuth { @protected void _updateCurrentUserAndEvents(User? user, [bool authStateChanged = false]) { - _userStorage.putValue( - '${app.options.apiKey}:${app.name}', - {'currentUser': user?.toMap()}, - ); + _userStorage.addAll({ + '${app.options.apiKey}:${app.name}': { + 'currentUser': user?.toMap(), + }, + }); _currentUser = user; diff --git a/packages/firebase_auth/firebase_auth_dart/lib/src/utils/persistence.dart b/packages/firebase_auth/firebase_auth_dart/lib/src/utils/persistence.dart deleted file mode 100644 index b47dc1bb..00000000 --- a/packages/firebase_auth/firebase_auth_dart/lib/src/utils/persistence.dart +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2021 Invertase Limited. All rights reserved. -// Use of this source code is governed by a BSD-style license -// that can be found in the LICENSE file. - -// ignore_for_file: require_trailing_commas - -part of firebase_auth_dart; - -/// A storage box is a container for key-value pairs of data -/// which exists in one box with specific name. -/// -/// To get or create a new box, first initialize an instance -/// with a name, then use the methods provided for that box, -/// if the box doesn't exist, it will be created, if it exists -/// data will be written to the existing one. -class StorageBox { - // ignore: public_member_api_docs - StorageBox._(this._name); - - /// Get a [StorageBox] instance for a given name. - static StorageBox instanceOf([String name = 'user']) { - if (!_instances.containsKey(name)) { - _instances.addAll({name: StorageBox._(name)}); - } - return _instances[name]!; - } - - static final Map _instances = {}; - - /// The name of the box which you want to create or get. - final String _name; - - File get _file { - /// `APPDATA` for windows, `HOME` for linux and mac - final _env = Platform.environment; - final _sep = Platform.pathSeparator; - - late String _home; - - if (Platform.isLinux || Platform.isMacOS) { - // ignore: cast_nullable_to_non_nullable - _home = _env['HOME'] as String; - } - - if (Platform.isWindows) { - // ignore: cast_nullable_to_non_nullable - _home = _env['APPDATA'] as String; - } - - final _path = '$_home$_sep.firebase-auth$_sep$_name.json'; - - return File(_path); - } - - /// Store the key-value pair in the box with [_name], if key already - /// exists the value will be overwritten. - void putValue(String key, T? value) { - if (!_file.existsSync()) { - _file.createSync(recursive: true); - } - final contentMap = _readFile(); - - if (value != null) { - contentMap[key] = value; - } else { - contentMap.remove(key); - } - - if (contentMap.isEmpty) { - _file.deleteSync(recursive: true); - } else { - _file.writeAsStringSync(jsonEncode(contentMap)); - } - } - - /// Get the value for a specific key, if no such key exists, or no such box with [_name] - /// [StorageBoxException] will be thrown. - T getValue(String key) { - try { - final contentText = _file.readAsStringSync(); - final Map content = jsonDecode(contentText); - - if (!content.containsKey(key)) { - throw StorageBoxException('Key $key does not exist.'); - } - - return content[key]; - } on FileSystemException { - throw StorageBoxException('Box $_name does not exist, ' - 'to create one, add some value using "putValue".'); - } - } - - Map _readFile() { - final contentText = _file.readAsStringSync(); - - if (contentText.isEmpty) { - return {}; - } - - final content = json.decode(contentText) as Map; - - return content; - } -} - -/// Throw when there's an error with [StorageBox] methods. -class StorageBoxException implements Exception { - // ignore: public_member_api_docs - StorageBoxException([this.message]); - - /// Message describing the error. - final String? message; -} diff --git a/packages/firebase_auth/firebase_auth_dart/pubspec.yaml b/packages/firebase_auth/firebase_auth_dart/pubspec.yaml index a2d8eb17..ef3981d5 100644 --- a/packages/firebase_auth/firebase_auth_dart/pubspec.yaml +++ b/packages/firebase_auth/firebase_auth_dart/pubspec.yaml @@ -13,6 +13,7 @@ dependencies: googleapis_auth: ^1.1.0 http: ^0.13.4 meta: ^1.3.0 + storagebox: ^0.1.0+2 dev_dependencies: async: ^2.8.1 diff --git a/packages/firebase_auth/firebase_auth_dart/test/firebase_auth_dart_test.dart b/packages/firebase_auth/firebase_auth_dart/test/firebase_auth_dart_test.dart index f5f283e9..66224858 100644 --- a/packages/firebase_auth/firebase_auth_dart/test/firebase_auth_dart_test.dart +++ b/packages/firebase_auth/firebase_auth_dart/test/firebase_auth_dart_test.dart @@ -178,35 +178,35 @@ void main() { }); }); }); - group('StorageBox ', () { - test('put a new value.', () { - final box = StorageBox.instanceOf('box'); - box.putValue('key', '123'); - - expect(box.getValue('key'), '123'); - }); - test('put a null value does not add the value.', () { - final box = StorageBox.instanceOf('box'); - box.putValue('key_2', null); - expect( - () => box.getValue('key_2'), - throwsA(isA()), - ); - }); - test('get a key that does not exist.', () { - final box = StorageBox.instanceOf('box'); - expect( - () => box.getValue('random_key'), - throwsA(isA()), - ); - }); - test('get a key from a box that does not exist.', () { - final box = StorageBox.instanceOf('box_'); - expect( - () => box.getValue('key'), - throwsA(isA()), - ); - }); - }); + // group('StorageBox ', () { + // test('put a new value.', () { + // final box = StorageBox.instanceOf('box'); + // box.putValue('key', '123'); + + // expect(box.getValue('key'), '123'); + // }); + // test('put a null value does not add the value.', () { + // final box = StorageBox.instanceOf('box'); + // box.putValue('key_2', null); + // expect( + // () => box.getValue('key_2'), + // throwsA(isA()), + // ); + // }); + // test('get a key that does not exist.', () { + // final box = StorageBox.instanceOf('box'); + // expect( + // () => box.getValue('random_key'), + // throwsA(isA()), + // ); + // }); + // test('get a key from a box that does not exist.', () { + // final box = StorageBox.instanceOf('box_'); + // expect( + // () => box.getValue('key'), + // throwsA(isA()), + // ); + // }); + // }); }); } diff --git a/packages/firebase_functions/firebase_functions_dart/pubspec.yaml b/packages/firebase_functions/firebase_functions_dart/pubspec.yaml index 850be83b..13a80565 100644 --- a/packages/firebase_functions/firebase_functions_dart/pubspec.yaml +++ b/packages/firebase_functions/firebase_functions_dart/pubspec.yaml @@ -13,6 +13,7 @@ dependencies: firebase_core_dart: ^0.1.1 http: ^0.13.4 meta: ^1.7.0 + storagebox: ^0.1.0+1 dev_dependencies: test: ^1.16.0 diff --git a/packages/firebase_functions/firebase_functions_dart/test/firebase_functions_integration_test.dart b/packages/firebase_functions/firebase_functions_dart/test/firebase_functions_integration_test.dart index 0621db19..0ca9c3b4 100644 --- a/packages/firebase_functions/firebase_functions_dart/test/firebase_functions_integration_test.dart +++ b/packages/firebase_functions/firebase_functions_dart/test/firebase_functions_integration_test.dart @@ -8,6 +8,7 @@ import 'package:firebase_auth_dart/firebase_auth_dart.dart'; import 'package:firebase_core_dart/firebase_core_dart.dart'; import 'package:firebase_functions_dart/firebase_functions_dart.dart'; import 'package:http/http.dart' as http; +import 'package:storagebox/storagebox.dart'; import 'package:test/test.dart'; import 'data.dart' as data; @@ -154,11 +155,11 @@ Future main() async { functions.useFunctionsEmulator('localhost', 5001); httpsCallable = functions.httpsCallable('testFunctionAuthorized'); }); - tearDown(() { + final config = StorageBox(app.options.projectId); + // Clear auth storage - StorageBox.instanceOf(app.options.projectId) - .putValue('${app.options.apiKey}:${app.name}', null); + config.remove('${app.options.apiKey}:${app.name}'); }); test('unauthorized access throws', () async { expect( @@ -167,7 +168,6 @@ Future main() async { .having((e) => e.code, 'code', contains('unauthenticated'))), ); }); - test('authorized access succeeds', () async { final auth = FirebaseAuth.instanceFor(app: app); await auth.useAuthEmulator(); diff --git a/packages/firebase_functions/firebase_functions_dart/test/firebase_functions_test.dart b/packages/firebase_functions/firebase_functions_dart/test/firebase_functions_test.dart index 74f5d4e2..e608d308 100644 --- a/packages/firebase_functions/firebase_functions_dart/test/firebase_functions_test.dart +++ b/packages/firebase_functions/firebase_functions_dart/test/firebase_functions_test.dart @@ -11,6 +11,7 @@ import 'package:firebase_core_dart/firebase_core_dart.dart'; import 'package:firebase_functions_dart/firebase_functions_dart.dart'; import 'package:http/http.dart' as http; import 'package:http/testing.dart'; +import 'package:storagebox/storagebox.dart'; import 'package:test/test.dart'; import 'data.dart' as data; @@ -379,9 +380,12 @@ Future main() async { options: firebaseOptions, name: 'auth_functions', ); + + // Clear auth storage + final config = StorageBox(app.options.projectId); + // Clear auth storage - StorageBox.instanceOf(app.options.projectId) - .putValue('${app.options.apiKey}:${app.name}', null); + config.remove('${app.options.apiKey}:${app.name}'); functions = FirebaseFunctions.instanceFor(app: app); functions.setApiClient(MockClient(_authCheck)); httpsCallable = functions.httpsCallable('testFunctionAuthorized'); @@ -389,8 +393,10 @@ Future main() async { tearDown(() async { // Clear auth storage - StorageBox.instanceOf(app.options.projectId) - .putValue('${app.options.apiKey}:${app.name}', null); + final config = StorageBox(app.options.projectId); + + // Clear auth storage + config.remove('${app.options.apiKey}:${app.name}'); }); test('unauthorized access throws', () async {