firebase-tools 9.19.0 → 9.23.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.
- package/CHANGELOG.md +1 -3
- package/lib/api.js +3 -0
- package/lib/apiv2.js +7 -4
- package/lib/commands/crashlytics-symbols-upload.js +146 -0
- package/lib/commands/deploy.js +9 -1
- package/lib/commands/ext-configure.js +3 -1
- package/lib/commands/ext-dev-deprecate.js +63 -0
- package/lib/commands/ext-dev-undeprecate.js +56 -0
- package/lib/commands/ext-dev-unpublish.js +10 -3
- package/lib/commands/ext-export.js +44 -0
- package/lib/commands/ext-install.js +24 -3
- package/lib/commands/ext-uninstall.js +6 -0
- package/lib/commands/ext-update.js +10 -3
- package/lib/commands/functions-config-export.js +115 -0
- package/lib/commands/functions-delete.js +47 -25
- package/lib/commands/functions-list.js +12 -12
- package/lib/commands/index.js +9 -0
- package/lib/commands/init.js +3 -0
- package/lib/config.js +3 -2
- package/lib/deploy/extensions/args.js +2 -0
- package/lib/deploy/extensions/deploy.js +49 -0
- package/lib/deploy/extensions/deploymentSummary.js +52 -0
- package/lib/deploy/extensions/errors.js +31 -0
- package/lib/deploy/extensions/index.js +8 -0
- package/lib/deploy/extensions/params.js +39 -0
- package/lib/deploy/extensions/planner.js +94 -0
- package/lib/deploy/extensions/prepare.js +111 -0
- package/lib/deploy/extensions/release.js +43 -0
- package/lib/deploy/extensions/secrets.js +150 -0
- package/lib/deploy/extensions/tasks.js +98 -0
- package/lib/deploy/extensions/validate.js +17 -0
- package/lib/deploy/functions/backend.js +93 -115
- package/lib/deploy/functions/checkIam.js +8 -8
- package/lib/deploy/functions/containerCleaner.js +71 -14
- package/lib/deploy/functions/deploy.js +4 -10
- package/lib/deploy/functions/functionsDeployHelper.js +3 -68
- package/lib/deploy/functions/prepare.js +63 -27
- package/lib/deploy/functions/pricing.js +17 -17
- package/lib/deploy/functions/prompts.js +22 -21
- package/lib/deploy/functions/release/executor.js +39 -0
- package/lib/deploy/functions/release/fabricator.js +422 -0
- package/lib/deploy/functions/release/index.js +73 -0
- package/lib/deploy/functions/release/planner.js +162 -0
- package/lib/deploy/functions/release/reporter.js +165 -0
- package/lib/deploy/functions/release/sourceTokenScraper.js +28 -0
- package/lib/deploy/functions/release/timer.js +14 -0
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +129 -126
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +41 -45
- package/lib/deploy/functions/triggerRegionHelper.js +40 -0
- package/lib/deploy/functions/validate.js +1 -24
- package/lib/deploy/index.js +10 -1
- package/lib/downloadUtils.js +37 -0
- package/lib/emulator/auth/apiSpec.js +549 -6
- package/lib/emulator/auth/handlers.js +4 -3
- package/lib/emulator/auth/operations.js +154 -14
- package/lib/emulator/auth/server.js +26 -15
- package/lib/emulator/auth/state.js +151 -13
- package/lib/emulator/download.js +2 -31
- package/lib/emulator/downloadableEmulators.js +7 -7
- package/lib/emulator/functionsEmulator.js +18 -4
- package/lib/emulator/functionsEmulatorRuntime.js +29 -7
- package/lib/emulator/storage/cloudFunctions.js +37 -7
- package/lib/extensions/askUserForConsent.js +14 -1
- package/lib/extensions/askUserForParam.js +81 -4
- package/lib/extensions/checkProjectBilling.js +7 -7
- package/lib/extensions/export.js +107 -0
- package/lib/extensions/extensionsApi.js +104 -21
- package/lib/extensions/extensionsHelper.js +6 -2
- package/lib/extensions/listExtensions.js +16 -11
- package/lib/extensions/paramHelper.js +9 -6
- package/lib/extensions/provisioningHelper.js +16 -3
- package/lib/extensions/refs.js +9 -1
- package/lib/extensions/secretsUtils.js +59 -0
- package/lib/extensions/updateHelper.js +12 -2
- package/lib/extensions/versionHelper.js +14 -0
- package/lib/extensions/warnings.js +33 -1
- package/lib/functional.js +8 -1
- package/lib/functions/env.js +10 -4
- package/lib/functions/runtimeConfigExport.js +137 -0
- package/lib/gcp/artifactregistry.js +16 -0
- package/lib/gcp/cloudfunctions.js +20 -74
- package/lib/gcp/cloudfunctionsv2.js +12 -90
- package/lib/gcp/cloudscheduler.js +22 -16
- package/lib/gcp/cloudtasks.js +143 -0
- package/lib/gcp/docker.js +7 -1
- package/lib/gcp/proto.js +2 -2
- package/lib/gcp/pubsub.js +1 -9
- package/lib/gcp/secretManager.js +132 -0
- package/lib/gcp/storage.js +16 -0
- package/lib/projectUtils.js +10 -1
- package/lib/requireInteractive.js +12 -0
- package/lib/utils.js +30 -1
- package/package.json +5 -4
- package/schema/firebase-config.json +9 -0
- package/lib/deploy/functions/deploymentPlanner.js +0 -113
- package/lib/deploy/functions/deploymentTimer.js +0 -23
- package/lib/deploy/functions/errorHandler.js +0 -75
- package/lib/deploy/functions/release.js +0 -116
- package/lib/deploy/functions/tasks.js +0 -324
- package/lib/functions/listFunctions.js +0 -10
- package/lib/functionsDelete.js +0 -60
|
@@ -7,7 +7,7 @@ const errors_1 = require("./errors");
|
|
|
7
7
|
const widget_ui_1 = require("./widget_ui");
|
|
8
8
|
function registerHandlers(app, getProjectStateByApiKey) {
|
|
9
9
|
app.get(`/emulator/action`, (req, res) => {
|
|
10
|
-
const { mode, oobCode, continueUrl, apiKey } = req.query;
|
|
10
|
+
const { mode, oobCode, continueUrl, apiKey, tenantId } = req.query;
|
|
11
11
|
if (!apiKey) {
|
|
12
12
|
return res.status(400).json({
|
|
13
13
|
authEmulator: {
|
|
@@ -24,7 +24,7 @@ function registerHandlers(app, getProjectStateByApiKey) {
|
|
|
24
24
|
},
|
|
25
25
|
});
|
|
26
26
|
}
|
|
27
|
-
const state = getProjectStateByApiKey(apiKey);
|
|
27
|
+
const state = getProjectStateByApiKey(apiKey, tenantId);
|
|
28
28
|
switch (mode) {
|
|
29
29
|
case "recoverEmail": {
|
|
30
30
|
const oob = state.validateOobCode(oobCode);
|
|
@@ -159,6 +159,7 @@ function registerHandlers(app, getProjectStateByApiKey) {
|
|
|
159
159
|
res.set("Content-Type", "text/html; charset=utf-8");
|
|
160
160
|
const apiKey = req.query.apiKey;
|
|
161
161
|
const providerId = req.query.providerId;
|
|
162
|
+
const tenantId = req.query.tenantId;
|
|
162
163
|
if (!apiKey || !providerId) {
|
|
163
164
|
return res.status(400).json({
|
|
164
165
|
authEmulator: {
|
|
@@ -166,7 +167,7 @@ function registerHandlers(app, getProjectStateByApiKey) {
|
|
|
166
167
|
},
|
|
167
168
|
});
|
|
168
169
|
}
|
|
169
|
-
const state = getProjectStateByApiKey(apiKey);
|
|
170
|
+
const state = getProjectStateByApiKey(apiKey, tenantId);
|
|
170
171
|
const providerInfos = state.listProviderInfosByProviderId(providerId);
|
|
171
172
|
const options = providerInfos
|
|
172
173
|
.map((info) => `<li class="js-reuse-account mdc-list-item mdc-ripple-upgraded" tabindex="0" data-id-token="${encodeURIComponent(createFakeClaims(info))}">
|
|
@@ -50,6 +50,25 @@ exports.authOperations = {
|
|
|
50
50
|
batchDelete,
|
|
51
51
|
batchGet,
|
|
52
52
|
},
|
|
53
|
+
tenants: {
|
|
54
|
+
create: createTenant,
|
|
55
|
+
delete: deleteTenant,
|
|
56
|
+
get: getTenant,
|
|
57
|
+
list: listTenants,
|
|
58
|
+
patch: updateTenant,
|
|
59
|
+
createSessionCookie,
|
|
60
|
+
accounts: {
|
|
61
|
+
_: signUp,
|
|
62
|
+
batchCreate,
|
|
63
|
+
batchDelete,
|
|
64
|
+
batchGet,
|
|
65
|
+
delete: deleteAccount,
|
|
66
|
+
lookup,
|
|
67
|
+
query: queryAccounts,
|
|
68
|
+
sendOobCode,
|
|
69
|
+
update: setAccountInfo,
|
|
70
|
+
},
|
|
71
|
+
},
|
|
53
72
|
},
|
|
54
73
|
},
|
|
55
74
|
securetoken: {
|
|
@@ -83,6 +102,7 @@ const MFA_INELIGIBLE_PROVIDER = new Set([
|
|
|
83
102
|
]);
|
|
84
103
|
function signUp(state, reqBody, ctx) {
|
|
85
104
|
var _a;
|
|
105
|
+
errors_1.assert(!state.disableAuth, "PROJECT_DISABLED");
|
|
86
106
|
errors_1.assert(state.usageMode !== state_1.UsageMode.PASSTHROUGH, "UNSUPPORTED_PASSTHROUGH_OPERATION");
|
|
87
107
|
let provider;
|
|
88
108
|
const updates = {
|
|
@@ -115,9 +135,11 @@ function signUp(state, reqBody, ctx) {
|
|
|
115
135
|
errors_1.assert(reqBody.email, "MISSING_EMAIL");
|
|
116
136
|
errors_1.assert(reqBody.password, "MISSING_PASSWORD");
|
|
117
137
|
provider = state_1.PROVIDER_PASSWORD;
|
|
138
|
+
errors_1.assert(state.allowPasswordSignup, "OPERATION_NOT_ALLOWED");
|
|
118
139
|
}
|
|
119
140
|
else {
|
|
120
141
|
provider = state_1.PROVIDER_ANONYMOUS;
|
|
142
|
+
errors_1.assert(state.enableAnonymousUser, "ADMIN_ONLY_OPERATION");
|
|
121
143
|
}
|
|
122
144
|
}
|
|
123
145
|
if (reqBody.email) {
|
|
@@ -138,6 +160,9 @@ function signUp(state, reqBody, ctx) {
|
|
|
138
160
|
generateEnrollmentIds: true,
|
|
139
161
|
});
|
|
140
162
|
}
|
|
163
|
+
if (state instanceof state_1.TenantProjectState) {
|
|
164
|
+
updates.tenantId = state.tenantId;
|
|
165
|
+
}
|
|
141
166
|
let user;
|
|
142
167
|
if (reqBody.idToken) {
|
|
143
168
|
({ user } = parseIdToken(state, reqBody.idToken));
|
|
@@ -158,6 +183,7 @@ function signUp(state, reqBody, ctx) {
|
|
|
158
183
|
}
|
|
159
184
|
function lookup(state, reqBody, ctx) {
|
|
160
185
|
var _a, _b, _c, _d, _e;
|
|
186
|
+
errors_1.assert(!state.disableAuth, "PROJECT_DISABLED");
|
|
161
187
|
const seenLocalIds = new Set();
|
|
162
188
|
const users = [];
|
|
163
189
|
function tryAddUser(maybeUser) {
|
|
@@ -198,6 +224,7 @@ function lookup(state, reqBody, ctx) {
|
|
|
198
224
|
}
|
|
199
225
|
function batchCreate(state, reqBody) {
|
|
200
226
|
var _a, _b;
|
|
227
|
+
errors_1.assert(!state.disableAuth, "PROJECT_DISABLED");
|
|
201
228
|
errors_1.assert(state.usageMode !== state_1.UsageMode.PASSTHROUGH, "UNSUPPORTED_PASSTHROUGH_OPERATION");
|
|
202
229
|
errors_1.assert((_a = reqBody.users) === null || _a === void 0 ? void 0 : _a.length, "MISSING_USER_ACCOUNT");
|
|
203
230
|
if (reqBody.sanityCheck) {
|
|
@@ -238,6 +265,12 @@ function batchCreate(state, reqBody) {
|
|
|
238
265
|
photoUrl: userInfo.photoUrl,
|
|
239
266
|
lastLoginAt: userInfo.lastLoginAt,
|
|
240
267
|
};
|
|
268
|
+
if (userInfo.tenantId) {
|
|
269
|
+
errors_1.assert(state instanceof state_1.TenantProjectState && state.tenantId === userInfo.tenantId, "Tenant id in userInfo does not match the tenant id in request.");
|
|
270
|
+
}
|
|
271
|
+
if (state instanceof state_1.TenantProjectState) {
|
|
272
|
+
fields.tenantId = state.tenantId;
|
|
273
|
+
}
|
|
241
274
|
if (userInfo.passwordHash) {
|
|
242
275
|
fields.passwordHash = userInfo.passwordHash;
|
|
243
276
|
fields.salt = userInfo.salt;
|
|
@@ -369,6 +402,7 @@ function batchDelete(state, reqBody) {
|
|
|
369
402
|
return { errors: errors.length ? errors : undefined };
|
|
370
403
|
}
|
|
371
404
|
function batchGet(state, reqBody, ctx) {
|
|
405
|
+
errors_1.assert(!state.disableAuth, "PROJECT_DISABLED");
|
|
372
406
|
const maxResults = Math.min(Math.floor(ctx.params.query.maxResults) || 20, 1000);
|
|
373
407
|
const users = state.queryUsers({}, { sortByField: "localId", order: "ASC", startToken: ctx.params.query.nextPageToken });
|
|
374
408
|
let newPageToken = undefined;
|
|
@@ -386,6 +420,7 @@ function batchGet(state, reqBody, ctx) {
|
|
|
386
420
|
}
|
|
387
421
|
function createAuthUri(state, reqBody) {
|
|
388
422
|
var _a;
|
|
423
|
+
errors_1.assert(!state.disableAuth, "PROJECT_DISABLED");
|
|
389
424
|
errors_1.assert(state.usageMode !== state_1.UsageMode.PASSTHROUGH, "UNSUPPORTED_PASSTHROUGH_OPERATION");
|
|
390
425
|
const sessionId = reqBody.sessionId || utils_1.randomId(27);
|
|
391
426
|
if (reqBody.providerId) {
|
|
@@ -461,6 +496,7 @@ function createSessionCookie(state, reqBody, ctx) {
|
|
|
461
496
|
}
|
|
462
497
|
function deleteAccount(state, reqBody, ctx) {
|
|
463
498
|
var _a;
|
|
499
|
+
errors_1.assert(!state.disableAuth, "PROJECT_DISABLED");
|
|
464
500
|
let user;
|
|
465
501
|
if ((_a = ctx.security) === null || _a === void 0 ? void 0 : _a.Oauth2) {
|
|
466
502
|
errors_1.assert(reqBody.localId, "MISSING_LOCAL_ID");
|
|
@@ -478,6 +514,8 @@ function deleteAccount(state, reqBody, ctx) {
|
|
|
478
514
|
};
|
|
479
515
|
}
|
|
480
516
|
function getProjects(state) {
|
|
517
|
+
errors_1.assert(!state.disableAuth, "PROJECT_DISABLED");
|
|
518
|
+
errors_1.assert(state instanceof state_1.AgentProjectState, "UNSUPPORTED_TENANT_OPERATION");
|
|
481
519
|
return {
|
|
482
520
|
projectId: state.projectNumber,
|
|
483
521
|
authorizedDomains: [
|
|
@@ -485,7 +523,8 @@ function getProjects(state) {
|
|
|
485
523
|
],
|
|
486
524
|
};
|
|
487
525
|
}
|
|
488
|
-
function getRecaptchaParams() {
|
|
526
|
+
function getRecaptchaParams(state) {
|
|
527
|
+
errors_1.assert(!state.disableAuth, "PROJECT_DISABLED");
|
|
489
528
|
return {
|
|
490
529
|
kind: "identitytoolkit#GetRecaptchaParamResponse",
|
|
491
530
|
recaptchaStoken: "This-is-a-fake-token__Dont-send-this-to-the-Recaptcha-service__The-Auth-Emulator-does-not-support-Recaptcha",
|
|
@@ -494,6 +533,7 @@ function getRecaptchaParams() {
|
|
|
494
533
|
}
|
|
495
534
|
function queryAccounts(state, reqBody) {
|
|
496
535
|
var _a;
|
|
536
|
+
errors_1.assert(!state.disableAuth, "PROJECT_DISABLED");
|
|
497
537
|
if ((_a = reqBody.expression) === null || _a === void 0 ? void 0 : _a.length) {
|
|
498
538
|
throw new errors_1.NotImplementedError("expression is not implemented.");
|
|
499
539
|
}
|
|
@@ -530,7 +570,9 @@ function queryAccounts(state, reqBody) {
|
|
|
530
570
|
}
|
|
531
571
|
function resetPassword(state, reqBody) {
|
|
532
572
|
var _a;
|
|
573
|
+
errors_1.assert(!state.disableAuth, "PROJECT_DISABLED");
|
|
533
574
|
errors_1.assert(state.usageMode !== state_1.UsageMode.PASSTHROUGH, "UNSUPPORTED_PASSTHROUGH_OPERATION");
|
|
575
|
+
errors_1.assert(state.allowPasswordSignup, "PASSWORD_LOGIN_DISABLED");
|
|
534
576
|
errors_1.assert(reqBody.oobCode, "MISSING_OOB_CODE");
|
|
535
577
|
const oob = state.validateOobCode(reqBody.oobCode);
|
|
536
578
|
errors_1.assert(oob, "INVALID_OOB_CODE");
|
|
@@ -559,6 +601,7 @@ function resetPassword(state, reqBody) {
|
|
|
559
601
|
exports.resetPassword = resetPassword;
|
|
560
602
|
function sendOobCode(state, reqBody, ctx) {
|
|
561
603
|
var _a;
|
|
604
|
+
errors_1.assert(!state.disableAuth, "PROJECT_DISABLED");
|
|
562
605
|
errors_1.assert(state.usageMode !== state_1.UsageMode.PASSTHROUGH, "UNSUPPORTED_PASSTHROUGH_OPERATION");
|
|
563
606
|
errors_1.assert(reqBody.requestType && reqBody.requestType !== "OOB_REQ_TYPE_UNSPECIFIED", "MISSING_REQ_TYPE");
|
|
564
607
|
if (reqBody.returnOobLink) {
|
|
@@ -571,6 +614,7 @@ function sendOobCode(state, reqBody, ctx) {
|
|
|
571
614
|
let mode;
|
|
572
615
|
switch (reqBody.requestType) {
|
|
573
616
|
case "EMAIL_SIGNIN":
|
|
617
|
+
errors_1.assert(state.enableEmailLinkSignin, "OPERATION_NOT_ALLOWED");
|
|
574
618
|
mode = "signIn";
|
|
575
619
|
errors_1.assert(reqBody.email, "MISSING_EMAIL");
|
|
576
620
|
email = utils_1.canonicalizeEmailAddress(reqBody.email);
|
|
@@ -625,6 +669,8 @@ function sendOobCode(state, reqBody, ctx) {
|
|
|
625
669
|
}
|
|
626
670
|
function sendVerificationCode(state, reqBody) {
|
|
627
671
|
var _a;
|
|
672
|
+
errors_1.assert(!state.disableAuth, "PROJECT_DISABLED");
|
|
673
|
+
errors_1.assert(state instanceof state_1.AgentProjectState, "UNSUPPORTED_TENANT_OPERATION");
|
|
628
674
|
errors_1.assert(state.usageMode !== state_1.UsageMode.PASSTHROUGH, "UNSUPPORTED_PASSTHROUGH_OPERATION");
|
|
629
675
|
errors_1.assert(reqBody.phoneNumber && utils_1.isValidPhoneNumber(reqBody.phoneNumber), "INVALID_PHONE_NUMBER : Invalid format.");
|
|
630
676
|
const user = state.getUserByPhoneNumber(reqBody.phoneNumber);
|
|
@@ -637,6 +683,7 @@ function sendVerificationCode(state, reqBody) {
|
|
|
637
683
|
}
|
|
638
684
|
function setAccountInfo(state, reqBody, ctx) {
|
|
639
685
|
var _a;
|
|
686
|
+
errors_1.assert(!state.disableAuth, "PROJECT_DISABLED");
|
|
640
687
|
errors_1.assert(state.usageMode !== state_1.UsageMode.PASSTHROUGH, "UNSUPPORTED_PASSTHROUGH_OPERATION");
|
|
641
688
|
const url = utils_1.authEmulatorUrl(ctx.req);
|
|
642
689
|
return setAccountInfoImpl(state, reqBody, {
|
|
@@ -831,6 +878,9 @@ function createOobRecord(state, email, url, params) {
|
|
|
831
878
|
if (params.continueUrl) {
|
|
832
879
|
url.searchParams.set("continueUrl", params.continueUrl);
|
|
833
880
|
}
|
|
881
|
+
if (state instanceof state_1.TenantProjectState) {
|
|
882
|
+
url.searchParams.set("tenantId", state.tenantId);
|
|
883
|
+
}
|
|
834
884
|
return url.toString();
|
|
835
885
|
});
|
|
836
886
|
return oobRecord;
|
|
@@ -859,6 +909,7 @@ function logOobMessage(oobRecord) {
|
|
|
859
909
|
}
|
|
860
910
|
function signInWithCustomToken(state, reqBody) {
|
|
861
911
|
var _a;
|
|
912
|
+
errors_1.assert(!state.disableAuth, "PROJECT_DISABLED");
|
|
862
913
|
errors_1.assert(reqBody.token, "MISSING_CUSTOM_TOKEN");
|
|
863
914
|
let payload;
|
|
864
915
|
if (reqBody.token.startsWith("{")) {
|
|
@@ -871,6 +922,9 @@ function signInWithCustomToken(state, reqBody) {
|
|
|
871
922
|
}
|
|
872
923
|
else {
|
|
873
924
|
const decoded = jsonwebtoken_1.decode(reqBody.token, { complete: true });
|
|
925
|
+
if (state instanceof state_1.TenantProjectState) {
|
|
926
|
+
errors_1.assert((decoded === null || decoded === void 0 ? void 0 : decoded.payload.tenant_id) === state.tenantId, "TENANT_ID_MISMATCH");
|
|
927
|
+
}
|
|
874
928
|
errors_1.assert(decoded, "INVALID_CUSTOM_TOKEN : Invalid assertion format");
|
|
875
929
|
if (decoded.header.alg !== "none") {
|
|
876
930
|
emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.AUTH).log("WARN", "Received a signed custom token. Auth Emulator does not validate JWTs and IS NOT SECURE");
|
|
@@ -891,6 +945,7 @@ function signInWithCustomToken(state, reqBody) {
|
|
|
891
945
|
const updates = {
|
|
892
946
|
customAuth: true,
|
|
893
947
|
lastLoginAt: Date.now().toString(),
|
|
948
|
+
tenantId: state instanceof state_1.TenantProjectState ? state.tenantId : undefined,
|
|
894
949
|
};
|
|
895
950
|
if (user) {
|
|
896
951
|
errors_1.assert(!user.disabled, "USER_DISABLED");
|
|
@@ -906,6 +961,8 @@ function signInWithCustomToken(state, reqBody) {
|
|
|
906
961
|
}
|
|
907
962
|
function signInWithEmailLink(state, reqBody) {
|
|
908
963
|
var _a;
|
|
964
|
+
errors_1.assert(!state.disableAuth, "PROJECT_DISABLED");
|
|
965
|
+
errors_1.assert(state.enableEmailLinkSignin, "OPERATION_NOT_ALLOWED");
|
|
909
966
|
errors_1.assert(state.usageMode !== state_1.UsageMode.PASSTHROUGH, "UNSUPPORTED_PASSTHROUGH_OPERATION");
|
|
910
967
|
const userFromIdToken = reqBody.idToken ? parseIdToken(state, reqBody.idToken).user : undefined;
|
|
911
968
|
errors_1.assert(reqBody.email, "MISSING_EMAIL");
|
|
@@ -920,6 +977,9 @@ function signInWithEmailLink(state, reqBody) {
|
|
|
920
977
|
emailVerified: true,
|
|
921
978
|
emailLinkSignin: true,
|
|
922
979
|
};
|
|
980
|
+
if (state instanceof state_1.TenantProjectState) {
|
|
981
|
+
updates.tenantId = state.tenantId;
|
|
982
|
+
}
|
|
923
983
|
let user = state.getUserByEmail(email);
|
|
924
984
|
const isNewUser = !user && !userFromIdToken;
|
|
925
985
|
if (!user) {
|
|
@@ -941,7 +1001,7 @@ function signInWithEmailLink(state, reqBody) {
|
|
|
941
1001
|
localId: user.localId,
|
|
942
1002
|
isNewUser,
|
|
943
1003
|
};
|
|
944
|
-
if ((_a = user.mfaInfo) === null || _a === void 0 ? void 0 : _a.length) {
|
|
1004
|
+
if ((state.mfaConfig.state === "ENABLED" || state.mfaConfig.state === "MANDATORY") && ((_a = user.mfaInfo) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
945
1005
|
return Object.assign(Object.assign({}, response), mfaPending(state, user, state_1.PROVIDER_PASSWORD));
|
|
946
1006
|
}
|
|
947
1007
|
else {
|
|
@@ -951,6 +1011,7 @@ function signInWithEmailLink(state, reqBody) {
|
|
|
951
1011
|
}
|
|
952
1012
|
function signInWithIdp(state, reqBody) {
|
|
953
1013
|
var _a, _b;
|
|
1014
|
+
errors_1.assert(!state.disableAuth, "PROJECT_DISABLED");
|
|
954
1015
|
errors_1.assert(state.usageMode !== state_1.UsageMode.PASSTHROUGH, "UNSUPPORTED_PASSTHROUGH_OPERATION");
|
|
955
1016
|
if (reqBody.returnRefreshToken) {
|
|
956
1017
|
throw new errors_1.NotImplementedError("returnRefreshToken is not implemented yet.");
|
|
@@ -1023,7 +1084,7 @@ function signInWithIdp(state, reqBody) {
|
|
|
1023
1084
|
};
|
|
1024
1085
|
let user;
|
|
1025
1086
|
if (response.isNewUser) {
|
|
1026
|
-
user = state.createUser(Object.assign(Object.assign({}, accountUpdates.fields), { lastLoginAt: Date.now().toString(), providerUserInfo: [providerUserInfo] }));
|
|
1087
|
+
user = state.createUser(Object.assign(Object.assign({}, accountUpdates.fields), { lastLoginAt: Date.now().toString(), providerUserInfo: [providerUserInfo], tenantId: state instanceof state_1.TenantProjectState ? state.tenantId : undefined }));
|
|
1027
1088
|
response.localId = user.localId;
|
|
1028
1089
|
}
|
|
1029
1090
|
else {
|
|
@@ -1037,7 +1098,10 @@ function signInWithIdp(state, reqBody) {
|
|
|
1037
1098
|
if (user.email === response.email) {
|
|
1038
1099
|
response.emailVerified = user.emailVerified;
|
|
1039
1100
|
}
|
|
1040
|
-
if (
|
|
1101
|
+
if (state instanceof state_1.TenantProjectState) {
|
|
1102
|
+
response.tenantId = state.tenantId;
|
|
1103
|
+
}
|
|
1104
|
+
if ((state.mfaConfig.state === "ENABLED" || state.mfaConfig.state === "MANDATORY") && ((_b = user.mfaInfo) === null || _b === void 0 ? void 0 : _b.length)) {
|
|
1041
1105
|
return Object.assign(Object.assign({}, response), mfaPending(state, user, providerId));
|
|
1042
1106
|
}
|
|
1043
1107
|
else {
|
|
@@ -1047,6 +1111,8 @@ function signInWithIdp(state, reqBody) {
|
|
|
1047
1111
|
}
|
|
1048
1112
|
function signInWithPassword(state, reqBody) {
|
|
1049
1113
|
var _a;
|
|
1114
|
+
errors_1.assert(!state.disableAuth, "PROJECT_DISABLED");
|
|
1115
|
+
errors_1.assert(state.allowPasswordSignup, "PASSWORD_LOGIN_DISABLED");
|
|
1050
1116
|
errors_1.assert(state.usageMode !== state_1.UsageMode.PASSTHROUGH, "UNSUPPORTED_PASSTHROUGH_OPERATION");
|
|
1051
1117
|
errors_1.assert(reqBody.email, "MISSING_EMAIL");
|
|
1052
1118
|
errors_1.assert(reqBody.password, "MISSING_PASSWORD");
|
|
@@ -1068,7 +1134,7 @@ function signInWithPassword(state, reqBody) {
|
|
|
1068
1134
|
localId: user.localId,
|
|
1069
1135
|
email,
|
|
1070
1136
|
};
|
|
1071
|
-
if ((_a = user.mfaInfo) === null || _a === void 0 ? void 0 : _a.length) {
|
|
1137
|
+
if ((state.mfaConfig.state === "ENABLED" || state.mfaConfig.state === "MANDATORY") && ((_a = user.mfaInfo) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
1072
1138
|
return Object.assign(Object.assign({}, response), mfaPending(state, user, state_1.PROVIDER_PASSWORD));
|
|
1073
1139
|
}
|
|
1074
1140
|
else {
|
|
@@ -1078,6 +1144,8 @@ function signInWithPassword(state, reqBody) {
|
|
|
1078
1144
|
}
|
|
1079
1145
|
function signInWithPhoneNumber(state, reqBody) {
|
|
1080
1146
|
var _a;
|
|
1147
|
+
errors_1.assert(!state.disableAuth, "PROJECT_DISABLED");
|
|
1148
|
+
errors_1.assert(state instanceof state_1.AgentProjectState, "UNSUPPORTED_TENANT_OPERATION");
|
|
1081
1149
|
errors_1.assert(state.usageMode !== state_1.UsageMode.PASSTHROUGH, "UNSUPPORTED_PASSTHROUGH_OPERATION");
|
|
1082
1150
|
let phoneNumber;
|
|
1083
1151
|
if (reqBody.temporaryProof) {
|
|
@@ -1191,7 +1259,9 @@ function listVerificationCodesInProject(state) {
|
|
|
1191
1259
|
};
|
|
1192
1260
|
}
|
|
1193
1261
|
function mfaEnrollmentStart(state, reqBody) {
|
|
1194
|
-
var _a;
|
|
1262
|
+
var _a, _b;
|
|
1263
|
+
errors_1.assert(!state.disableAuth, "PROJECT_DISABLED");
|
|
1264
|
+
errors_1.assert((state.mfaConfig.state === "ENABLED" || state.mfaConfig.state === "MANDATORY") && ((_a = state.mfaConfig.enabledProviders) === null || _a === void 0 ? void 0 : _a.includes("PHONE_SMS")), "OPERATION_NOT_ALLOWED : SMS based MFA not enabled.");
|
|
1195
1265
|
errors_1.assert(reqBody.idToken, "MISSING_ID_TOKEN");
|
|
1196
1266
|
const { user, signInProvider } = parseIdToken(state, reqBody.idToken);
|
|
1197
1267
|
errors_1.assert(!MFA_INELIGIBLE_PROVIDER.has(signInProvider), "UNSUPPORTED_FIRST_FACTOR : MFA is not available for the given first factor.");
|
|
@@ -1199,7 +1269,7 @@ function mfaEnrollmentStart(state, reqBody) {
|
|
|
1199
1269
|
errors_1.assert(reqBody.phoneEnrollmentInfo, "INVALID_ARGUMENT : ((Missing phoneEnrollmentInfo.))");
|
|
1200
1270
|
const phoneNumber = reqBody.phoneEnrollmentInfo.phoneNumber;
|
|
1201
1271
|
errors_1.assert(phoneNumber && utils_1.isValidPhoneNumber(phoneNumber), "INVALID_PHONE_NUMBER : Invalid format.");
|
|
1202
|
-
errors_1.assert(!((
|
|
1272
|
+
errors_1.assert(!((_b = user.mfaInfo) === null || _b === void 0 ? void 0 : _b.some((enrollment) => enrollment.unobfuscatedPhoneInfo === phoneNumber)), "SECOND_FACTOR_EXISTS : Phone number already enrolled as second factor for this account.");
|
|
1203
1273
|
const { sessionInfo, code } = state.createVerificationCode(phoneNumber);
|
|
1204
1274
|
emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.AUTH).log("BULLET", `To enroll MFA with ${phoneNumber}, use the code ${code}.`);
|
|
1205
1275
|
return {
|
|
@@ -1209,7 +1279,9 @@ function mfaEnrollmentStart(state, reqBody) {
|
|
|
1209
1279
|
};
|
|
1210
1280
|
}
|
|
1211
1281
|
function mfaEnrollmentFinalize(state, reqBody) {
|
|
1212
|
-
var _a;
|
|
1282
|
+
var _a, _b;
|
|
1283
|
+
errors_1.assert(!state.disableAuth, "PROJECT_DISABLED");
|
|
1284
|
+
errors_1.assert((state.mfaConfig.state === "ENABLED" || state.mfaConfig.state === "MANDATORY") && ((_a = state.mfaConfig.enabledProviders) === null || _a === void 0 ? void 0 : _a.includes("PHONE_SMS")), "OPERATION_NOT_ALLOWED : SMS based MFA not enabled.");
|
|
1213
1285
|
errors_1.assert(reqBody.idToken, "MISSING_ID_TOKEN");
|
|
1214
1286
|
let { user, signInProvider } = parseIdToken(state, reqBody.idToken);
|
|
1215
1287
|
errors_1.assert(!MFA_INELIGIBLE_PROVIDER.has(signInProvider), "UNSUPPORTED_FIRST_FACTOR : MFA is not available for the given first factor.");
|
|
@@ -1221,7 +1293,7 @@ function mfaEnrollmentFinalize(state, reqBody) {
|
|
|
1221
1293
|
errors_1.assert(code, "MISSING_CODE");
|
|
1222
1294
|
errors_1.assert(sessionInfo, "MISSING_SESSION_INFO");
|
|
1223
1295
|
const phoneNumber = verifyPhoneNumber(state, sessionInfo, code);
|
|
1224
|
-
errors_1.assert(!((
|
|
1296
|
+
errors_1.assert(!((_b = user.mfaInfo) === null || _b === void 0 ? void 0 : _b.some((enrollment) => enrollment.unobfuscatedPhoneInfo === phoneNumber)), "SECOND_FACTOR_EXISTS : Phone number already enrolled as second factor for this account.");
|
|
1225
1297
|
const existingFactors = user.mfaInfo || [];
|
|
1226
1298
|
const existingIds = new Set();
|
|
1227
1299
|
for (const { mfaEnrollmentId } of existingFactors) {
|
|
@@ -1248,6 +1320,7 @@ function mfaEnrollmentFinalize(state, reqBody) {
|
|
|
1248
1320
|
};
|
|
1249
1321
|
}
|
|
1250
1322
|
function mfaEnrollmentWithdraw(state, reqBody) {
|
|
1323
|
+
errors_1.assert(!state.disableAuth, "PROJECT_DISABLED");
|
|
1251
1324
|
errors_1.assert(reqBody.idToken, "MISSING_ID_TOKEN");
|
|
1252
1325
|
let { user, signInProvider } = parseIdToken(state, reqBody.idToken);
|
|
1253
1326
|
errors_1.assert(user.mfaInfo, "MFA_ENROLLMENT_NOT_FOUND");
|
|
@@ -1257,11 +1330,13 @@ function mfaEnrollmentWithdraw(state, reqBody) {
|
|
|
1257
1330
|
return Object.assign({}, issueTokens(state, user, signInProvider));
|
|
1258
1331
|
}
|
|
1259
1332
|
function mfaSignInStart(state, reqBody) {
|
|
1260
|
-
var _a;
|
|
1333
|
+
var _a, _b;
|
|
1334
|
+
errors_1.assert(!state.disableAuth, "PROJECT_DISABLED");
|
|
1335
|
+
errors_1.assert((state.mfaConfig.state === "ENABLED" || state.mfaConfig.state === "MANDATORY") && ((_a = state.mfaConfig.enabledProviders) === null || _a === void 0 ? void 0 : _a.includes("PHONE_SMS")), "OPERATION_NOT_ALLOWED : SMS based MFA not enabled.");
|
|
1261
1336
|
errors_1.assert(reqBody.mfaPendingCredential, "MISSING_MFA_PENDING_CREDENTIAL : Request does not have MFA pending credential.");
|
|
1262
1337
|
errors_1.assert(reqBody.mfaEnrollmentId, "MISSING_MFA_ENROLLMENT_ID : No second factor identifier is provided.");
|
|
1263
1338
|
const { user } = parsePendingCredential(state, reqBody.mfaPendingCredential);
|
|
1264
|
-
const enrollment = (
|
|
1339
|
+
const enrollment = (_b = user.mfaInfo) === null || _b === void 0 ? void 0 : _b.find((factor) => factor.mfaEnrollmentId === reqBody.mfaEnrollmentId);
|
|
1265
1340
|
errors_1.assert(enrollment, "MFA_ENROLLMENT_NOT_FOUND");
|
|
1266
1341
|
const phoneNumber = enrollment.unobfuscatedPhoneInfo;
|
|
1267
1342
|
errors_1.assert(phoneNumber, "INVALID_ARGUMENT : MFA provider not supported!");
|
|
@@ -1274,7 +1349,9 @@ function mfaSignInStart(state, reqBody) {
|
|
|
1274
1349
|
};
|
|
1275
1350
|
}
|
|
1276
1351
|
function mfaSignInFinalize(state, reqBody) {
|
|
1277
|
-
var _a;
|
|
1352
|
+
var _a, _b;
|
|
1353
|
+
errors_1.assert(!state.disableAuth, "PROJECT_DISABLED");
|
|
1354
|
+
errors_1.assert((state.mfaConfig.state === "ENABLED" || state.mfaConfig.state === "MANDATORY") && ((_a = state.mfaConfig.enabledProviders) === null || _a === void 0 ? void 0 : _a.includes("PHONE_SMS")), "OPERATION_NOT_ALLOWED : SMS based MFA not enabled.");
|
|
1278
1355
|
errors_1.assert(reqBody.mfaPendingCredential, "MISSING_CREDENTIAL : Please set MFA Pending Credential.");
|
|
1279
1356
|
errors_1.assert(reqBody.phoneVerificationInfo, "INVALID_ARGUMENT : MFA provider not supported!");
|
|
1280
1357
|
if (reqBody.phoneVerificationInfo.androidVerificationProof) {
|
|
@@ -1285,7 +1362,7 @@ function mfaSignInFinalize(state, reqBody) {
|
|
|
1285
1362
|
errors_1.assert(sessionInfo, "MISSING_SESSION_INFO");
|
|
1286
1363
|
const phoneNumber = verifyPhoneNumber(state, sessionInfo, code);
|
|
1287
1364
|
let { user, signInProvider } = parsePendingCredential(state, reqBody.mfaPendingCredential);
|
|
1288
|
-
const enrollment = (
|
|
1365
|
+
const enrollment = (_b = user.mfaInfo) === null || _b === void 0 ? void 0 : _b.find((enrollment) => enrollment.unobfuscatedPhoneInfo == phoneNumber);
|
|
1289
1366
|
errors_1.assert(enrollment && enrollment.mfaEnrollmentId, "MFA_ENROLLMENT_NOT_FOUND");
|
|
1290
1367
|
user = state.updateUserByLocalId(user.localId, { lastLoginAt: Date.now().toString() });
|
|
1291
1368
|
errors_1.assert(!user.disabled, "USER_DISABLED");
|
|
@@ -1317,6 +1394,7 @@ function hashPassword(password, salt) {
|
|
|
1317
1394
|
function issueTokens(state, user, signInProvider, { extraClaims, secondFactor, } = {}) {
|
|
1318
1395
|
user = state.updateUserByLocalId(user.localId, { lastRefreshAt: new Date().toISOString() });
|
|
1319
1396
|
const usageMode = state.usageMode === state_1.UsageMode.PASSTHROUGH ? "passthrough" : undefined;
|
|
1397
|
+
const tenantId = state instanceof state_1.TenantProjectState ? state.tenantId : undefined;
|
|
1320
1398
|
const expiresInSeconds = 60 * 60;
|
|
1321
1399
|
const idToken = generateJwt(user, {
|
|
1322
1400
|
projectId: state.projectId,
|
|
@@ -1325,6 +1403,7 @@ function issueTokens(state, user, signInProvider, { extraClaims, secondFactor, }
|
|
|
1325
1403
|
extraClaims,
|
|
1326
1404
|
secondFactor,
|
|
1327
1405
|
usageMode,
|
|
1406
|
+
tenantId,
|
|
1328
1407
|
});
|
|
1329
1408
|
const refreshToken = state.usageMode === state_1.UsageMode.DEFAULT
|
|
1330
1409
|
? state.createRefreshTokenFor(user, signInProvider, {
|
|
@@ -1345,6 +1424,10 @@ function parseIdToken(state, idToken) {
|
|
|
1345
1424
|
if (decoded.header.alg !== "none") {
|
|
1346
1425
|
emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.AUTH).log("WARN", "Received a signed JWT. Auth Emulator does not validate JWTs and IS NOT SECURE");
|
|
1347
1426
|
}
|
|
1427
|
+
if (decoded.payload.firebase.tenant) {
|
|
1428
|
+
errors_1.assert(state instanceof state_1.TenantProjectState, "((Parsed token that belongs to tenant in a non-tenant project.))");
|
|
1429
|
+
errors_1.assert(decoded.payload.firebase.tenant === state.tenantId, "TENANT_ID_MISMATCH");
|
|
1430
|
+
}
|
|
1348
1431
|
const user = state.getUserByLocalId(decoded.payload.user_id);
|
|
1349
1432
|
errors_1.assert(user, "USER_NOT_FOUND");
|
|
1350
1433
|
errors_1.assert(!user.validSince || decoded.payload.iat >= Number(user.validSince), "TOKEN_EXPIRED");
|
|
@@ -1352,7 +1435,7 @@ function parseIdToken(state, idToken) {
|
|
|
1352
1435
|
const signInProvider = decoded.payload.firebase.sign_in_provider;
|
|
1353
1436
|
return { user, signInProvider, payload: decoded.payload };
|
|
1354
1437
|
}
|
|
1355
|
-
function generateJwt(user, { projectId, signInProvider, expiresInSeconds, extraClaims = {}, secondFactor, usageMode, }) {
|
|
1438
|
+
function generateJwt(user, { projectId, signInProvider, expiresInSeconds, extraClaims = {}, secondFactor, usageMode, tenantId, }) {
|
|
1356
1439
|
const identities = {};
|
|
1357
1440
|
if (user.email) {
|
|
1358
1441
|
identities["email"] = [user.email];
|
|
@@ -1375,6 +1458,7 @@ function generateJwt(user, { projectId, signInProvider, expiresInSeconds, extraC
|
|
|
1375
1458
|
second_factor_identifier: secondFactor === null || secondFactor === void 0 ? void 0 : secondFactor.identifier,
|
|
1376
1459
|
sign_in_second_factor: secondFactor === null || secondFactor === void 0 ? void 0 : secondFactor.provider,
|
|
1377
1460
|
usage_mode: usageMode,
|
|
1461
|
+
tenant: tenantId,
|
|
1378
1462
|
} });
|
|
1379
1463
|
const jwtStr = jsonwebtoken_1.sign(customPayloadFields, "", {
|
|
1380
1464
|
algorithm: "none",
|
|
@@ -1667,6 +1751,9 @@ function mfaPending(state, user, signInProvider) {
|
|
|
1667
1751
|
signInProvider,
|
|
1668
1752
|
projectId: state.projectId,
|
|
1669
1753
|
};
|
|
1754
|
+
if (state instanceof state_1.TenantProjectState) {
|
|
1755
|
+
pendingCredentialPayload.tenantId = state.tenantId;
|
|
1756
|
+
}
|
|
1670
1757
|
const mfaPendingCredential = Buffer.from(JSON.stringify(pendingCredentialPayload), "utf8").toString("base64");
|
|
1671
1758
|
return { mfaPendingCredential, mfaInfo: user.mfaInfo.map(redactMfaInfo) };
|
|
1672
1759
|
}
|
|
@@ -1704,8 +1791,61 @@ function parsePendingCredential(state, pendingCredential) {
|
|
|
1704
1791
|
}
|
|
1705
1792
|
errors_1.assert(pendingCredentialPayload._AuthEmulatorMfaPendingCredential, "((Invalid phoneVerificationInfo.mfaPendingCredential.))");
|
|
1706
1793
|
errors_1.assert(pendingCredentialPayload.projectId === state.projectId, "INVALID_PROJECT_ID : Project ID does not match MFA pending credential.");
|
|
1794
|
+
if (state instanceof state_1.TenantProjectState) {
|
|
1795
|
+
errors_1.assert(pendingCredentialPayload.tenantId === state.tenantId, "INVALID_PROJECT_ID : Project ID does not match MFA pending credential.");
|
|
1796
|
+
}
|
|
1707
1797
|
const { localId, signInProvider } = pendingCredentialPayload;
|
|
1708
1798
|
const user = state.getUserByLocalId(localId);
|
|
1709
1799
|
errors_1.assert(user, "((User in pendingCredentialPayload does not exist.))");
|
|
1710
1800
|
return { user, signInProvider };
|
|
1711
1801
|
}
|
|
1802
|
+
function createTenant(state, reqBody) {
|
|
1803
|
+
var _a, _b, _c, _d, _e;
|
|
1804
|
+
if (!(state instanceof state_1.AgentProjectState)) {
|
|
1805
|
+
throw new errors_1.InternalError("INTERNAL_ERROR: Can only create tenant in agent project", "INTERNAL");
|
|
1806
|
+
}
|
|
1807
|
+
const mfaConfig = (_a = reqBody.mfaConfig) !== null && _a !== void 0 ? _a : {};
|
|
1808
|
+
if (!("state" in mfaConfig)) {
|
|
1809
|
+
mfaConfig.state = "DISABLED";
|
|
1810
|
+
}
|
|
1811
|
+
if (!("enabledProviders" in mfaConfig)) {
|
|
1812
|
+
mfaConfig.enabledProviders = [];
|
|
1813
|
+
}
|
|
1814
|
+
const tenant = {
|
|
1815
|
+
displayName: reqBody.displayName,
|
|
1816
|
+
allowPasswordSignup: (_b = reqBody.allowPasswordSignup) !== null && _b !== void 0 ? _b : false,
|
|
1817
|
+
enableEmailLinkSignin: (_c = reqBody.enableEmailLinkSignin) !== null && _c !== void 0 ? _c : false,
|
|
1818
|
+
enableAnonymousUser: (_d = reqBody.enableAnonymousUser) !== null && _d !== void 0 ? _d : false,
|
|
1819
|
+
disableAuth: (_e = reqBody.disableAuth) !== null && _e !== void 0 ? _e : false,
|
|
1820
|
+
mfaConfig: mfaConfig,
|
|
1821
|
+
tenantId: "",
|
|
1822
|
+
};
|
|
1823
|
+
return state.createTenant(tenant);
|
|
1824
|
+
}
|
|
1825
|
+
function listTenants(state, reqBody, ctx) {
|
|
1826
|
+
errors_1.assert(state instanceof state_1.AgentProjectState, "((Can only list tenants in agent project.))");
|
|
1827
|
+
const pageSize = Math.min(Math.floor(ctx.params.query.pageSize) || 20, 1000);
|
|
1828
|
+
const tenants = state.listTenants(ctx.params.query.pageToken);
|
|
1829
|
+
let nextPageToken = undefined;
|
|
1830
|
+
if (pageSize > 0 && tenants.length >= pageSize) {
|
|
1831
|
+
tenants.length = pageSize;
|
|
1832
|
+
nextPageToken = tenants[tenants.length - 1].tenantId;
|
|
1833
|
+
}
|
|
1834
|
+
return {
|
|
1835
|
+
nextPageToken,
|
|
1836
|
+
tenants,
|
|
1837
|
+
};
|
|
1838
|
+
}
|
|
1839
|
+
function deleteTenant(state, reqBody, ctx) {
|
|
1840
|
+
errors_1.assert(state instanceof state_1.TenantProjectState, "((Can only delete tenant on tenant projects.))");
|
|
1841
|
+
state.delete();
|
|
1842
|
+
return {};
|
|
1843
|
+
}
|
|
1844
|
+
function getTenant(state, reqBody, ctx) {
|
|
1845
|
+
errors_1.assert(state instanceof state_1.TenantProjectState, "((Can only get tenant on tenant projects.))");
|
|
1846
|
+
return state.tenantConfig;
|
|
1847
|
+
}
|
|
1848
|
+
function updateTenant(state, reqBody, ctx) {
|
|
1849
|
+
errors_1.assert(state instanceof state_1.TenantProjectState, "((Can only update tenant on tenant projects.))");
|
|
1850
|
+
return state.updateTenant(reqBody, ctx.params.query.updateMask);
|
|
1851
|
+
}
|
|
@@ -17,6 +17,7 @@ const lodash_1 = require("lodash");
|
|
|
17
17
|
const handlers_1 = require("./handlers");
|
|
18
18
|
const bodyParser = require("body-parser");
|
|
19
19
|
const url_1 = require("url");
|
|
20
|
+
const jsonwebtoken_1 = require("jsonwebtoken");
|
|
20
21
|
const apiSpec = apiSpec_1.default;
|
|
21
22
|
const API_SPEC_PATH = "/emulator/openapi.json";
|
|
22
23
|
const AUTH_HEADER_PREFIX = "bearer ";
|
|
@@ -70,6 +71,10 @@ async function createApp(defaultProjectId, projectStateForId = new Map()) {
|
|
|
70
71
|
const app = express();
|
|
71
72
|
app.set("json spaces", 2);
|
|
72
73
|
app.use(cors({ origin: true }));
|
|
74
|
+
app.delete("*", (req, _, next) => {
|
|
75
|
+
delete req.headers["content-type"];
|
|
76
|
+
next();
|
|
77
|
+
});
|
|
73
78
|
app.get("/", (req, res) => {
|
|
74
79
|
return res.json({
|
|
75
80
|
authEmulator: {
|
|
@@ -83,7 +88,7 @@ async function createApp(defaultProjectId, projectStateForId = new Map()) {
|
|
|
83
88
|
res.json(specWithEmulatorServer(req.protocol, req.headers.host));
|
|
84
89
|
});
|
|
85
90
|
registerLegacyRoutes(app);
|
|
86
|
-
handlers_1.registerHandlers(app, (apiKey) => getProjectStateById(getProjectIdByApiKey(apiKey)));
|
|
91
|
+
handlers_1.registerHandlers(app, (apiKey, tenantId) => getProjectStateById(getProjectIdByApiKey(apiKey), tenantId));
|
|
87
92
|
const apiKeyAuthenticator = (ctx, info) => {
|
|
88
93
|
if (info.in !== "query") {
|
|
89
94
|
throw new Error('apiKey must be defined as in: "query" in API spec.');
|
|
@@ -169,6 +174,9 @@ async function createApp(defaultProjectId, projectStateForId = new Map()) {
|
|
|
169
174
|
"google-fieldmask"() {
|
|
170
175
|
return true;
|
|
171
176
|
},
|
|
177
|
+
"google-duration"() {
|
|
178
|
+
return true;
|
|
179
|
+
},
|
|
172
180
|
uint64() {
|
|
173
181
|
return true;
|
|
174
182
|
},
|
|
@@ -235,21 +243,15 @@ async function createApp(defaultProjectId, projectStateForId = new Map()) {
|
|
|
235
243
|
return defaultProjectId;
|
|
236
244
|
}
|
|
237
245
|
function getProjectStateById(projectId, tenantId) {
|
|
238
|
-
let
|
|
239
|
-
if (!
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
projectStateForId.set(projectId, agentProject);
|
|
246
|
+
let agentState = projectStateForId.get(projectId);
|
|
247
|
+
if (!agentState) {
|
|
248
|
+
agentState = new state_1.AgentProjectState(projectId);
|
|
249
|
+
projectStateForId.set(projectId, agentState);
|
|
243
250
|
}
|
|
244
251
|
if (!tenantId) {
|
|
245
|
-
return
|
|
252
|
+
return agentState;
|
|
246
253
|
}
|
|
247
|
-
|
|
248
|
-
if (!tenantState) {
|
|
249
|
-
tenantState = new state_1.TenantProjectState(projectId, tenantId, agentProject.state);
|
|
250
|
-
agentProject.tenantProjects.set(tenantId, tenantState);
|
|
251
|
-
}
|
|
252
|
-
return tenantState;
|
|
254
|
+
return agentState.getTenantProject(tenantId);
|
|
253
255
|
}
|
|
254
256
|
}
|
|
255
257
|
exports.createApp = createApp;
|
|
@@ -337,7 +339,7 @@ function toExegesisController(ops, getProjectStateById) {
|
|
|
337
339
|
}
|
|
338
340
|
function toExegesisOperation(operation) {
|
|
339
341
|
return (ctx) => {
|
|
340
|
-
var _a, _b, _c, _d, _e;
|
|
342
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
341
343
|
let targetProjectId = ctx.params.path.targetProjectId || ((_a = ctx.requestBody) === null || _a === void 0 ? void 0 : _a.targetProjectId);
|
|
342
344
|
if (targetProjectId) {
|
|
343
345
|
if ((_b = ctx.api.operationObject.security) === null || _b === void 0 ? void 0 : _b.some((sec) => sec.Oauth2)) {
|
|
@@ -347,10 +349,19 @@ function toExegesisController(ops, getProjectStateById) {
|
|
|
347
349
|
else {
|
|
348
350
|
targetProjectId = ctx.user;
|
|
349
351
|
}
|
|
352
|
+
let targetTenantId = undefined;
|
|
350
353
|
if (ctx.params.path.tenantId && ((_d = ctx.requestBody) === null || _d === void 0 ? void 0 : _d.tenantId)) {
|
|
351
354
|
errors_2.assert(ctx.params.path.tenantId === ctx.requestBody.tenantId, "TENANT_ID_MISMATCH");
|
|
352
355
|
}
|
|
353
|
-
|
|
356
|
+
targetTenantId = ctx.params.path.tenantId || ((_e = ctx.requestBody) === null || _e === void 0 ? void 0 : _e.tenantId);
|
|
357
|
+
if ((_f = ctx.requestBody) === null || _f === void 0 ? void 0 : _f.idToken) {
|
|
358
|
+
const idToken = (_g = ctx.requestBody) === null || _g === void 0 ? void 0 : _g.idToken;
|
|
359
|
+
const decoded = jsonwebtoken_1.decode(idToken, { complete: true });
|
|
360
|
+
if ((decoded === null || decoded === void 0 ? void 0 : decoded.payload.firebase.tenant) && targetTenantId) {
|
|
361
|
+
errors_2.assert((decoded === null || decoded === void 0 ? void 0 : decoded.payload.firebase.tenant) === targetTenantId, "TENANT_ID_MISMATCH");
|
|
362
|
+
}
|
|
363
|
+
targetTenantId = targetTenantId || (decoded === null || decoded === void 0 ? void 0 : decoded.payload.firebase.tenant);
|
|
364
|
+
}
|
|
354
365
|
return operation(getProjectStateById(targetProjectId, targetTenantId), ctx.requestBody, ctx);
|
|
355
366
|
};
|
|
356
367
|
}
|