firebase-functions 3.24.1 → 4.0.0

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.
Files changed (130) hide show
  1. package/README.md +7 -9
  2. package/lib/bin/firebase-functions.js +13 -15
  3. package/lib/common/app.d.ts +14 -0
  4. package/lib/common/app.js +62 -0
  5. package/lib/common/change.d.ts +0 -5
  6. package/lib/common/change.js +5 -7
  7. package/lib/common/config.d.ts +6 -0
  8. package/lib/common/config.js +49 -0
  9. package/lib/common/debug.js +2 -2
  10. package/lib/common/encoding.d.ts +0 -8
  11. package/lib/common/encoding.js +6 -29
  12. package/lib/common/options.d.ts +14 -0
  13. package/lib/common/options.js +44 -0
  14. package/lib/common/params.d.ts +32 -0
  15. package/lib/common/params.js +23 -0
  16. package/lib/common/providers/database.d.ts +17 -19
  17. package/lib/common/providers/database.js +68 -39
  18. package/lib/common/providers/https.d.ts +11 -52
  19. package/lib/common/providers/https.js +115 -110
  20. package/lib/common/providers/identity.d.ts +8 -8
  21. package/lib/common/providers/identity.js +71 -79
  22. package/lib/common/providers/tasks.d.ts +11 -10
  23. package/lib/common/providers/tasks.js +10 -9
  24. package/lib/common/timezone.js +538 -538
  25. package/lib/common/trace.d.ts +14 -0
  26. package/lib/common/trace.js +69 -0
  27. package/lib/{encoder.d.ts → common/utilities/encoder.d.ts} +0 -0
  28. package/lib/{encoder.js → common/utilities/encoder.js} +1 -1
  29. package/lib/{utilities → common/utilities}/path-pattern.d.ts +0 -0
  30. package/lib/{utilities → common/utilities}/path-pattern.js +17 -16
  31. package/lib/{utilities → common/utilities}/path.d.ts +0 -0
  32. package/lib/{utilities → common/utilities}/path.js +5 -7
  33. package/lib/{utils.d.ts → common/utilities/utils.d.ts} +1 -1
  34. package/lib/{utils.js → common/utilities/utils.js} +18 -12
  35. package/lib/logger/common.d.ts +1 -3
  36. package/lib/logger/common.js +9 -14
  37. package/lib/logger/compat.js +9 -9
  38. package/lib/logger/index.d.ts +1 -1
  39. package/lib/logger/index.js +24 -30
  40. package/lib/{v2/params → params}/index.d.ts +22 -9
  41. package/lib/{v2/params → params}/index.js +22 -14
  42. package/lib/params/types.d.ts +180 -0
  43. package/lib/params/types.js +289 -0
  44. package/lib/runtime/loader.js +12 -14
  45. package/lib/runtime/manifest.d.ts +56 -24
  46. package/lib/runtime/manifest.js +114 -4
  47. package/lib/v1/cloud-functions.d.ts +232 -0
  48. package/lib/v1/cloud-functions.js +205 -0
  49. package/lib/v1/config.d.ts +8 -0
  50. package/lib/v1/config.js +75 -0
  51. package/lib/{function-builder.d.ts → v1/function-builder.d.ts} +16 -16
  52. package/lib/{function-builder.js → v1/function-builder.js} +56 -46
  53. package/lib/v1/function-configuration.d.ts +197 -0
  54. package/lib/v1/function-configuration.js +70 -0
  55. package/lib/v1/index.d.ts +20 -0
  56. package/lib/{index.js → v1/index.js} +5 -10
  57. package/lib/{providers → v1/providers}/analytics.d.ts +5 -11
  58. package/lib/{providers → v1/providers}/analytics.js +49 -43
  59. package/lib/{providers → v1/providers}/auth.d.ts +28 -18
  60. package/lib/{providers → v1/providers}/auth.js +45 -34
  61. package/lib/{providers → v1/providers}/database.d.ts +25 -42
  62. package/lib/{providers → v1/providers}/database.js +46 -46
  63. package/lib/{providers → v1/providers}/firestore.d.ts +15 -33
  64. package/lib/{providers → v1/providers}/firestore.js +40 -44
  65. package/lib/{providers → v1/providers}/https.d.ts +3 -8
  66. package/lib/{providers → v1/providers}/https.js +14 -22
  67. package/lib/{providers → v1/providers}/pubsub.d.ts +8 -16
  68. package/lib/{providers → v1/providers}/pubsub.js +22 -26
  69. package/lib/{providers → v1/providers}/remoteConfig.d.ts +2 -11
  70. package/lib/{providers → v1/providers}/remoteConfig.js +9 -9
  71. package/lib/{providers → v1/providers}/storage.d.ts +11 -26
  72. package/lib/{providers → v1/providers}/storage.js +24 -29
  73. package/lib/{providers → v1/providers}/tasks.d.ts +6 -8
  74. package/lib/{providers → v1/providers}/tasks.js +12 -17
  75. package/lib/{providers → v1/providers}/testLab.d.ts +86 -46
  76. package/lib/{providers → v1/providers}/testLab.js +14 -14
  77. package/lib/v2/core.d.ts +4 -5
  78. package/lib/v2/index.d.ts +16 -14
  79. package/lib/v2/index.js +5 -1
  80. package/lib/v2/options.d.ts +52 -32
  81. package/lib/v2/options.js +32 -47
  82. package/lib/v2/providers/alerts/alerts.d.ts +20 -18
  83. package/lib/v2/providers/alerts/alerts.js +9 -6
  84. package/lib/v2/providers/alerts/appDistribution.d.ts +28 -26
  85. package/lib/v2/providers/alerts/appDistribution.js +8 -7
  86. package/lib/v2/providers/alerts/billing.d.ts +5 -5
  87. package/lib/v2/providers/alerts/billing.js +5 -4
  88. package/lib/v2/providers/alerts/crashlytics.d.ts +32 -30
  89. package/lib/v2/providers/alerts/crashlytics.js +10 -9
  90. package/lib/v2/providers/alerts/index.d.ts +5 -5
  91. package/lib/v2/providers/alerts/performance.d.ts +3 -3
  92. package/lib/v2/providers/alerts/performance.js +5 -7
  93. package/lib/v2/providers/database.d.ts +41 -38
  94. package/lib/v2/providers/database.js +22 -17
  95. package/lib/v2/providers/eventarc.d.ts +25 -23
  96. package/lib/v2/providers/eventarc.js +10 -7
  97. package/lib/v2/providers/https.d.ts +43 -33
  98. package/lib/v2/providers/https.js +18 -56
  99. package/lib/v2/providers/identity.d.ts +25 -23
  100. package/lib/v2/providers/identity.js +10 -7
  101. package/lib/v2/providers/pubsub.d.ts +25 -23
  102. package/lib/v2/providers/pubsub.js +11 -27
  103. package/lib/v2/providers/remoteConfig.d.ts +63 -0
  104. package/lib/v2/providers/remoteConfig.js +65 -0
  105. package/lib/v2/providers/scheduler.d.ts +14 -12
  106. package/lib/v2/providers/scheduler.js +16 -14
  107. package/lib/v2/providers/storage.d.ts +32 -30
  108. package/lib/v2/providers/storage.js +16 -32
  109. package/lib/v2/providers/tasks.d.ts +30 -26
  110. package/lib/v2/providers/tasks.js +14 -31
  111. package/lib/v2/providers/testLab.d.ts +110 -0
  112. package/lib/v2/providers/testLab.js +65 -0
  113. package/lib/v2/trace.d.ts +4 -0
  114. package/lib/v2/trace.js +21 -0
  115. package/package.json +61 -66
  116. package/lib/apps.d.ts +0 -35
  117. package/lib/apps.js +0 -112
  118. package/lib/cloud-functions.d.ts +0 -231
  119. package/lib/cloud-functions.js +0 -251
  120. package/lib/config.d.ts +0 -24
  121. package/lib/config.js +0 -117
  122. package/lib/function-configuration.d.ts +0 -108
  123. package/lib/function-configuration.js +0 -71
  124. package/lib/handler-builder.d.ts +0 -256
  125. package/lib/handler-builder.js +0 -349
  126. package/lib/index.d.ts +0 -19
  127. package/lib/setup.d.ts +0 -1
  128. package/lib/setup.js +0 -60
  129. package/lib/v2/params/types.d.ts +0 -118
  130. package/lib/v2/params/types.js +0 -196
@@ -26,7 +26,9 @@ const cors = require("cors");
26
26
  const logger = require("../../logger");
27
27
  // TODO(inlined): Decide whether we want to un-version apps or whether we want a
28
28
  // different strategy
29
- const apps_1 = require("../../apps");
29
+ const app_check_1 = require("firebase-admin/app-check");
30
+ const auth_1 = require("firebase-admin/auth");
31
+ const app_1 = require("../app");
30
32
  const debug_1 = require("../debug");
31
33
  const JWT_REGEX = /^[a-zA-Z0-9\-_=]+?\.[a-zA-Z0-9\-_=]+?\.([a-zA-Z0-9\-_=]+)?$/;
32
34
  /**
@@ -39,23 +41,23 @@ const JWT_REGEX = /^[a-zA-Z0-9\-_=]+?\.[a-zA-Z0-9\-_=]+?\.([a-zA-Z0-9\-_=]+)?$/;
39
41
  * supported set.
40
42
  */
41
43
  const errorCodeMap = {
42
- ok: { canonicalName: 'OK', status: 200 },
43
- cancelled: { canonicalName: 'CANCELLED', status: 499 },
44
- unknown: { canonicalName: 'UNKNOWN', status: 500 },
45
- 'invalid-argument': { canonicalName: 'INVALID_ARGUMENT', status: 400 },
46
- 'deadline-exceeded': { canonicalName: 'DEADLINE_EXCEEDED', status: 504 },
47
- 'not-found': { canonicalName: 'NOT_FOUND', status: 404 },
48
- 'already-exists': { canonicalName: 'ALREADY_EXISTS', status: 409 },
49
- 'permission-denied': { canonicalName: 'PERMISSION_DENIED', status: 403 },
50
- unauthenticated: { canonicalName: 'UNAUTHENTICATED', status: 401 },
51
- 'resource-exhausted': { canonicalName: 'RESOURCE_EXHAUSTED', status: 429 },
52
- 'failed-precondition': { canonicalName: 'FAILED_PRECONDITION', status: 400 },
53
- aborted: { canonicalName: 'ABORTED', status: 409 },
54
- 'out-of-range': { canonicalName: 'OUT_OF_RANGE', status: 400 },
55
- unimplemented: { canonicalName: 'UNIMPLEMENTED', status: 501 },
56
- internal: { canonicalName: 'INTERNAL', status: 500 },
57
- unavailable: { canonicalName: 'UNAVAILABLE', status: 503 },
58
- 'data-loss': { canonicalName: 'DATA_LOSS', status: 500 },
44
+ ok: { canonicalName: "OK", status: 200 },
45
+ cancelled: { canonicalName: "CANCELLED", status: 499 },
46
+ unknown: { canonicalName: "UNKNOWN", status: 500 },
47
+ "invalid-argument": { canonicalName: "INVALID_ARGUMENT", status: 400 },
48
+ "deadline-exceeded": { canonicalName: "DEADLINE_EXCEEDED", status: 504 },
49
+ "not-found": { canonicalName: "NOT_FOUND", status: 404 },
50
+ "already-exists": { canonicalName: "ALREADY_EXISTS", status: 409 },
51
+ "permission-denied": { canonicalName: "PERMISSION_DENIED", status: 403 },
52
+ unauthenticated: { canonicalName: "UNAUTHENTICATED", status: 401 },
53
+ "resource-exhausted": { canonicalName: "RESOURCE_EXHAUSTED", status: 429 },
54
+ "failed-precondition": { canonicalName: "FAILED_PRECONDITION", status: 400 },
55
+ aborted: { canonicalName: "ABORTED", status: 409 },
56
+ "out-of-range": { canonicalName: "OUT_OF_RANGE", status: 400 },
57
+ unimplemented: { canonicalName: "UNIMPLEMENTED", status: 501 },
58
+ internal: { canonicalName: "INTERNAL", status: 500 },
59
+ unavailable: { canonicalName: "UNAVAILABLE", status: 503 },
60
+ "data-loss": { canonicalName: "DATA_LOSS", status: 500 },
59
61
  };
60
62
  /**
61
63
  * An explicit error that can be thrown from a handler to send an error to the
@@ -90,51 +92,51 @@ exports.HttpsError = HttpsError;
90
92
  function isValidRequest(req) {
91
93
  // The body must not be empty.
92
94
  if (!req.body) {
93
- logger.warn('Request is missing body.');
95
+ logger.warn("Request is missing body.");
94
96
  return false;
95
97
  }
96
98
  // Make sure it's a POST.
97
- if (req.method !== 'POST') {
98
- logger.warn('Request has invalid method.', req.method);
99
+ if (req.method !== "POST") {
100
+ logger.warn("Request has invalid method.", req.method);
99
101
  return false;
100
102
  }
101
103
  // Check that the Content-Type is JSON.
102
- let contentType = (req.header('Content-Type') || '').toLowerCase();
104
+ let contentType = (req.header("Content-Type") || "").toLowerCase();
103
105
  // If it has a charset, just ignore it for now.
104
- const semiColon = contentType.indexOf(';');
106
+ const semiColon = contentType.indexOf(";");
105
107
  if (semiColon >= 0) {
106
108
  contentType = contentType.slice(0, semiColon).trim();
107
109
  }
108
- if (contentType !== 'application/json') {
109
- logger.warn('Request has incorrect Content-Type.', contentType);
110
+ if (contentType !== "application/json") {
111
+ logger.warn("Request has incorrect Content-Type.", contentType);
110
112
  return false;
111
113
  }
112
114
  // The body must have data.
113
- if (typeof req.body.data === 'undefined') {
114
- logger.warn('Request body is missing data.', req.body);
115
+ if (typeof req.body.data === "undefined") {
116
+ logger.warn("Request body is missing data.", req.body);
115
117
  return false;
116
118
  }
117
119
  // TODO(klimt): Allow only specific http headers.
118
120
  // Verify that the body does not have any extra fields.
119
- const extraKeys = Object.keys(req.body).filter((field) => field !== 'data');
121
+ const extraKeys = Object.keys(req.body).filter((field) => field !== "data");
120
122
  if (extraKeys.length !== 0) {
121
- logger.warn('Request body has extra fields: ', extraKeys.join(', '));
123
+ logger.warn("Request body has extra fields: ", extraKeys.join(", "));
122
124
  return false;
123
125
  }
124
126
  return true;
125
127
  }
126
128
  exports.isValidRequest = isValidRequest;
127
129
  /** @hidden */
128
- const LONG_TYPE = 'type.googleapis.com/google.protobuf.Int64Value';
130
+ const LONG_TYPE = "type.googleapis.com/google.protobuf.Int64Value";
129
131
  /** @hidden */
130
- const UNSIGNED_LONG_TYPE = 'type.googleapis.com/google.protobuf.UInt64Value';
132
+ const UNSIGNED_LONG_TYPE = "type.googleapis.com/google.protobuf.UInt64Value";
131
133
  /**
132
134
  * Encodes arbitrary data in our special format for JSON.
133
135
  * This is exposed only for testing.
134
136
  */
135
137
  /** @hidden */
136
138
  function encode(data) {
137
- if (data === null || typeof data === 'undefined') {
139
+ if (data === null || typeof data === "undefined") {
138
140
  return null;
139
141
  }
140
142
  if (data instanceof Number) {
@@ -145,16 +147,16 @@ function encode(data) {
145
147
  // without any loss of precision.
146
148
  return data;
147
149
  }
148
- if (typeof data === 'boolean') {
150
+ if (typeof data === "boolean") {
149
151
  return data;
150
152
  }
151
- if (typeof data === 'string') {
153
+ if (typeof data === "string") {
152
154
  return data;
153
155
  }
154
156
  if (Array.isArray(data)) {
155
157
  return data.map(encode);
156
158
  }
157
- if (typeof data === 'object' || typeof data === 'function') {
159
+ if (typeof data === "object" || typeof data === "function") {
158
160
  // Sadly we don't have Object.fromEntries in Node 10, so we can't use a single
159
161
  // list comprehension
160
162
  const obj = {};
@@ -164,8 +166,8 @@ function encode(data) {
164
166
  return obj;
165
167
  }
166
168
  // If we got this far, the data is not encodable.
167
- logger.error('Data cannot be encoded in JSON.', data);
168
- throw new Error('Data cannot be encoded in JSON: ' + data);
169
+ logger.error("Data cannot be encoded in JSON.", data);
170
+ throw new Error(`Data cannot be encoded in JSON: ${data}`);
169
171
  }
170
172
  exports.encode = encode;
171
173
  /**
@@ -177,8 +179,8 @@ function decode(data) {
177
179
  if (data === null) {
178
180
  return data;
179
181
  }
180
- if (data['@type']) {
181
- switch (data['@type']) {
182
+ if (data["@type"]) {
183
+ switch (data["@type"]) {
182
184
  case LONG_TYPE:
183
185
  // Fall through and handle this the same as unsigned.
184
186
  case UNSIGNED_LONG_TYPE: {
@@ -187,21 +189,21 @@ function decode(data) {
187
189
  // worth all the extra code to detect that case.
188
190
  const value = parseFloat(data.value);
189
191
  if (isNaN(value)) {
190
- logger.error('Data cannot be decoded from JSON.', data);
191
- throw new Error('Data cannot be decoded from JSON: ' + data);
192
+ logger.error("Data cannot be decoded from JSON.", data);
193
+ throw new Error(`Data cannot be decoded from JSON: ${data}`);
192
194
  }
193
195
  return value;
194
196
  }
195
197
  default: {
196
- logger.error('Data cannot be decoded from JSON.', data);
197
- throw new Error('Data cannot be decoded from JSON: ' + data);
198
+ logger.error("Data cannot be decoded from JSON.", data);
199
+ throw new Error(`Data cannot be decoded from JSON: ${data}`);
198
200
  }
199
201
  }
200
202
  }
201
203
  if (Array.isArray(data)) {
202
204
  return data.map(decode);
203
205
  }
204
- if (typeof data === 'object') {
206
+ if (typeof data === "object") {
205
207
  const obj = {};
206
208
  for (const [k, v] of Object.entries(data)) {
207
209
  obj[k] = decode(v);
@@ -217,18 +219,18 @@ function unsafeDecodeToken(token) {
217
219
  if (!JWT_REGEX.test(token)) {
218
220
  return {};
219
221
  }
220
- const components = token
221
- .split('.')
222
- .map((s) => Buffer.from(s, 'base64').toString());
222
+ const components = token.split(".").map((s) => Buffer.from(s, "base64").toString());
223
223
  let payload = components[1];
224
- if (typeof payload === 'string') {
224
+ if (typeof payload === "string") {
225
225
  try {
226
226
  const obj = JSON.parse(payload);
227
- if (typeof obj === 'object') {
227
+ if (typeof obj === "object") {
228
228
  payload = obj;
229
229
  }
230
230
  }
231
- catch (e) { }
231
+ catch (e) {
232
+ // ignore error
233
+ }
232
234
  }
233
235
  return payload;
234
236
  }
@@ -267,13 +269,13 @@ exports.unsafeDecodeAppCheckToken = unsafeDecodeAppCheckToken;
267
269
  *
268
270
  * @param {Request} req - Request sent to the Callable function.
269
271
  * @param {CallableContext} ctx - Context to be sent to callable function handler.
270
- * @return {CallableTokenStatus} Status of the token verifications.
272
+ * @returns {CallableTokenStatus} Status of the token verifications.
271
273
  */
272
274
  /** @internal */
273
275
  async function checkTokens(req, ctx) {
274
276
  const verifications = {
275
- app: 'INVALID',
276
- auth: 'INVALID',
277
+ app: "INVALID",
278
+ auth: "INVALID",
277
279
  };
278
280
  await Promise.all([
279
281
  Promise.resolve().then(async () => {
@@ -285,83 +287,77 @@ async function checkTokens(req, ctx) {
285
287
  ]);
286
288
  const logPayload = {
287
289
  verifications,
288
- 'logging.googleapis.com/labels': {
289
- 'firebase-log-type': 'callable-request-verification',
290
+ "logging.googleapis.com/labels": {
291
+ "firebase-log-type": "callable-request-verification",
290
292
  },
291
293
  };
292
294
  const errs = [];
293
- if (verifications.app === 'INVALID') {
294
- errs.push('AppCheck token was rejected.');
295
+ if (verifications.app === "INVALID") {
296
+ errs.push("AppCheck token was rejected.");
295
297
  }
296
- if (verifications.auth === 'INVALID') {
297
- errs.push('Auth token was rejected.');
298
+ if (verifications.auth === "INVALID") {
299
+ errs.push("Auth token was rejected.");
298
300
  }
299
- if (errs.length == 0) {
300
- logger.info('Callable request verification passed', logPayload);
301
+ if (errs.length === 0) {
302
+ logger.debug("Callable request verification passed", logPayload);
301
303
  }
302
304
  else {
303
- logger.warn(`Callable request verification failed: ${errs.join(' ')}`, logPayload);
305
+ logger.warn(`Callable request verification failed: ${errs.join(" ")}`, logPayload);
304
306
  }
305
307
  return verifications;
306
308
  }
307
309
  /** @interanl */
308
310
  async function checkAuthToken(req, ctx) {
309
- const authorization = req.header('Authorization');
311
+ const authorization = req.header("Authorization");
310
312
  if (!authorization) {
311
- return 'MISSING';
313
+ return "MISSING";
312
314
  }
313
- const match = authorization.match(/^Bearer (.*)$/);
314
- if (match) {
315
- const idToken = match[1];
316
- try {
317
- let authToken;
318
- if ((0, debug_1.isDebugFeatureEnabled)('skipTokenVerification')) {
319
- authToken = unsafeDecodeIdToken(idToken);
320
- }
321
- else {
322
- authToken = await (0, apps_1.apps)()
323
- .admin.auth()
324
- .verifyIdToken(idToken);
325
- }
326
- ctx.auth = {
327
- uid: authToken.uid,
328
- token: authToken,
329
- };
330
- return 'VALID';
315
+ const match = authorization.match(/^Bearer (.*)$/i);
316
+ if (!match) {
317
+ return "INVALID";
318
+ }
319
+ const idToken = match[1];
320
+ try {
321
+ let authToken;
322
+ if ((0, debug_1.isDebugFeatureEnabled)("skipTokenVerification")) {
323
+ authToken = unsafeDecodeIdToken(idToken);
331
324
  }
332
- catch (err) {
333
- logger.warn('Failed to validate auth token.', err);
334
- return 'INVALID';
325
+ else {
326
+ authToken = await (0, auth_1.getAuth)((0, app_1.getApp)()).verifyIdToken(idToken);
335
327
  }
328
+ ctx.auth = {
329
+ uid: authToken.uid,
330
+ token: authToken,
331
+ };
332
+ return "VALID";
333
+ }
334
+ catch (err) {
335
+ logger.warn("Failed to validate auth token.", err);
336
+ return "INVALID";
336
337
  }
337
338
  }
338
339
  exports.checkAuthToken = checkAuthToken;
339
340
  /** @internal */
340
341
  async function checkAppCheckToken(req, ctx) {
341
- const appCheck = req.header('X-Firebase-AppCheck');
342
+ const appCheck = req.header("X-Firebase-AppCheck");
342
343
  if (!appCheck) {
343
- return 'MISSING';
344
+ return "MISSING";
344
345
  }
345
346
  try {
346
- if (!(0, apps_1.apps)().admin.appCheck) {
347
- throw new Error('Cannot validate AppCheck token. Please update Firebase Admin SDK to >= v9.8.0');
348
- }
349
347
  let appCheckData;
350
- if ((0, debug_1.isDebugFeatureEnabled)('skipTokenVerification')) {
348
+ if ((0, debug_1.isDebugFeatureEnabled)("skipTokenVerification")) {
351
349
  const decodedToken = unsafeDecodeAppCheckToken(appCheck);
352
350
  appCheckData = { appId: decodedToken.app_id, token: decodedToken };
353
351
  }
354
352
  else {
355
- appCheckData = await (0, apps_1.apps)()
356
- .admin.appCheck()
357
- .verifyToken(appCheck);
353
+ appCheckData = await (0, app_check_1.getAppCheck)((0, app_1.getApp)()).verifyToken(appCheck);
358
354
  }
359
355
  ctx.app = appCheckData;
360
- return 'VALID';
356
+ return "VALID";
361
357
  }
362
358
  catch (err) {
363
- logger.warn('Failed to validate AppCheck token.', err);
364
- return 'INVALID';
359
+ logger.warn("Failed to validate AppCheck token.", err);
360
+ return "INVALID";
365
361
  }
366
362
  }
367
363
  /** @internal */
@@ -369,7 +365,7 @@ function onCallHandler(options, handler) {
369
365
  const wrapped = wrapOnCallHandler(options, handler);
370
366
  return (req, res) => {
371
367
  return new Promise((resolve) => {
372
- res.on('finish', resolve);
368
+ res.on("finish", resolve);
373
369
  cors(options.cors)(req, res, () => {
374
370
  resolve(wrapped(req, res));
375
371
  });
@@ -382,24 +378,32 @@ function wrapOnCallHandler(options, handler) {
382
378
  return async (req, res) => {
383
379
  try {
384
380
  if (!isValidRequest(req)) {
385
- logger.error('Invalid request, unable to process.');
386
- throw new HttpsError('invalid-argument', 'Bad Request');
381
+ logger.error("Invalid request, unable to process.");
382
+ throw new HttpsError("invalid-argument", "Bad Request");
387
383
  }
388
384
  const context = { rawRequest: req };
389
385
  const tokenStatus = await checkTokens(req, context);
390
- if (tokenStatus.auth === 'INVALID') {
391
- throw new HttpsError('unauthenticated', 'Unauthenticated');
386
+ if (tokenStatus.auth === "INVALID") {
387
+ throw new HttpsError("unauthenticated", "Unauthenticated");
388
+ }
389
+ if (tokenStatus.app === "INVALID") {
390
+ if (options.enforceAppCheck) {
391
+ throw new HttpsError("unauthenticated", "Unauthenticated");
392
+ }
393
+ else {
394
+ logger.warn("Allowing request with invalid AppCheck token because enforcement is disabled");
395
+ }
392
396
  }
393
- if (tokenStatus.app === 'INVALID' && !options.allowInvalidAppCheckToken) {
394
- throw new HttpsError('unauthenticated', 'Unauthenticated');
397
+ if (tokenStatus.app === "MISSING" && options.enforceAppCheck) {
398
+ throw new HttpsError("unauthenticated", "Unauthenticated");
395
399
  }
396
- const instanceId = req.header('Firebase-Instance-ID-Token');
400
+ const instanceId = req.header("Firebase-Instance-ID-Token");
397
401
  if (instanceId) {
398
402
  // Validating the token requires an http request, so we don't do it.
399
403
  // If the user wants to use it for something, it will be validated then.
400
404
  // Currently, the only real use case for this token is for sending
401
405
  // pushes with FCM. In that case, the FCM APIs will validate the token.
402
- context.instanceIdToken = req.header('Firebase-Instance-ID-Token');
406
+ context.instanceIdToken = req.header("Firebase-Instance-ID-Token");
403
407
  }
404
408
  const data = decode(req.body.data);
405
409
  let result;
@@ -422,13 +426,14 @@ function wrapOnCallHandler(options, handler) {
422
426
  res.status(200).send(responseBody);
423
427
  }
424
428
  catch (err) {
429
+ let httpErr = err;
425
430
  if (!(err instanceof HttpsError)) {
426
431
  // This doesn't count as an 'explicit' error.
427
- logger.error('Unhandled error', err);
428
- err = new HttpsError('internal', 'INTERNAL');
432
+ logger.error("Unhandled error", err);
433
+ httpErr = new HttpsError("internal", "INTERNAL");
429
434
  }
430
- const { status } = err.httpErrorCode;
431
- const body = { error: err.toJSON() };
435
+ const { status } = httpErr.httpErrorCode;
436
+ const body = { error: httpErr.toJSON() };
432
437
  res.status(status).send(body);
433
438
  }
434
439
  };
@@ -1,26 +1,26 @@
1
- import * as firebase from 'firebase-admin';
2
- import { EventContext } from '../../cloud-functions';
3
- import { HttpsError } from './https';
1
+ import * as auth from "firebase-admin/auth";
2
+ import { EventContext } from "../../v1/cloud-functions";
3
+ import { HttpsError } from "./https";
4
4
  export { HttpsError };
5
5
  /**
6
6
  * Shorthand auth blocking events from GCIP.
7
7
  * @hidden
8
8
  * @alpha
9
9
  */
10
- export declare type AuthBlockingEventType = 'beforeCreate' | 'beforeSignIn';
10
+ export declare type AuthBlockingEventType = "beforeCreate" | "beforeSignIn";
11
11
  /**
12
12
  * The UserRecord passed to Cloud Functions is the same UserRecord that is returned by the Firebase Admin
13
13
  * SDK.
14
14
  */
15
- export declare type UserRecord = firebase.auth.UserRecord;
15
+ export declare type UserRecord = auth.UserRecord;
16
16
  /**
17
17
  * UserInfo that is part of the UserRecord
18
18
  */
19
- export declare type UserInfo = firebase.auth.UserInfo;
19
+ export declare type UserInfo = auth.UserInfo;
20
20
  /**
21
21
  * Helper class to create the user metadata in a UserRecord object
22
22
  */
23
- export declare class UserRecordMetadata implements firebase.auth.UserMetadata {
23
+ export declare class UserRecordMetadata implements auth.UserMetadata {
24
24
  creationTime: string;
25
25
  lastSignInTime: string;
26
26
  constructor(creationTime: string, lastSignInTime: string);
@@ -32,7 +32,7 @@ export declare class UserRecordMetadata implements firebase.auth.UserMetadata {
32
32
  * @param wireData data sent over the wire
33
33
  * @returns an instance of UserRecord with correct toJSON functions
34
34
  */
35
- export declare function userRecordConstructor(wireData: Object): UserRecord;
35
+ export declare function userRecordConstructor(wireData: Record<string, unknown>): UserRecord;
36
36
  /**
37
37
  * User info that is part of the AuthUserRecord
38
38
  */