firebase-functions 4.3.1 → 4.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/common/providers/database.js +1 -1
- package/lib/common/providers/https.d.ts +17 -0
- package/lib/common/providers/https.js +28 -8
- package/lib/logger/index.js +5 -2
- package/lib/v1/function-configuration.d.ts +23 -0
- package/lib/v1/providers/https.js +1 -0
- package/lib/v2/options.d.ts +2 -2
- package/lib/v2/providers/alerts/alerts.d.ts +1 -1
- package/lib/v2/providers/https.d.ts +23 -0
- package/lib/v2/providers/https.js +1 -0
- package/package.json +2 -2
|
@@ -12,8 +12,25 @@ export interface Request extends express.Request {
|
|
|
12
12
|
* The interface for AppCheck tokens verified in Callable functions
|
|
13
13
|
*/
|
|
14
14
|
export interface AppCheckData {
|
|
15
|
+
/**
|
|
16
|
+
* The app ID of a Firebase App attested by the App Check token.
|
|
17
|
+
*/
|
|
15
18
|
appId: string;
|
|
19
|
+
/**
|
|
20
|
+
* Decoded App Check token.
|
|
21
|
+
*/
|
|
16
22
|
token: DecodedAppCheckToken;
|
|
23
|
+
/**
|
|
24
|
+
* Indicates if the token has been consumed.
|
|
25
|
+
*
|
|
26
|
+
* @remarks
|
|
27
|
+
* `false` value indicates that this is the first time the App Check service has seen this token and marked the
|
|
28
|
+
* token as consumed for future use of the token.
|
|
29
|
+
*
|
|
30
|
+
* `true` value indicates the token has previously been marked as consumed by the App Check service. In this case,
|
|
31
|
+
* consider taking extra precautions, such as rejecting the request or requiring additional security checks.
|
|
32
|
+
*/
|
|
33
|
+
alreadyConsumed?: boolean;
|
|
17
34
|
}
|
|
18
35
|
/**
|
|
19
36
|
* The interface for Auth tokens verified in Callable functions
|
|
@@ -276,7 +276,7 @@ exports.unsafeDecodeAppCheckToken = unsafeDecodeAppCheckToken;
|
|
|
276
276
|
* @returns {CallableTokenStatus} Status of the token verifications.
|
|
277
277
|
*/
|
|
278
278
|
/** @internal */
|
|
279
|
-
async function checkTokens(req, ctx) {
|
|
279
|
+
async function checkTokens(req, ctx, options) {
|
|
280
280
|
const verifications = {
|
|
281
281
|
app: "INVALID",
|
|
282
282
|
auth: "INVALID",
|
|
@@ -286,7 +286,7 @@ async function checkTokens(req, ctx) {
|
|
|
286
286
|
verifications.auth = await checkAuthToken(req, ctx);
|
|
287
287
|
}),
|
|
288
288
|
Promise.resolve().then(async () => {
|
|
289
|
-
verifications.app = await checkAppCheckToken(req, ctx);
|
|
289
|
+
verifications.app = await checkAppCheckToken(req, ctx, options);
|
|
290
290
|
}),
|
|
291
291
|
]);
|
|
292
292
|
const logPayload = {
|
|
@@ -342,25 +342,45 @@ async function checkAuthToken(req, ctx) {
|
|
|
342
342
|
}
|
|
343
343
|
exports.checkAuthToken = checkAuthToken;
|
|
344
344
|
/** @internal */
|
|
345
|
-
async function checkAppCheckToken(req, ctx) {
|
|
346
|
-
|
|
347
|
-
|
|
345
|
+
async function checkAppCheckToken(req, ctx, options) {
|
|
346
|
+
var _a;
|
|
347
|
+
const appCheckToken = req.header("X-Firebase-AppCheck");
|
|
348
|
+
if (!appCheckToken) {
|
|
348
349
|
return "MISSING";
|
|
349
350
|
}
|
|
350
351
|
try {
|
|
351
352
|
let appCheckData;
|
|
352
353
|
if ((0, debug_1.isDebugFeatureEnabled)("skipTokenVerification")) {
|
|
353
|
-
const decodedToken = unsafeDecodeAppCheckToken(
|
|
354
|
+
const decodedToken = unsafeDecodeAppCheckToken(appCheckToken);
|
|
354
355
|
appCheckData = { appId: decodedToken.app_id, token: decodedToken };
|
|
356
|
+
if (options.consumeAppCheckToken) {
|
|
357
|
+
appCheckData.alreadyConsumed = false;
|
|
358
|
+
}
|
|
355
359
|
}
|
|
356
360
|
else {
|
|
357
|
-
|
|
361
|
+
const appCheck = (0, app_check_1.getAppCheck)((0, app_1.getApp)());
|
|
362
|
+
if (options.consumeAppCheckToken) {
|
|
363
|
+
if (((_a = appCheck.verifyToken) === null || _a === void 0 ? void 0 : _a.length) === 1) {
|
|
364
|
+
const errorMsg = "Unsupported version of the Admin SDK." +
|
|
365
|
+
" App Check token will not be consumed." +
|
|
366
|
+
" Please upgrade the firebase-admin to the latest version.";
|
|
367
|
+
logger.error(errorMsg);
|
|
368
|
+
throw new HttpsError("internal", "Internal Error");
|
|
369
|
+
}
|
|
370
|
+
appCheckData = await (0, app_check_1.getAppCheck)((0, app_1.getApp)()).verifyToken(appCheckToken, { consume: true });
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
appCheckData = await (0, app_check_1.getAppCheck)((0, app_1.getApp)()).verifyToken(appCheckToken);
|
|
374
|
+
}
|
|
358
375
|
}
|
|
359
376
|
ctx.app = appCheckData;
|
|
360
377
|
return "VALID";
|
|
361
378
|
}
|
|
362
379
|
catch (err) {
|
|
363
380
|
logger.warn("Failed to validate AppCheck token.", err);
|
|
381
|
+
if (err instanceof HttpsError) {
|
|
382
|
+
throw err;
|
|
383
|
+
}
|
|
364
384
|
return "INVALID";
|
|
365
385
|
}
|
|
366
386
|
}
|
|
@@ -409,7 +429,7 @@ function wrapOnCallHandler(options, handler) {
|
|
|
409
429
|
delete context.rawRequest.headers[exports.ORIGINAL_AUTH_HEADER];
|
|
410
430
|
}
|
|
411
431
|
}
|
|
412
|
-
const tokenStatus = await checkTokens(req, context);
|
|
432
|
+
const tokenStatus = await checkTokens(req, context, options);
|
|
413
433
|
if (tokenStatus.auth === "INVALID") {
|
|
414
434
|
throw new HttpsError("unauthenticated", "Unauthenticated");
|
|
415
435
|
}
|
package/lib/logger/index.js
CHANGED
|
@@ -129,12 +129,15 @@ function entryFromArgs(severity, args) {
|
|
|
129
129
|
if (severity === "ERROR" && !args.find((arg) => arg instanceof Error)) {
|
|
130
130
|
message = new Error(message).stack || message;
|
|
131
131
|
}
|
|
132
|
-
|
|
132
|
+
const out = {
|
|
133
133
|
"logging.googleapis.com/trace": (ctx === null || ctx === void 0 ? void 0 : ctx.traceId)
|
|
134
134
|
? `projects/${process.env.GCLOUD_PROJECT}/traces/${ctx.traceId}`
|
|
135
135
|
: undefined,
|
|
136
136
|
...entry,
|
|
137
137
|
severity,
|
|
138
|
-
message,
|
|
139
138
|
};
|
|
139
|
+
if (message) {
|
|
140
|
+
out.message = message;
|
|
141
|
+
}
|
|
142
|
+
return out;
|
|
140
143
|
}
|
|
@@ -172,6 +172,29 @@ export interface RuntimeOptions {
|
|
|
172
172
|
* When false, requests with invalid tokens set context.app to undefiend.
|
|
173
173
|
*/
|
|
174
174
|
enforceAppCheck?: boolean;
|
|
175
|
+
/**
|
|
176
|
+
* Determines whether Firebase App Check token is consumed on request. Defaults to false.
|
|
177
|
+
*
|
|
178
|
+
* @remarks
|
|
179
|
+
* Set this to true to enable the App Check replay protection feature by consuming the App Check token on callable
|
|
180
|
+
* request. Tokens that are found to be already consumed will have request.app.alreadyConsumed property set true.
|
|
181
|
+
*
|
|
182
|
+
*
|
|
183
|
+
* Tokens are only considered to be consumed if it is sent to the App Check service by setting this option to true.
|
|
184
|
+
* Other uses of the token do not consume it.
|
|
185
|
+
*
|
|
186
|
+
* This replay protection feature requires an additional network call to the App Check backend and forces the clients
|
|
187
|
+
* to obtain a fresh attestation from the chosen attestation providers. This can therefore negatively impact
|
|
188
|
+
* performance and can potentially deplete your attestation providers' quotas faster. Use this feature only for
|
|
189
|
+
* protecting low volume, security critical, or expensive operations.
|
|
190
|
+
*
|
|
191
|
+
* This option does not affect the enforceAppCheck option. Setting the latter to true will cause the callable function
|
|
192
|
+
* to automatically respond with a 401 Unauthorized status code when request includes an invalid App Check token.
|
|
193
|
+
* When request includes valid but consumed App Check tokens, requests will not be automatically rejected. Instead,
|
|
194
|
+
* the request.app.alreadyConsumed property will be set to true and pass the execution to the handler code for making
|
|
195
|
+
* further decisions, such as requiring additional security checks or rejecting the request.
|
|
196
|
+
*/
|
|
197
|
+
consumeAppCheckToken?: boolean;
|
|
175
198
|
/**
|
|
176
199
|
* Controls whether function configuration modified outside of function source is preserved. Defaults to false.
|
|
177
200
|
*
|
|
@@ -74,6 +74,7 @@ function _onCallWithOptions(handler, options) {
|
|
|
74
74
|
const fixedLen = (data, context) => handler(data, context);
|
|
75
75
|
const func = (0, https_1.onCallHandler)({
|
|
76
76
|
enforceAppCheck: options.enforceAppCheck,
|
|
77
|
+
consumeAppCheckToken: options.consumeAppCheckToken,
|
|
77
78
|
cors: { origin: true, methods: "POST" },
|
|
78
79
|
}, fixedLen);
|
|
79
80
|
func.__trigger = {
|
package/lib/v2/options.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { RESET_VALUE } from "../common/options";
|
|
|
5
5
|
/**
|
|
6
6
|
* List of all regions supported by Cloud Functions v2
|
|
7
7
|
*/
|
|
8
|
-
export type SupportedRegion = "asia-northeast1" | "europe-north1" | "europe-west1" | "europe-west4" | "us-central1" | "us-east1" | "us-west1";
|
|
8
|
+
export type SupportedRegion = "asia-east1" | "asia-northeast1" | "asia-northeast2" | "europe-north1" | "europe-west1" | "europe-west4" | "us-central1" | "us-east1" | "us-east4" | "us-west1" | "asia-east2" | "asia-northeast3" | "asia-southeast1" | "asia-southeast2" | "asia-south1" | "australia-southeast1" | "europe-central2" | "europe-west2" | "europe-west3" | "europe-west6" | "northamerica-northeast1" | "southamerica-east1" | "us-west2" | "us-west3" | "us-west4";
|
|
9
9
|
/**
|
|
10
10
|
* List of available memory options supported by Cloud Functions.
|
|
11
11
|
*/
|
|
@@ -111,7 +111,7 @@ export interface GlobalOptions {
|
|
|
111
111
|
* @remarks
|
|
112
112
|
* When true, requests with invalid tokens autorespond with a 401
|
|
113
113
|
* (Unauthorized) error.
|
|
114
|
-
* When false, requests with invalid tokens set event.app to
|
|
114
|
+
* When false, requests with invalid tokens set event.app to undefined.
|
|
115
115
|
*/
|
|
116
116
|
enforceAppCheck?: boolean;
|
|
117
117
|
/**
|
|
@@ -31,7 +31,7 @@ export interface AlertEvent<T> extends CloudEvent<FirebaseAlertData<T>> {
|
|
|
31
31
|
data: FirebaseAlertData<T>;
|
|
32
32
|
}
|
|
33
33
|
/** The underlying alert type of the Firebase Alerts provider. */
|
|
34
|
-
export type AlertType = "crashlytics.newFatalIssue" | "crashlytics.newNonfatalIssue" | "crashlytics.regression" | "crashlytics.stabilityDigest" | "crashlytics.velocity" | "crashlytics.newAnrIssue" | "billing.planUpdate" | "billing.
|
|
34
|
+
export type AlertType = "crashlytics.newFatalIssue" | "crashlytics.newNonfatalIssue" | "crashlytics.regression" | "crashlytics.stabilityDigest" | "crashlytics.velocity" | "crashlytics.newAnrIssue" | "billing.planUpdate" | "billing.planAutomatedUpdate" | "appDistribution.newTesterIosDevice" | "appDistribution.inAppFeedback" | "performance.threshold" | string;
|
|
35
35
|
/**
|
|
36
36
|
* Configuration for Firebase Alert functions.
|
|
37
37
|
*/
|
|
@@ -109,6 +109,29 @@ export interface CallableOptions extends HttpsOptions {
|
|
|
109
109
|
* When false, requests with invalid tokens set event.app to undefiend.
|
|
110
110
|
*/
|
|
111
111
|
enforceAppCheck?: boolean;
|
|
112
|
+
/**
|
|
113
|
+
* Determines whether Firebase App Check token is consumed on request. Defaults to false.
|
|
114
|
+
*
|
|
115
|
+
* @remarks
|
|
116
|
+
* Set this to true to enable the App Check replay protection feature by consuming the App Check token on callable
|
|
117
|
+
* request. Tokens that are found to be already consumed will have request.app.alreadyConsumed property set true.
|
|
118
|
+
*
|
|
119
|
+
*
|
|
120
|
+
* Tokens are only considered to be consumed if it is sent to the App Check service by setting this option to true.
|
|
121
|
+
* Other uses of the token do not consume it.
|
|
122
|
+
*
|
|
123
|
+
* This replay protection feature requires an additional network call to the App Check backend and forces the clients
|
|
124
|
+
* to obtain a fresh attestation from the chosen attestation providers. This can therefore negatively impact
|
|
125
|
+
* performance and can potentially deplete your attestation providers' quotas faster. Use this feature only for
|
|
126
|
+
* protecting low volume, security critical, or expensive operations.
|
|
127
|
+
*
|
|
128
|
+
* This option does not affect the enforceAppCheck option. Setting the latter to true will cause the callable function
|
|
129
|
+
* to automatically respond with a 401 Unauthorized status code when request includes an invalid App Check token.
|
|
130
|
+
* When request includes valid but consumed App Check tokens, requests will not be automatically rejected. Instead,
|
|
131
|
+
* the request.app.alreadyConsumed property will be set to true and pass the execution to the handler code for making
|
|
132
|
+
* further decisions, such as requiring additional security checks or rejecting the request.
|
|
133
|
+
*/
|
|
134
|
+
consumeAppCheckToken?: boolean;
|
|
112
135
|
}
|
|
113
136
|
/**
|
|
114
137
|
* Handles HTTPS requests.
|
|
@@ -119,6 +119,7 @@ function onCall(optsOrHandler, handler) {
|
|
|
119
119
|
const func = (0, https_1.onCallHandler)({
|
|
120
120
|
cors: { origin, methods: "POST" },
|
|
121
121
|
enforceAppCheck: (_a = opts.enforceAppCheck) !== null && _a !== void 0 ? _a : options.getGlobalOptions().enforceAppCheck,
|
|
122
|
+
consumeAppCheckToken: opts.consumeAppCheckToken,
|
|
122
123
|
}, fixedLen);
|
|
123
124
|
Object.defineProperty(func, "__trigger", {
|
|
124
125
|
get: () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "firebase-functions",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.4.1",
|
|
4
4
|
"description": "Firebase SDK for Cloud Functions",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"firebase",
|
|
@@ -225,7 +225,7 @@
|
|
|
225
225
|
"eslint-config-prettier": "^8.3.0",
|
|
226
226
|
"eslint-plugin-jsdoc": "^39.2.9",
|
|
227
227
|
"eslint-plugin-prettier": "^4.0.0",
|
|
228
|
-
"firebase-admin": "^
|
|
228
|
+
"firebase-admin": "^11.8.0",
|
|
229
229
|
"js-yaml": "^3.13.1",
|
|
230
230
|
"jsdom": "^16.2.1",
|
|
231
231
|
"jsonwebtoken": "^9.0.0",
|