Skip to content

Commit ea9c2e4

Browse files
jmwskiMichael Lehenbauer
authored andcommitted
use fake "owner" credential when rtdb emulator env var is set (#2029)
* omit access token exchange if talking to an emulator * [AUTOMATED]: Prettier Code Styling * create TokenProvider interface and add EmulatorAuthTokenProvider * [AUTOMATED]: Prettier Code Styling * Update packages/database/src/core/EmulatorAuthTokenProvider.ts Co-Authored-By: Yuchen Shi <[email protected]> * break circular dependency by extracting env var constant * [AUTOMATED]: Prettier Code Styling * rename AuthTokenProvider -> FirebaseAuthTokenProvider etc. * [AUTOMATED]: Prettier Code Styling * fix ReadOnlyRestClient constructor comment * poke travis CI * remove unnecessary js docs
1 parent bc0090e commit ea9c2e4

File tree

6 files changed

+99
-22
lines changed

6 files changed

+99
-22
lines changed

packages/database/src/core/AuthTokenProvider.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,28 @@ import { FirebaseAuthTokenData } from '@firebase/app-types/private';
2020
import { log, warn } from './util/util';
2121

2222
/**
23-
* Abstraction around FirebaseApp's token fetching capabilities.
23+
* An interface for token fetchers.
2424
*/
25-
export class AuthTokenProvider {
26-
/**
27-
* @param {!FirebaseApp} app_
28-
*/
29-
constructor(private app_: FirebaseApp) {}
30-
25+
export interface AuthTokenProvider {
3126
/**
3227
* @param {boolean} forceRefresh
3328
* @return {!Promise<FirebaseAuthTokenData>}
3429
*/
30+
getToken(forceRefresh: boolean): Promise<FirebaseAuthTokenData>;
31+
32+
addTokenChangeListener(listener: (token: string | null) => void);
33+
34+
removeTokenChangeListener(listener: (token: string | null) => void);
35+
36+
notifyForInvalidToken();
37+
}
38+
39+
/**
40+
* Abstraction around FirebaseApp's token fetching capabilities.
41+
*/
42+
export class FirebaseAuthTokenProvider implements AuthTokenProvider {
43+
constructor(private app_: FirebaseApp) {}
44+
3545
getToken(forceRefresh: boolean): Promise<FirebaseAuthTokenData> {
3646
return this.app_['INTERNAL']['getToken'](forceRefresh).then(
3747
null,
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* @license
3+
* Copyright 2019 Google Inc.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import { FirebaseApp } from '@firebase/app-types';
19+
import { FirebaseAuthTokenData } from '@firebase/app-types/private';
20+
21+
import { AuthTokenProvider } from './AuthTokenProvider';
22+
import { log, warn } from './util/util';
23+
24+
class EmulatorAuthToken implements FirebaseAuthTokenData {
25+
constructor(public accessToken: string) {}
26+
}
27+
28+
export class EmulatorAuthTokenProvider implements AuthTokenProvider {
29+
constructor(private app_: FirebaseApp) {}
30+
31+
getToken(forceRefresh: boolean): Promise<FirebaseAuthTokenData> {
32+
return Promise.resolve(new EmulatorAuthToken('owner'));
33+
}
34+
35+
addTokenChangeListener(listener: (token: string | null) => void) {}
36+
37+
removeTokenChangeListener(listener: (token: string | null) => void) {}
38+
39+
notifyForInvalidToken() {
40+
let errorMessage =
41+
'Database emulator unexpectedly rejected fake "owner" credentials.';
42+
warn(errorMessage);
43+
}
44+
}

packages/database/src/core/ReadonlyRestClient.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ import { safeGet } from '@firebase/util';
2222
import { querystring } from '@firebase/util';
2323
import { ServerActions } from './ServerActions';
2424
import { RepoInfo } from './RepoInfo';
25-
import { AuthTokenProvider } from './AuthTokenProvider';
25+
import {
26+
FirebaseAuthTokenProvider,
27+
AuthTokenProvider
28+
} from './AuthTokenProvider';
2629
import { Query } from '../api/Query';
2730

2831
/**

packages/database/src/core/Repo.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,20 @@ import { SparseSnapshotTree } from './SparseSnapshotTree';
2626
import { SyncTree } from './SyncTree';
2727
import { SnapshotHolder } from './SnapshotHolder';
2828
import { stringify } from '@firebase/util';
29-
import { beingCrawled, each, exceptionGuard, warn, log } from './util/util';
29+
import {
30+
beingCrawled,
31+
each,
32+
exceptionGuard,
33+
warn,
34+
log,
35+
FIREBASE_DATABASE_EMULATOR_HOST_VAR
36+
} from './util/util';
3037
import { map, isEmpty } from '@firebase/util';
31-
import { AuthTokenProvider } from './AuthTokenProvider';
38+
import {
39+
FirebaseAuthTokenProvider,
40+
AuthTokenProvider
41+
} from './AuthTokenProvider';
42+
import { EmulatorAuthTokenProvider } from './EmulatorAuthTokenProvider';
3243
import { StatsManager } from './stats/StatsManager';
3344
import { StatsReporter } from './stats/StatsReporter';
3445
import { StatsListener } from './stats/StatsListener';
@@ -81,7 +92,15 @@ export class Repo {
8192
forceRestClient: boolean,
8293
public app: FirebaseApp
8394
) {
84-
const authTokenProvider = new AuthTokenProvider(app);
95+
let authTokenProvider: AuthTokenProvider;
96+
if (
97+
typeof process !== 'undefined' &&
98+
process.env[FIREBASE_DATABASE_EMULATOR_HOST_VAR]
99+
) {
100+
authTokenProvider = new EmulatorAuthTokenProvider(app);
101+
} else {
102+
authTokenProvider = new FirebaseAuthTokenProvider(app);
103+
}
85104

86105
this.stats_ = StatsManager.getCollection(repoInfo_);
87106

packages/database/src/core/RepoManager.ts

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import { FirebaseApp } from '@firebase/app-types';
1919
import { safeGet } from '@firebase/util';
2020
import { Repo } from './Repo';
21-
import { fatal } from './util/util';
21+
import { fatal, FIREBASE_DATABASE_EMULATOR_HOST_VAR } from './util/util';
2222
import { parseRepoInfo, parseURL } from './util/libs/parser';
2323
import { validateUrl } from './util/validation';
2424
import './Repo_transaction';
@@ -28,16 +28,6 @@ import { RepoInfo } from './RepoInfo';
2828
/** @const {string} */
2929
const DATABASE_URL_OPTION = 'databaseURL';
3030

31-
/**
32-
* This variable is also defined in the firebase node.js admin SDK. Before
33-
* modifying this definition, consult the definition in:
34-
*
35-
* https://github.com/firebase/firebase-admin-node
36-
*
37-
* and make sure the two are consistent.
38-
*/
39-
const FIREBASE_DATABASE_EMULATOR_HOST_VAR = 'FIREBASE_DATABASE_EMULATOR_HOST';
40-
4131
let _staticInstance: RepoManager;
4232

4333
/**

packages/database/src/core/util/util.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,17 @@ import { Logger, LogLevel } from '@firebase/logger';
3131

3232
const logClient = new Logger('@firebase/database');
3333

34+
/**
35+
* Environment variable for enabling interaction with the Firebase Realtime Database
36+
* emulator. If set, the module will present the endpoint with a fake "owner" credential
37+
* (see EmulatorAuthTokenProvider) instead of one belonging to a real account.
38+
*
39+
* The expected format for this variable is '<HOST>:<PORT>'. The transfer protocol must be
40+
* omitted and will default to 'http'.
41+
*/
42+
export const FIREBASE_DATABASE_EMULATOR_HOST_VAR =
43+
'FIREBASE_DATABASE_EMULATOR_HOST';
44+
3445
/**
3546
* Returns a locally-unique ID (generated by just incrementing up from 0 each time its called).
3647
* @type {function(): number} Generated ID.

0 commit comments

Comments
 (0)