Skip to content
13 changes: 13 additions & 0 deletions src/auth/credential.ts
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,19 @@ export class ApplicationDefaultCredential implements FirebaseCredential {
}
}

export class DatabaseEmulatorCredential implements FirebaseCredential {
public getAccessToken(): Promise<GoogleOAuthAccessToken> {
return Promise.resolve({
expires_in: 1000000,
access_token: 'owner',
});
}

public getCertificate(): Certificate {
return null;
}
}

function credentialFromFile(filePath: string, httpAgent?: Agent): Credential {
const credentialsFile = readCredentialFile(filePath);
if (typeof credentialsFile !== 'object') {
Expand Down
37 changes: 35 additions & 2 deletions src/firebase-namespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
Credential,
CertCredential,
RefreshTokenCredential,
DatabaseEmulatorCredential,
ApplicationDefaultCredential,
} from './auth/credential';

Expand All @@ -46,6 +47,24 @@ const DEFAULT_APP_NAME = '[DEFAULT]';
*/
export const FIREBASE_CONFIG_VAR: string = 'FIREBASE_CONFIG';

/**
* Constant holding the fully-qualified domain URI for a database emulator
* instance. If specified, the contents of this variable will be used to
* set `databaseURL` in FirebaseAppOptions. The varaible should be a complete
* URI specifying a transfer protocol, hostname, and port number:
*
* FIREBASE_DATABASE_EMULATOR_HOST=http://localhost:9000
*
*
* If a `projectId` is specified in FirebaseAppOptions, the database url will
* include the `ns=${projectId}` query parameter to identify the appropriate
* namespace within the emulator. The final `databaseURL` for a firebase project
* called "test" would be:
*
* http://localhost:9000?ns=test
*/
const FIREBASE_DATABASE_EMULATOR_HOST_VAR: string = 'FIREBASE_DATABASE_EMULATOR_HOST';


let globalAppDefaultCred: ApplicationDefaultCredential;
const globalCertCreds: { [key: string]: CertCredential } = {};
Expand Down Expand Up @@ -84,7 +103,9 @@ export class FirebaseNamespaceInternals {
public initializeApp(options?: FirebaseAppOptions, appName = DEFAULT_APP_NAME): FirebaseApp {
if (typeof options === 'undefined') {
options = this.loadOptionsFromEnvVar();
options.credential = new ApplicationDefaultCredential();
if (!('credential' in options)) {
options.credential = new ApplicationDefaultCredential();
}
}
if (typeof appName !== 'string' || appName === '') {
throw new FirebaseAppError(
Expand Down Expand Up @@ -253,12 +274,24 @@ export class FirebaseNamespaceInternals {
*/
private loadOptionsFromEnvVar(): FirebaseAppOptions {
const config = process.env[FIREBASE_CONFIG_VAR];
const dbEmulatorHost = process.env[FIREBASE_DATABASE_EMULATOR_HOST_VAR];
if (!validator.isNonEmptyString(config)) {
if (validator.isNonEmptyString(dbEmulatorHost)) {
return {
credential: new DatabaseEmulatorCredential(),
databaseURL: dbEmulatorHost,
};
}
return {};
}
try {
const contents = config.startsWith('{') ? config : fs.readFileSync(config, 'utf8');
return JSON.parse(contents) as FirebaseAppOptions;
const options = JSON.parse(contents) as FirebaseAppOptions;
if (validator.isNonEmptyString(dbEmulatorHost)) {
options.credential = new DatabaseEmulatorCredential();
options.databaseURL = `${dbEmulatorHost}` + (('projectId' in options) ? `?ns=${options.projectId}` : ``);
}
return options;
} catch (error) {
// Throw a nicely formed error message if the file contents cannot be parsed
throw new FirebaseAppError(
Expand Down