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

feat: Adds support for authenticating via service account #152

Merged
Merged
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
22 changes: 22 additions & 0 deletions packages/flutterfire_cli/lib/src/commands/config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,21 @@ class ConfigCommand extends FlutterFireCommand {
'If no package name is provided then an attempt will be made to '
'automatically pick the first available web app id from remote.',
);

argParser.addOption(
kTokenFlag,
valueHelp: 'firebaseToken',
abbr: 't',
help: 'The token generated by running `firebase login:ci`',
);

argParser.addOption(
kServiceAccountFlag,
valueHelp: 'serviceAccount',
help:
'The path to a Google service account JSON file, used for authentication',
);

argParser.addFlag(
kAppleGradlePluginFlag,
defaultsTo: true,
Expand Down Expand Up @@ -311,6 +320,11 @@ class ConfigCommand extends FlutterFireCommand {
return value;
}

String? get serviceAccount {
final value = argResults!['service-account'] as String?;
return value;
}

String get outputFilePath {
return argResults!['out'] as String;
}
Expand Down Expand Up @@ -356,6 +370,7 @@ class ConfigCommand extends FlutterFireCommand {
projectId: newProjectId,
account: accountEmail,
token: token,
serviceAccount: serviceAccount,
);
creatingProjectSpinner.done();
return newProject;
Expand Down Expand Up @@ -385,12 +400,18 @@ class ConfigCommand extends FlutterFireCommand {
return baseMessage;
},
);
firebaseProjects = await firebase.getProjects(
account: accountEmail,
token: token,
serviceAccount: serviceAccount,
);

try {
firebaseProjects = await firebase
.getProjects(
account: accountEmail,
token: token,
serviceAccount: serviceAccount,
)
.timeout(const Duration(seconds: 15));

Expand Down Expand Up @@ -586,6 +607,7 @@ class ConfigCommand extends FlutterFireCommand {
iosBundleId: iosBundleId,
macosBundleId: macosBundleId,
token: token,
serviceAccount: serviceAccount,
webAppId: webAppId,
android: selectedPlatforms[kAndroid]!,
ios: selectedPlatforms[kIos]!,
Expand Down
1 change: 1 addition & 0 deletions packages/flutterfire_cli/lib/src/common/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ const String kAndroidAppIdFlag = 'android-app-id';
const String kAndroidPackageNameFlag = 'android-package-name';
const String kWebAppIdFlag = 'web-app-id';
const String kTokenFlag = 'token';
const String kServiceAccountFlag = 'service-account';
const String kAppleGradlePluginFlag = 'apply-gradle-plugins';
const String kIosBuildConfigFlag = 'ios-build-config';
const String kMacosBuildConfigFlag = 'macos-build-config';
Expand Down
24 changes: 24 additions & 0 deletions packages/flutterfire_cli/lib/src/firebase.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ Future<Map<String, dynamic>> runFirebaseCommand(
List<String> commandAndArgs, {
String? project,
String? account,
String? serviceAccount,
}) async {
final cliExists = await exists();
if (!cliExists) {
Expand All @@ -89,6 +90,10 @@ Future<Map<String, dynamic>> runFirebaseCommand(
'firebase',
execArgs,
workingDirectory: workingDirectoryPath,
environment: {
if (serviceAccount != null)
'GOOGLE_APPLICATION_CREDENTIALS': serviceAccount,
},
runInShell: true,
);

Expand All @@ -112,13 +117,15 @@ Future<Map<String, dynamic>> runFirebaseCommand(
Future<List<FirebaseProject>> getProjects({
String? account,
String? token,
String? serviceAccount,
}) async {
final response = await runFirebaseCommand(
[
'projects:list',
if (token != null) '--token=$token',
],
account: account,
serviceAccount: serviceAccount,
);
final result = List<Map<String, dynamic>>.from(response['result'] as List);
return result
Expand All @@ -136,6 +143,7 @@ Future<FirebaseProject> createProject({
String? displayName,
String? account,
String? token,
String? serviceAccount,
}) async {
final response = await runFirebaseCommand(
[
Expand All @@ -145,6 +153,7 @@ Future<FirebaseProject> createProject({
if (token != null) '--token=$token',
],
account: account,
serviceAccount: serviceAccount,
);
final result = Map<String, dynamic>.from(response['result'] as Map);
return FirebaseProject.fromJson(<String, dynamic>{
Expand All @@ -159,6 +168,7 @@ Future<List<FirebaseApp>> getApps({
String? account,
String? platform,
String? token,
String? serviceAccount,
}) async {
if (platform != null) _assertFirebaseSupportedPlatform(platform);
final response = await runFirebaseCommand(
Expand All @@ -169,6 +179,7 @@ Future<List<FirebaseApp>> getApps({
],
project: project,
account: account,
serviceAccount: serviceAccount,
);
final result = List<Map<String, dynamic>>.from(response['result'] as List);
return result
Expand All @@ -194,6 +205,7 @@ Future<FirebaseAppSdkConfig> getAppSdkConfig({
required String platform,
String? account,
String? token,
String? serviceAccount,
}) async {
final platformFirebase = platform == kMacos ? kIos : platform;
_assertFirebaseSupportedPlatform(platformFirebase);
Expand All @@ -205,6 +217,7 @@ Future<FirebaseAppSdkConfig> getAppSdkConfig({
if (token != null) '--token=$token',
],
account: account,
serviceAccount: serviceAccount,
);
final result = Map<String, dynamic>.from(response['result'] as Map);
final fileContents = result['fileContents'] as String;
Expand All @@ -228,6 +241,7 @@ Future<FirebaseApp> findOrCreateFirebaseApp({
String? packageNameOrBundleIdentifier,
String? account,
String? token,
String? serviceAccount,
String? webAppId,
}) async {
var foundFirebaseApp = false;
Expand Down Expand Up @@ -262,6 +276,7 @@ Future<FirebaseApp> findOrCreateFirebaseApp({
account: account,
platform: platformFirebase,
token: token,
serviceAccount: serviceAccount,
);
var filteredFirebaseApps = unfilteredFirebaseApps.where(
(firebaseApp) {
Expand Down Expand Up @@ -306,6 +321,7 @@ Future<FirebaseApp> findOrCreateFirebaseApp({
packageName: packageNameOrBundleIdentifier!,
account: account,
token: token,
serviceAccount: serviceAccount,
);
break;
case kIos:
Expand All @@ -315,6 +331,7 @@ Future<FirebaseApp> findOrCreateFirebaseApp({
bundleId: packageNameOrBundleIdentifier!,
account: account,
token: token,
serviceAccount: serviceAccount,
);
break;
case kWeb:
Expand All @@ -323,6 +340,7 @@ Future<FirebaseApp> findOrCreateFirebaseApp({
displayName: displayNameWithPlatform,
account: account,
token: token,
serviceAccount: serviceAccount,
);
break;
default:
Expand Down Expand Up @@ -352,11 +370,13 @@ Future<FirebaseApp> createWebApp({
required String displayName,
String? account,
String? token,
String? serviceAccount,
}) async {
final response = await runFirebaseCommand(
['apps:create', 'web', displayName, if (token != null) '--token=$token'],
project: project,
account: account,
serviceAccount: serviceAccount,
);
final result = Map<String, dynamic>.from(response['result'] as Map);
return FirebaseApp.fromJson(<String, dynamic>{
Expand All @@ -372,6 +392,7 @@ Future<FirebaseApp> createAndroidApp({
required String packageName,
String? account,
String? token,
String? serviceAccount,
}) async {
final response = await runFirebaseCommand(
[
Expand All @@ -383,6 +404,7 @@ Future<FirebaseApp> createAndroidApp({
],
project: project,
account: account,
serviceAccount: serviceAccount,
);
final result = Map<String, dynamic>.from(response['result'] as Map);
return FirebaseApp.fromJson(<String, dynamic>{
Expand All @@ -398,6 +420,7 @@ Future<FirebaseApp> createAppleApp({
required String bundleId,
String? account,
String? token,
String? serviceAccount,
}) async {
final response = await runFirebaseCommand(
[
Expand All @@ -409,6 +432,7 @@ Future<FirebaseApp> createAppleApp({
],
project: project,
account: account,
serviceAccount: serviceAccount,
);
final result = Map<String, dynamic>.from(response['result'] as Map);
return FirebaseApp.fromJson(<String, dynamic>{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ extension FirebaseAndroidOptions on FirebaseOptions {
required String firebaseProjectId,
String? firebaseAccount,
required String? token,
required String? serviceAccount,
}) async {
var selectedAndroidApplicationId =
androidApplicationId ?? flutterApp.androidApplicationId;
Expand All @@ -52,12 +53,14 @@ extension FirebaseAndroidOptions on FirebaseOptions {
project: firebaseProjectId,
account: firebaseAccount,
token: token,
serviceAccount: serviceAccount,
);
final appSdkConfig = await firebase.getAppSdkConfig(
appId: firebaseApp.appId,
platform: kAndroid,
account: firebaseAccount,
token: token,
serviceAccount: serviceAccount,
);

return convertConfigToOptions(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ extension FirebaseAppleOptions on FirebaseOptions {
required String firebaseProjectId,
String? firebaseAccount,
required String? token,
required String? serviceAccount,
}) async {
final platformIdentifier = macos ? kMacos : kIos;
var selectedAppleBundleId = appleBundleIdentifier ??
Expand All @@ -51,12 +52,14 @@ extension FirebaseAppleOptions on FirebaseOptions {
project: firebaseProjectId,
account: firebaseAccount,
token: token,
serviceAccount: serviceAccount,
);
final appSdkConfig = await firebase.getAppSdkConfig(
appId: firebaseApp.appId,
platform: platformIdentifier,
account: firebaseAccount,
token: token,
serviceAccount: serviceAccount,
);

return convertConfigToOptions(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,23 @@ extension FirebaseDartOptions on FirebaseOptions {
String? webAppId,
String platform = kWeb,
required String? token,
required String? serviceAccount,
}) async {
final firebaseApp = await firebase.findOrCreateFirebaseApp(
displayName: flutterApp.package.pubSpec.name ?? 'flutterfire_app',
platform: platform,
project: firebaseProjectId,
account: firebaseAccount,
token: token,
serviceAccount: serviceAccount,
webAppId: webAppId,
);
final appSdkConfig = await firebase.getAppSdkConfig(
appId: firebaseApp.appId,
platform: kWeb,
account: firebaseAccount,
token: token,
serviceAccount: serviceAccount,
);

return convertConfigToOptions(appSdkConfig, firebaseProjectId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Future<FirebasePlatformOptions> fetchAllFirebaseOptions({
String? iosBundleId,
String? macosBundleId,
String? token,
String? serviceAccount,
}) async {
FirebaseOptions? androidOptions;
FirebaseOptions? iosOptions;
Expand All @@ -53,6 +54,7 @@ Future<FirebasePlatformOptions> fetchAllFirebaseOptions({
firebaseProjectId: firebaseProjectId,
firebaseAccount: firebaseAccount,
token: token,
serviceAccount: serviceAccount,
);
}

Expand All @@ -63,6 +65,7 @@ Future<FirebasePlatformOptions> fetchAllFirebaseOptions({
firebaseProjectId: firebaseProjectId,
firebaseAccount: firebaseAccount,
token: token,
serviceAccount: serviceAccount,
);
}
if (macos) {
Expand All @@ -73,6 +76,7 @@ Future<FirebasePlatformOptions> fetchAllFirebaseOptions({
firebaseAccount: firebaseAccount,
macos: true,
token: token,
serviceAccount: serviceAccount,
);
}

Expand All @@ -83,6 +87,7 @@ Future<FirebasePlatformOptions> fetchAllFirebaseOptions({
firebaseAccount: firebaseAccount,
webAppId: webAppId,
token: token,
serviceAccount: serviceAccount,
);
}

Expand All @@ -93,6 +98,7 @@ Future<FirebasePlatformOptions> fetchAllFirebaseOptions({
firebaseAccount: firebaseAccount,
platform: kWindows,
token: token,
serviceAccount: serviceAccount,
);
}

Expand All @@ -103,6 +109,7 @@ Future<FirebasePlatformOptions> fetchAllFirebaseOptions({
firebaseAccount: firebaseAccount,
platform: kLinux,
token: token,
serviceAccount: serviceAccount,
);
}

Expand Down
Loading