-
Notifications
You must be signed in to change notification settings - Fork 919
/
Copy pathfirebaseServerApp.ts
176 lines (156 loc) · 5.48 KB
/
firebaseServerApp.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/**
* @license
* Copyright 2023 Google LLC
*
* 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 {
FirebaseAppSettings,
FirebaseServerApp,
FirebaseServerAppSettings,
FirebaseOptions
} from './public-types';
import { deleteApp, registerVersion } from './api';
import { ComponentContainer } from '@firebase/component';
import { FirebaseAppImpl } from './firebaseApp';
import { ERROR_FACTORY, AppError } from './errors';
import { name as packageName, version } from '../package.json';
import { base64Decode } from '@firebase/util';
// Parse the token and check to see if the `exp` claim is in the future.
// Reports an error to the console if the token or claim could not be parsed, or if `exp` is in
// the past.
function validateTokenTTL(base64Token: string, tokenName: string): void {
const secondPart = base64Decode(base64Token.split('.')[1]);
if (secondPart === null) {
console.error(
`FirebaseServerApp ${tokenName} is invalid: second part could not be parsed.`
);
return;
}
const expClaim = JSON.parse(secondPart).exp;
if (expClaim === undefined) {
console.error(
`FirebaseServerApp ${tokenName} is invalid: expiration claim could not be parsed`
);
return;
}
const exp = JSON.parse(secondPart).exp * 1000;
const now = new Date().getTime();
const diff = exp - now;
if (diff <= 0) {
console.error(
`FirebaseServerApp ${tokenName} is invalid: the token has expired.`
);
}
}
export class FirebaseServerAppImpl
extends FirebaseAppImpl
implements FirebaseServerApp
{
private readonly _serverConfig: FirebaseServerAppSettings;
private _finalizationRegistry: FinalizationRegistry<object> | null;
private _refCount: number;
constructor(
options: FirebaseOptions | FirebaseAppImpl,
serverConfig: FirebaseServerAppSettings,
name: string,
container: ComponentContainer
) {
// Build configuration parameters for the FirebaseAppImpl base class.
const automaticDataCollectionEnabled =
serverConfig.automaticDataCollectionEnabled !== undefined
? serverConfig.automaticDataCollectionEnabled
: false;
// Create the FirebaseAppSettings object for the FirebaseAppImp constructor.
const config: Required<FirebaseAppSettings> = {
name,
automaticDataCollectionEnabled
};
if ((options as FirebaseOptions).apiKey !== undefined) {
// Construct the parent FirebaseAppImp object.
super(options as FirebaseOptions, config, container);
} else {
const appImpl: FirebaseAppImpl = options as FirebaseAppImpl;
super(appImpl.options, config, container);
}
// Now construct the data for the FirebaseServerAppImpl.
this._serverConfig = {
automaticDataCollectionEnabled,
...serverConfig
};
// Ensure that the current time is within the `authIdtoken` window of validity.
if (this._serverConfig.authIdToken) {
validateTokenTTL(this._serverConfig.authIdToken, 'authIdToken');
}
// Ensure that the current time is within the `appCheckToken` window of validity.
if (this._serverConfig.appCheckToken) {
validateTokenTTL(this._serverConfig.appCheckToken, 'appCheckToken');
}
this._finalizationRegistry = null;
if (typeof FinalizationRegistry !== 'undefined') {
this._finalizationRegistry = new FinalizationRegistry(() => {
this.automaticCleanup();
});
}
this._refCount = 0;
this.incRefCount(this._serverConfig.releaseOnDeref);
// Do not retain a hard reference to the dref object, otherwise the FinalizationRegistry
// will never trigger.
this._serverConfig.releaseOnDeref = undefined;
serverConfig.releaseOnDeref = undefined;
registerVersion(packageName, version, 'serverapp');
}
toJSON(): undefined {
return undefined;
}
get refCount(): number {
return this._refCount;
}
// Increment the reference count of this server app. If an object is provided, register it
// with the finalization registry.
incRefCount(obj: object | undefined): void {
if (this.isDeleted) {
return;
}
this._refCount++;
if (obj !== undefined && this._finalizationRegistry !== null) {
this._finalizationRegistry.register(obj, this);
}
}
// Decrement the reference count.
decRefCount(): number {
if (this.isDeleted) {
return 0;
}
return --this._refCount;
}
// Invoked by the FinalizationRegistry callback to note that this app should go through its
// reference counts and delete itself if no reference count remain. The coordinating logic that
// handles this is in deleteApp(...).
private automaticCleanup(): void {
void deleteApp(this);
}
get settings(): FirebaseServerAppSettings {
this.checkDestroyed();
return this._serverConfig;
}
/**
* This function will throw an Error if the App has already been deleted -
* use before performing API actions on the App.
*/
protected checkDestroyed(): void {
if (this.isDeleted) {
throw ERROR_FACTORY.create(AppError.SERVER_APP_DELETED);
}
}
}