Permalink
Switch branches/tags
v4.5.1 v4.5.0 v4.4.0 v4.3.1 v4.3.0 v4.2.0 v4.1.5 v4.1.4 v4.1.3 v4.1.2 v4.1.1 v4.1.0 v4.1.0-rc.1 v4.0.0 rxfire@3.0.10 rxfire@3.0.9 rxfire@3.0.8 rxfire@3.0.7 rxfire@3.0.6 rxfire@3.0.5 rxfire@3.0.4 rxfire@3.0.3 rxfire@3.0.2 rxfire@3.0.1 rxfire@3.0.0 rxfire@2.0.0 firebase@5.5.8 firebase@5.5.7 firebase@5.5.6 firebase@5.5.5 firebase@5.5.4 firebase@5.5.3 firebase@5.5.2 firebase@5.5.1 firebase@5.5.0 firebase@5.4.2 firebase@5.4.1 firebase@5.4.0 firebase@5.3.1 firebase@5.3.0 firebase@5.2.0 firebase@5.1.0 firebase@5.0.4 firebase@5.0.3 firebase@5.0.2 firebase@5.0.1 firebase@5.0.0 firebase@4.13.1 firebase@4.13.0 firebase@4.12.1 firebase@4.12.0 firebase@4.11.0 firebase@4.10.1 firebase@4.10.0 firebase@4.9.1 firebase@4.9.0 firebase@4.9.0-2 firebase@4.9.0-1 firebase@4.9.0-0 firebase@4.8.2 firebase@4.8.2-0 firebase@4.8.1 firebase@4.8.0 firebase@4.7.0 firebase@4.6.2 firebase@4.6.1 firebase@4.6.0 firebase@4.5.2 @firebase/webchannel-wrapper@0.2.11 @firebase/webchannel-wrapper@0.2.10 @firebase/webchannel-wrapper@0.2.9 @firebase/webchannel-wrapper@0.2.8 @firebase/webchannel-wrapper@0.2.7 @firebase/webchannel-wrapper@0.2.6 @firebase/webchannel-wrapper@0.2.6-0 @firebase/webchannel-wrapper@0.2.5 @firebase/webchannel-wrapper@0.2.4 @firebase/webchannel-wrapper@0.2.3 @firebase/util@0.2.2 @firebase/util@0.2.1 @firebase/util@0.2.0 @firebase/util@0.1.11 @firebase/util@0.1.10 @firebase/util@0.1.9 @firebase/util@0.1.8 @firebase/util@0.1.7 @firebase/util@0.1.6 @firebase/util@0.1.6-0 @firebase/util@0.1.5 @firebase/util@0.1.4 @firebase/util@0.1.3 @firebase/util@0.1.2 @firebase/util@0.1.1 @firebase/testing@0.3.2 @firebase/testing@0.3.1 @firebase/testing@0.3.0 @firebase/storage@0.2.4 @firebase/storage@0.2.3 @firebase/storage@0.2.2 @firebase/storage@0.2.1
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
233 lines (214 sloc) 6.79 KB
/**
* Copyright 2018 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as firebase from 'firebase';
import * as request from 'request';
import { base64 } from '@firebase/util';
import { setLogLevel, LogLevel } from '@firebase/logger';
import * as grpc from 'grpc';
import { resolve } from 'path';
import * as fs from 'fs';
export { database, firestore } from 'firebase';
const PROTO_ROOT = {
root: resolve(
__dirname,
process.env.FIRESTORE_EMULATOR_PROTO_ROOT || '../protos'
),
file: 'google/firestore/emulator/v1/firestore_emulator.proto'
};
const PROTOS = grpc.load(PROTO_ROOT, /* format = */ 'proto');
const EMULATOR = PROTOS['google']['firestore']['emulator']['v1'];
/** If this environment variable is set, use it for the database emulator's address. */
const DATABASE_ADDRESS_ENV: string = 'FIREBASE_DATABASE_EMULATOR_ADDRESS';
/** The default address for the local database emulator. */
const DATABASE_ADDRESS_DEFAULT: string = 'localhost:9000';
/** The actual address for the database emulator */
const DATABASE_ADDRESS: string =
process.env[DATABASE_ADDRESS_ENV] || DATABASE_ADDRESS_DEFAULT;
/** If this environment variable is set, use it for the Firestore emulator. */
const FIRESTORE_ADDRESS_ENV: string = 'FIREBASE_FIRESTORE_EMULATOR_ADDRESS';
/** The default address for the local Firestore emulator. */
const FIRESTORE_ADDRESS_DEFAULT: string = 'localhost:8080';
/** The actual address for the Firestore emulator */
const FIRESTORE_ADDRESS: string =
process.env[FIRESTORE_ADDRESS_ENV] || FIRESTORE_ADDRESS_DEFAULT;
/** Passing this in tells the emulator to treat you as an admin. */
const ADMIN_TOKEN = 'owner';
/** Create an unsecured JWT for the given auth payload. See https://tools.ietf.org/html/rfc7519#section-6. */
function createUnsecuredJwt(auth: object): string {
// Unsecured JWTs use "none" as the algorithm.
const header = {
alg: 'none',
kid: 'fakekid'
};
// Ensure that the auth payload has a value for 'iat'.
(auth as any).iat = (auth as any).iat || 0;
// Use `uid` field as a backup when `sub` is missing.
(auth as any).sub = (auth as any).sub || (auth as any).uid;
if (!(auth as any).sub) {
throw new Error("auth must be an object with a 'sub' or 'uid' field");
}
// Unsecured JWTs use the empty string as a signature.
const signature = '';
return [
base64.encodeString(JSON.stringify(header), /*webSafe=*/ false),
base64.encodeString(JSON.stringify(auth), /*webSafe=*/ false),
signature
].join('.');
}
export function apps(): firebase.app.App[] {
return firebase.apps;
}
export type AppOptions = {
databaseName?: string;
projectId?: string;
auth?: object;
};
/** Construct an App authenticated with options.auth. */
export function initializeTestApp(options: AppOptions): firebase.app.App {
return initializeApp(
options.auth ? createUnsecuredJwt(options.auth) : null,
options.databaseName,
options.projectId
);
}
export type AdminAppOptions = {
databaseName?: string;
projectId?: string;
};
/** Construct an App authenticated as an admin user. */
export function initializeAdminApp(options: AdminAppOptions): firebase.app.App {
return initializeApp(ADMIN_TOKEN, options.databaseName, options.projectId);
}
function initializeApp(
accessToken?: string,
databaseName?: string,
projectId?: string
): firebase.app.App {
let appOptions = {};
if (databaseName) {
appOptions = {
databaseURL: `http://${DATABASE_ADDRESS}?ns=${databaseName}`
};
} else if (projectId) {
appOptions = {
projectId: projectId
};
} else {
throw new Error('neither databaseName or projectId were specified');
}
const appName = 'app-' + new Date().getTime() + '-' + Math.random();
let app = firebase.initializeApp(appOptions, appName);
// hijacking INTERNAL.getToken to bypass FirebaseAuth and allows specifying of auth headers
if (accessToken) {
(app as any).INTERNAL.getToken = () =>
Promise.resolve({ accessToken: accessToken });
}
if (databaseName) {
// Toggle network connectivity to force a reauthentication attempt.
// This mitigates a minor race condition where the client can send the
// first database request before authenticating.
app.database().goOffline();
app.database().goOnline();
}
if (projectId) {
app.firestore().settings({
host: FIRESTORE_ADDRESS,
ssl: false,
timestampsInSnapshots: true
});
}
/**
Mute warnings for the previously-created database and whatever other
objects were just created.
*/
setLogLevel(LogLevel.ERROR);
return app;
}
export type LoadDatabaseRulesOptions = {
databaseName: string;
rules: string;
};
export function loadDatabaseRules(
options: LoadDatabaseRulesOptions
): Promise<void> {
if (!options.databaseName) {
throw Error('databaseName not specified');
}
if (!options.rules) {
throw Error('must provide rules to loadDatabaseRules');
}
return new Promise((resolve, reject) => {
request.put(
{
uri: `http://${DATABASE_ADDRESS}/.settings/rules.json?ns=${
options.databaseName
}`,
headers: { Authorization: 'Bearer owner' },
body: options.rules
},
(err, resp, body) => {
if (err) {
reject(err);
} else {
resolve();
}
}
);
});
}
export type LoadFirestoreRulesOptions = {
projectId: string;
rules: string;
};
export function loadFirestoreRules(
options: LoadFirestoreRulesOptions
): Promise<void> {
if (!options.projectId) {
throw new Error('projectId not specified');
}
if (!options.rules) {
throw new Error('must provide rules to loadFirestoreRules');
}
let client = new EMULATOR.FirestoreEmulator(
FIRESTORE_ADDRESS,
grpc.credentials.createInsecure()
);
return new Promise((resolve, reject) => {
client.setSecurityRules(
{
project: `projects/${options.projectId}`,
rules: { files: [{ content: options.rules }] }
},
(err, resp) => {
if (err) {
reject(err);
} else {
resolve(resp);
}
}
);
});
}
export function assertFails(pr: Promise<any>): any {
return pr.then(
v =>
Promise.reject(new Error('Expected request to fail, but it succeeded.')),
err => err
);
}
export function assertSucceeds(pr: Promise<any>): any {
return pr;
}