Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: add customAttributes to edit account request #13

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ build/
# Directory created by dartdoc
doc/api/

.idea/
*.iml
15 changes: 1 addition & 14 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -1,14 +1 @@
# Defines a default set of lint rules enforced for
# projects at Google. For details and rationale,
# see https://github.com/dart-lang/pedantic#enabled-lints.
include: package:pedantic/analysis_options.yaml

# For lint rules and documentation, see http://dart-lang.github.io/linter/lints.
# Uncomment to specify additional rules.
# linter:
# rules:
# - camel_case_types

analyzer:
# exclude:
# - path/to/excluded/files/**
include: package:lints/recommended.yaml
1 change: 0 additions & 1 deletion example/main.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'package:firebase_admin/firebase_admin.dart';
import 'package:firebase_admin/src/credential.dart';

void main() async {
// applicationDefault() will look for credentials in the following locations:
Expand Down
3 changes: 0 additions & 3 deletions lib/src/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ import 'package:firebase_admin/src/storage.dart';
import '../firebase_admin.dart';
import 'app/app.dart';
import 'database.dart';
import 'utils/error.dart';
import 'service.dart';
import 'auth.dart';
import 'credential.dart';

/// Represents initialized Firebase application and provides access to the
/// app's services.
Expand Down
6 changes: 3 additions & 3 deletions lib/src/app/app.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import 'dart:async';

import 'package:clock/clock.dart';
import 'package:firebase_admin/src/utils/error.dart';

import '../credential.dart';
import 'package:clock/clock.dart';

class FirebaseAppInternals {
final Credential credential;
Expand Down Expand Up @@ -55,9 +55,9 @@ class FirebaseAppInternals {
hasAccessTokenChanged ||
hasExpirationChanged) {
_cachedToken = token;
_tokenListeners.forEach((listener) {
for (var listener in _tokenListeners) {
listener(token.accessToken);
});
}
}

var expiresIn = token.expirationTime.difference(clock.now());
Expand Down
1 change: 0 additions & 1 deletion lib/src/app/app_extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import 'dart:io';
import 'package:firebase_admin/src/auth/credential.dart';

import '../../firebase_admin.dart';
import '../credential.dart';

extension GetProjectIdExtension on App {
String get projectId => _getProjectId(this);
Expand Down
13 changes: 11 additions & 2 deletions lib/src/auth.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import 'package:firebase_admin/src/auth/token_generator.dart';
import 'package:firebase_admin/src/auth/token_verifier.dart';
import 'package:openid_client/openid_client.dart';

import 'app.dart';
import 'auth/auth_api_request.dart';
import 'auth/user_record.dart';
import 'service.dart';

export 'auth/user_record.dart';

/// The Firebase Auth service interface.
class Auth implements FirebaseService {
@override
Expand Down Expand Up @@ -35,6 +35,15 @@ class Auth implements FirebaseService {
return UserRecord.fromJson(response['users'][0]);
}

/// Gets the user data for the users corresponding to the given [uids].
Future<List<UserRecord>> getUsers(List<String> uids) async {
var response = await _authRequestHandler.getAccountInfoByUids(uids);
// Returns the user record populated with server response.
return (response['users'] as List)
.map((u) => UserRecord.fromJson(u))
.toList();
}

/// Looks up the user identified by the provided email and returns a future
/// that is fulfilled with a user record for the given user if that user is
/// found.
Expand Down
24 changes: 17 additions & 7 deletions lib/src/auth/auth_api_request.dart
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import 'dart:convert';

import 'package:clock/clock.dart';
import 'package:collection/collection.dart';
import 'package:http/http.dart';

import '../auth.dart';
import '../app.dart';
import '../app/app_extension.dart';
import '../auth.dart';
import '../utils/api_request.dart';
import '../utils/error.dart';

import '../app.dart';
import 'action_code_settings.dart';
import '../utils/validator.dart' as validator;
import 'package:http/http.dart';

import 'package:collection/collection.dart';
import 'action_code_settings.dart';

class ApiClient {
final Client httpClient;
Expand Down Expand Up @@ -67,6 +65,7 @@ class ApiClient {
class AuthRequestHandler {
final ApiClient apiClient;

// ignore: prefer_function_declarations_over_variables
static AuthRequestHandler Function(App app) factory =
(app) => AuthRequestHandler._(app);

Expand All @@ -87,6 +86,16 @@ class AuthRequestHandler {
});
}

/// Looks up users by their uids.
Future<Map<String, dynamic>> getAccountInfoByUids(List<String> uids) async {
if (uids.any((uid) => !validator.isUid(uid))) {
throw FirebaseAuthError.invalidUid();
}
return _getAccountInfo({
'localId': uids,
});
}

/// Looks up a user by email.
Future<Map<String, dynamic>> getAccountInfoByEmail(String email) async {
if (!validator.isEmail(email)) {
Expand Down Expand Up @@ -474,6 +483,7 @@ class CreateEditAccountRequest {
// will be passed.
// Currently this applies to phone provider only.
if (phoneNumber == '') 'deleteProvider': ['phone'],
if (customAttributes != null) 'customAttributes': customAttributes,
if (validSince != null)
'validSince': validSince!.millisecondsSinceEpoch ~/ 1000
};
Expand Down
13 changes: 7 additions & 6 deletions lib/src/auth/credential.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import 'dart:async';
import 'dart:io';
import 'dart:convert';
import 'package:x509/x509.dart';
import '../utils/error.dart';
import 'dart:io';

import 'package:clock/clock.dart';
import 'package:http/http.dart' as http;
import 'package:jose/jose.dart';
import 'package:crypto_keys/crypto_keys.dart';
import '../credential.dart';
import 'package:clock/clock.dart';
import 'package:openid_client/openid_client.dart' as openid;
import 'package:x509/x509.dart';

import '../credential.dart';
import '../utils/error.dart';

/// Contains the properties necessary to use service-account JSON credentials.
class Certificate {
Expand Down
1 change: 1 addition & 0 deletions lib/src/auth/token_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import '../utils/validator.dart' as validator;
class FirebaseTokenGenerator {
final App app;

// ignore: prefer_function_declarations_over_variables
static FirebaseTokenGenerator Function(App app) factory =
(app) => FirebaseTokenGenerator(app);

Expand Down
3 changes: 2 additions & 1 deletion lib/src/auth/token_verifier.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import 'package:meta/meta.dart';
import 'package:openid_client/openid_client.dart';

import '../../firebase_admin.dart';
import '../app/app_extension.dart';
import 'package:meta/meta.dart';
import '../utils/validator.dart' as validator;

/// Class for verifying general purpose Firebase JWTs.
Expand All @@ -14,6 +14,7 @@ class FirebaseTokenVerifier {

final String _jwtName = 'ID token';

// ignore: prefer_function_declarations_over_variables
static FirebaseTokenVerifier Function(App app) factory =
(app) => FirebaseTokenVerifier(app);

Expand Down
6 changes: 3 additions & 3 deletions lib/src/auth/user_record.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ class UserMetadata {
? null
: DateTime.fromMillisecondsSinceEpoch(
int.parse(map['createdAt'])),
lastSignInTime: map['lastSignInTime'] == null
lastSignInTime: map['lastLoginAt'] == null
? null
: DateTime.fromMillisecondsSinceEpoch(
int.parse(map['lastSignInTime'])));
int.parse(map['lastLoginAt'])));

Map<String, dynamic> toJson() {
return {
'lastSignInTime': lastSignInTime?.toIso8601String(),
'lastLoginAt': lastSignInTime?.toIso8601String(),
'creationTime': creationTime?.toIso8601String(),
};
}
Expand Down
16 changes: 6 additions & 10 deletions lib/src/database.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import 'dart:async';

import 'package:firebase_admin/src/service.dart';
import 'package:firebase_dart/standalone_database.dart';

import '../firebase_admin.dart';
import 'app.dart';
import 'app/app.dart';
import 'app/app_extension.dart';
import 'app.dart';

import 'package:firebase_dart/standalone_database.dart';

class _AuthTokenProvider implements AuthTokenProvider {
final FirebaseAppInternals internals;
Expand All @@ -22,13 +20,11 @@ class _AuthTokenProvider implements AuthTokenProvider {
}

@override
Stream<String?> get onTokenChanged {
var controller = StreamController<String?>();
var listener = (v) => controller.add(v);
Stream<Future<String>?> get onTokenChanged {
var controller = StreamController<Future<String>?>();
listener(String v) => controller.add(Future.value(v));

controller.onListen = () {
internals.addAuthTokenListener(listener);
};
controller.onListen = () => internals.addAuthTokenListener(listener);
controller.onCancel = () => internals.removeAuthTokenListener(listener);

return controller.stream;
Expand Down
3 changes: 1 addition & 2 deletions lib/src/storage.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import 'package:firebase_admin/firebase_admin.dart';
import 'package:firebase_admin/src/service.dart';
import 'package:firebase_admin/src/utils/api_request.dart';
import 'package:gcloud/storage.dart' as gcloud;

import 'package:firebase_admin/src/app.dart';
import 'package:firebase_admin/src/service.dart';
import 'app/app_extension.dart';

/// Storage service bound to the provided app.
Expand Down
6 changes: 3 additions & 3 deletions lib/src/testing.dart
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import 'dart:convert';

import 'package:clock/clock.dart';
import 'package:firebase_admin/src/auth/credential.dart';
import 'package:firebase_admin/src/auth/token_verifier.dart';
import 'package:firebase_admin/src/credential.dart';
import 'package:firebase_admin/firebase_admin.dart';
import 'package:firebase_admin/src/app.dart';
import 'package:firebase_admin/src/auth/credential.dart';
import 'package:firebase_admin/src/auth/token_verifier.dart';
import 'package:jose/jose.dart';
import 'package:openid_client/openid_client.dart' hide Credential;

class ServiceAccountMockCredential extends ServiceAccountCredential
with MockCredentialMixin {
@override
// ignore: prefer_function_declarations_over_variables
late final AccessToken Function() tokenFactory = () {
return MockAccessToken.fromJson({
'access_token': (JsonWebSignatureBuilder()
Expand Down
3 changes: 0 additions & 3 deletions lib/src/utils/api_request.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@


import 'package:firebase_admin/firebase_admin.dart';
import 'package:http/http.dart';

import '../app.dart';
Expand Down
4 changes: 3 additions & 1 deletion lib/src/utils/error.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// ignore_for_file: non_constant_identifier_names

import 'dart:convert';

/// Base class for all Firebase exceptions.
Expand Down Expand Up @@ -69,7 +71,7 @@ class FirebaseAuthError extends _PrefixedFirebaseError {
// serverErrorCode could contain additional details:
// ERROR_CODE : Detailed message which can also contain colons
final colonSeparator = serverErrorCode.indexOf(':');
var customMessage;
String? customMessage;
if (colonSeparator != -1) {
customMessage = serverErrorCode.substring(colonSeparator + 1).trim();
serverErrorCode = serverErrorCode.substring(0, colonSeparator).trim();
Expand Down
5 changes: 3 additions & 2 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,17 @@ dependencies:
jose: ^0.3.2
dotenv: ^3.0.0
openid_client: ^0.4.3
firebase_dart: ^1.0.0-dev.49
firebase_dart: ^1.0.9
path: ^1.8.0
meta: ^1.4.0
http: ^0.13.0
crypto_keys: ^0.3.0
collection: ^1.15.0
gcloud: ^0.8.0
googleapis: '>=8.0.0 <12.0.0'

dev_dependencies:
test: ^1.17.8
fake_async: ^1.2.0
pedantic: ^1.11.1
lints: ^1.0.1
mockito: ^5.0.10
17 changes: 7 additions & 10 deletions test/app_test.dart
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
import 'dart:async';
import 'dart:io';

import 'package:clock/clock.dart';
import 'package:dotenv/dotenv.dart';
import 'package:fake_async/fake_async.dart';
import 'package:firebase_admin/firebase_admin.dart';
import 'package:firebase_admin/src/app.dart';
import 'package:firebase_admin/src/auth/credential.dart';
import 'package:firebase_admin/src/credential.dart';
import 'package:firebase_admin/src/service.dart';
import 'package:firebase_admin/src/testing.dart';
import 'package:test/test.dart';

import 'package:firebase_admin/firebase_admin.dart';
import 'package:firebase_admin/src/service.dart';
import 'dart:async';
import 'resources/mocks.dart' as mocks;
import 'package:fake_async/fake_async.dart';
import 'package:dotenv/dotenv.dart';

import 'resources/mocks.dart';
import 'package:firebase_admin/src/app.dart';

Matcher throwsAppError([String? message]) =>
throwsA(TypeMatcher<FirebaseAppError>()
Expand Down Expand Up @@ -586,7 +583,7 @@ void main() {

group('App.internals.addAuthTokenListener()', () {
test('is notified when the token changes', () async {
var calledWithValue;
String? calledWithValue;
mockApp.internals.addAuthTokenListener(expectAsync1((v) {
calledWithValue = v;
}, count: 1));
Expand Down
6 changes: 2 additions & 4 deletions test/auth_test.dart
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import 'dart:convert';
import 'dart:io';

import 'package:firebase_admin/firebase_admin.dart';
import 'package:firebase_admin/src/auth/auth_api_request.dart';
import 'package:firebase_admin/src/auth/user_record.dart';
import 'package:firebase_admin/testing.dart';
import 'package:jose/jose.dart';
import 'package:mockito/mockito.dart';
import 'package:openid_client/openid_client.dart';
import 'package:test/test.dart';
import 'resources/mocks.dart' as mocks;
import 'package:mockito/mockito.dart';

import 'resources/mocks.dart' as mocks;
import 'resources/mocks.dart';

Matcher throwsFirebaseError([String? code]) => throwsA(
Expand Down
1 change: 0 additions & 1 deletion test/resources/mocks.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'package:firebase_admin/src/auth/credential.dart';
import 'package:firebase_admin/src/testing.dart';
import 'package:firebase_admin/testing.dart';
import 'package:firebase_admin/src/app.dart';

var projectId = 'project_id';

Expand Down