Skip to content

Commit abc9d87

Browse files
authored
[ServerApp] Mangle the FirebaseServerApp name (#7993)
Mangle the name of the ServerAap based on the hash of the parameters passed in. In addition, return the same instance of app when the same parameters are used.
1 parent 562d619 commit abc9d87

File tree

4 files changed

+89
-44
lines changed

4 files changed

+89
-44
lines changed

packages/app/src/api.test.ts

+65-8
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import { createTestComponent } from '../test/util';
4040
import { Component, ComponentType } from '@firebase/component';
4141
import { Logger } from '@firebase/logger';
4242
import { FirebaseAppImpl } from './firebaseApp';
43+
import { FirebaseServerAppImpl } from './firebaseServerApp';
4344
import { isBrowser } from '@firebase/util';
4445

4546
declare module '@firebase/component' {
@@ -184,7 +185,7 @@ describe('API tests', () => {
184185
});
185186

186187
describe('initializeServerApp', () => {
187-
it('creates FirebaseServerApp with options', () => {
188+
it('creates FirebaseServerApp fails in browsers.', () => {
188189
if (isBrowser()) {
189190
const options = {
190191
apiKey: 'APIKEY'
@@ -196,7 +197,7 @@ describe('API tests', () => {
196197
}
197198
});
198199

199-
it('creates FirebaseServerApp with options', () => {
200+
it('creates FirebaseServerApp with options', async () => {
200201
if (isBrowser()) {
201202
// FirebaseServerApp isn't supported for execution in browser enviornments.
202203
return;
@@ -211,9 +212,10 @@ describe('API tests', () => {
211212
const app = initializeServerApp(options, serverAppSettings);
212213
expect(app).to.not.equal(null);
213214
expect(app.automaticDataCollectionEnabled).to.be.false;
215+
await deleteApp(app);
214216
});
215217

216-
it('creates FirebaseServerApp with automaticDataCollectionEnabled', () => {
218+
it('creates FirebaseServerApp with automaticDataCollectionEnabled', async () => {
217219
if (isBrowser()) {
218220
// FirebaseServerApp isn't supported for execution in browser enviornments.
219221
return;
@@ -230,9 +232,10 @@ describe('API tests', () => {
230232
const app = initializeServerApp(options, serverAppSettings);
231233
expect(app).to.not.equal(null);
232234
expect(app.automaticDataCollectionEnabled).to.be.true;
235+
await deleteApp(app);
233236
});
234237

235-
it('creates FirebaseServerApp with releaseOnDeref', () => {
238+
it('creates FirebaseServerApp with releaseOnDeref', async () => {
236239
if (isBrowser()) {
237240
// FirebaseServerApp isn't supported for execution in browser enviornments.
238241
return;
@@ -247,9 +250,10 @@ describe('API tests', () => {
247250
const app = initializeServerApp(options, serverAppSettings);
248251
expect(app).to.not.equal(null);
249252
expect(app.automaticDataCollectionEnabled).to.be.false;
253+
await deleteApp(app);
250254
});
251255

252-
it('creates FirebaseServerApp with FirebaseApp', () => {
256+
it('creates FirebaseServerApp with FirebaseApp', async () => {
253257
if (isBrowser()) {
254258
// FirebaseServerApp isn't supported for execution in browser enviornments.
255259
return;
@@ -266,12 +270,65 @@ describe('API tests', () => {
266270
automaticDataCollectionEnabled: false
267271
};
268272

269-
const serverApp = initializeServerApp(standardApp, serverAppSettings);
270-
expect(serverApp).to.not.equal(null);
271-
expect(serverApp.options.apiKey).to.equal('test1');
273+
const app = initializeServerApp(standardApp, serverAppSettings);
274+
expect(app).to.not.equal(null);
275+
expect(app.options.apiKey).to.equal('test1');
276+
await deleteApp(app);
272277
});
273278
});
274279

280+
it('create similar FirebaseServerApps does not return the same object', async () => {
281+
if (isBrowser()) {
282+
// FirebaseServerApp isn't supported for execution in browser enviornments.
283+
return;
284+
}
285+
286+
const options = { apiKey: 'APIKEY' };
287+
const serverAppSettingsOne: FirebaseServerAppSettings = {
288+
automaticDataCollectionEnabled: false,
289+
releaseOnDeref: options
290+
};
291+
292+
const serverAppSettingsTwo: FirebaseServerAppSettings = {
293+
automaticDataCollectionEnabled: false
294+
};
295+
296+
const appOne = initializeServerApp(options, serverAppSettingsOne);
297+
expect(appOne).to.not.equal(null);
298+
expect(appOne.automaticDataCollectionEnabled).to.be.false;
299+
const appTwo = initializeServerApp(options, serverAppSettingsTwo);
300+
expect(appTwo).to.not.equal(null);
301+
expect(appTwo).to.not.equal(appOne);
302+
await deleteApp(appOne);
303+
await deleteApp(appTwo);
304+
});
305+
306+
it('create duplicate FirebaseServerApps returns the same object', async () => {
307+
if (isBrowser()) {
308+
// FirebaseServerApp isn't supported for execution in browser enviornments.
309+
return;
310+
}
311+
312+
const options = { apiKey: 'APIKEY' };
313+
const serverAppSettings: FirebaseServerAppSettings = {
314+
automaticDataCollectionEnabled: false,
315+
releaseOnDeref: options
316+
};
317+
318+
const appOne = initializeServerApp(options, serverAppSettings);
319+
expect(appOne).to.not.equal(null);
320+
expect(appOne.automaticDataCollectionEnabled).to.be.false;
321+
const appTwo = initializeServerApp(options, serverAppSettings);
322+
expect(appTwo).to.not.equal(null);
323+
expect(appTwo).to.equal(appOne);
324+
await deleteApp(appOne);
325+
326+
// TODO: When Reference Counting works, update test. The following line should be false
327+
// until and the app should be deleted a second time.
328+
expect((appOne as FirebaseServerAppImpl).isDeleted).to.be.true;
329+
// await deleteApp(appTwo);
330+
});
331+
275332
describe('getApp', () => {
276333
it('retrieves DEFAULT App', () => {
277334
const app = initializeApp({});

packages/app/src/api.ts

+17-14
Original file line numberDiff line numberDiff line change
@@ -235,22 +235,30 @@ export function initializeServerApp(
235235
throw ERROR_FACTORY.create(AppError.INVALID_SERVER_APP_ENVIRONMENT);
236236
}
237237

238-
const serverAppSettings: FirebaseServerAppSettings = {
239-
automaticDataCollectionEnabled: false,
240-
..._serverAppConfig
241-
};
242-
243238
let appOptions: FirebaseOptions;
244239
if (_isFirebaseApp(_options)) {
245240
appOptions = _options.options;
246241
} else {
247242
appOptions = _options;
248243
}
249244

245+
// Mangle the ap name based on a hash of the FirebaseServerAppSettings, and FirebaseOptions
246+
// objects and the authIdToken, if provided.
250247
const nameObj = {
251-
authIdToken: _serverAppConfig?.authIdToken,
248+
_serverAppConfig,
252249
...appOptions
253250
};
251+
const hashCode = (s: string): number => {
252+
return [...s].reduce(
253+
(hash, c) => (Math.imul(31, hash) + c.charCodeAt(0)) | 0,
254+
0
255+
);
256+
};
257+
258+
const serverAppSettings: FirebaseServerAppSettings = {
259+
automaticDataCollectionEnabled: false,
260+
..._serverAppConfig
261+
};
254262

255263
if (serverAppSettings.releaseOnDeref !== undefined) {
256264
if (typeof FinalizationRegistry === 'undefined') {
@@ -261,14 +269,6 @@ export function initializeServerApp(
261269
}
262270
}
263271

264-
// TODO: move this into util.js.
265-
const hashCode = (s: string): number => {
266-
return [...s].reduce(
267-
(hash, c) => (Math.imul(31, hash) + c.charCodeAt(0)) | 0,
268-
0
269-
);
270-
};
271-
272272
const nameString = '' + hashCode(JSON.stringify(nameObj));
273273
const existingApp = _serverApps.get(nameString) as FirebaseServerApp;
274274
if (existingApp) {
@@ -286,9 +286,12 @@ export function initializeServerApp(
286286
const newApp = new FirebaseServerAppImpl(
287287
appOptions,
288288
serverAppSettings,
289+
nameString,
289290
container
290291
);
291292

293+
_serverApps.set(nameString, newApp);
294+
292295
return newApp;
293296
}
294297

packages/app/src/firebaseServerApp.test.ts

+5-8
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ describe('FirebaseServerApp', () => {
3535
const firebaseServerAppImpl = new FirebaseServerAppImpl(
3636
options,
3737
serverAppSettings,
38+
'testName',
3839
new ComponentContainer('test')
3940
);
4041

@@ -55,6 +56,7 @@ describe('FirebaseServerApp', () => {
5556
const firebaseServerAppImpl = new FirebaseServerAppImpl(
5657
options,
5758
serverAppSettings,
59+
'testName',
5860
new ComponentContainer('test')
5961
);
6062

@@ -75,6 +77,7 @@ describe('FirebaseServerApp', () => {
7577
const firebaseServerAppImpl = new FirebaseServerAppImpl(
7678
options,
7779
serverAppSettings,
80+
'testName',
7881
new ComponentContainer('test')
7982
);
8083

@@ -96,6 +99,7 @@ describe('FirebaseServerApp', () => {
9699
const app = new FirebaseServerAppImpl(
97100
options,
98101
serverAppSettings,
102+
'testName',
99103
new ComponentContainer('test')
100104
);
101105

@@ -122,6 +126,7 @@ describe('FirebaseServerApp', () => {
122126
const app = new FirebaseServerAppImpl(
123127
options,
124128
serverAppSettings,
129+
'testName',
125130
new ComponentContainer('test')
126131
);
127132

@@ -131,13 +136,5 @@ describe('FirebaseServerApp', () => {
131136
expect(() => app.authIdTokenVerified()).throws(
132137
'Firebase Server App has been deleted'
133138
);
134-
135-
expect(() => app.appCheckTokenVerified()).throws(
136-
'Firebase Server App has been deleted'
137-
);
138-
139-
expect(() => app.installationTokenVerified()).throws(
140-
'Firebase Server App has been deleted'
141-
);
142139
});
143140
});

packages/app/src/firebaseServerApp.ts

+2-14
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export class FirebaseServerAppImpl
3636
constructor(
3737
options: FirebaseOptions | FirebaseAppImpl,
3838
serverConfig: FirebaseServerAppSettings,
39+
name: string,
3940
container: ComponentContainer
4041
) {
4142
// Build configuration parameters for the FirebaseAppImpl base class.
@@ -46,7 +47,7 @@ export class FirebaseServerAppImpl
4647

4748
// Create the FirebaseAppSettings object for the FirebaseAppImp constructor.
4849
const config: Required<FirebaseAppSettings> = {
49-
name: '',
50+
name,
5051
automaticDataCollectionEnabled
5152
};
5253

@@ -55,7 +56,6 @@ export class FirebaseServerAppImpl
5556
super(options as FirebaseOptions, config, container);
5657
} else {
5758
const appImpl: FirebaseAppImpl = options as FirebaseAppImpl;
58-
5959
super(appImpl.options, config, container);
6060
}
6161

@@ -94,18 +94,6 @@ export class FirebaseServerAppImpl
9494
return Promise.resolve();
9595
}
9696

97-
appCheckTokenVerified(): Promise<void> {
98-
this.checkDestroyed();
99-
// TODO
100-
return Promise.resolve();
101-
}
102-
103-
installationTokenVerified(): Promise<void> {
104-
this.checkDestroyed();
105-
// TODO
106-
return Promise.resolve();
107-
}
108-
10997
/**
11098
* This function will throw an Error if the App has already been deleted -
11199
* use before performing API actions on the App.

0 commit comments

Comments
 (0)