firebase-tools 11.1.0 → 11.2.2
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/accountExporter.js +11 -4
- package/lib/accountImporter.js +5 -6
- package/lib/appdistribution/client.js +7 -9
- package/lib/auth.js +3 -5
- package/lib/checkValidTargetFilters.js +28 -18
- package/lib/commands/database-profile.js +2 -3
- package/lib/commands/database-push.js +2 -3
- package/lib/commands/database-remove.js +1 -2
- package/lib/commands/database-set.js +1 -2
- package/lib/commands/deploy.js +5 -6
- package/lib/commands/ext-dev-emulators-exec.js +1 -1
- package/lib/commands/ext-dev-emulators-start.js +1 -1
- package/lib/commands/ext-dev-list.js +6 -7
- package/lib/commands/ext-export.js +2 -0
- package/lib/commands/ext-info.js +12 -13
- package/lib/commands/ext.js +2 -3
- package/lib/commands/functions-delete.js +1 -7
- package/lib/commands/open.js +5 -6
- package/lib/commands/serve.js +3 -5
- package/lib/commands/use.js +2 -3
- package/lib/config.js +4 -3
- package/lib/deploy/database/prepare.js +2 -3
- package/lib/deploy/extensions/planner.js +1 -0
- package/lib/deploy/extensions/prepare.js +18 -1
- package/lib/deploy/extensions/release.js +4 -0
- package/lib/deploy/extensions/secrets.js +3 -3
- package/lib/deploy/functions/build.js +35 -53
- package/lib/deploy/functions/ensure.js +1 -11
- package/lib/deploy/functions/params.js +189 -0
- package/lib/deploy/functions/prepare.js +3 -13
- package/lib/deploy/functions/prepareFunctionsUpload.js +2 -3
- package/lib/deploy/functions/release/fabricator.js +0 -1
- package/lib/deploy/functions/release/index.js +1 -5
- package/lib/deploy/functions/runtimes/discovery/index.js +18 -3
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +3 -2
- package/lib/deploy/functions/runtimes/golang/index.js +2 -22
- package/lib/deploy/functions/runtimes/node/index.js +3 -7
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +2 -2
- package/lib/deploy/lifecycleHooks.js +8 -11
- package/lib/deploy/storage/prepare.js +2 -2
- package/lib/emulator/auth/index.js +1 -1
- package/lib/emulator/auth/operations.js +336 -64
- package/lib/emulator/auth/server.js +2 -2
- package/lib/emulator/auth/state.js +32 -7
- package/lib/emulator/commandUtils.js +1 -1
- package/lib/emulator/constants.js +1 -1
- package/lib/emulator/controller.js +6 -5
- package/lib/emulator/databaseEmulator.js +2 -2
- package/lib/emulator/download.js +1 -1
- package/lib/emulator/downloadableEmulators.js +6 -6
- package/lib/emulator/events/types.js +2 -3
- package/lib/emulator/firestoreEmulator.js +2 -2
- package/lib/emulator/functionsEmulator.js +36 -45
- package/lib/emulator/functionsEmulatorRuntime.js +12 -16
- package/lib/emulator/functionsEmulatorShared.js +7 -5
- package/lib/emulator/functionsRuntimeWorker.js +0 -6
- package/lib/emulator/hostingEmulator.js +1 -1
- package/lib/emulator/hub.js +1 -1
- package/lib/emulator/loggingEmulator.js +1 -1
- package/lib/emulator/pubsubEmulator.js +1 -1
- package/lib/emulator/storage/crc.js +4 -4
- package/lib/emulator/storage/index.js +1 -1
- package/lib/emulator/types.js +1 -1
- package/lib/extensions/askUserForConsent.js +1 -2
- package/lib/extensions/askUserForParam.js +15 -18
- package/lib/extensions/emulator/optionsHelper.js +4 -4
- package/lib/extensions/etags.js +28 -0
- package/lib/extensions/extensionsApi.js +1 -22
- package/lib/extensions/extensionsHelper.js +6 -6
- package/lib/extensions/listExtensions.js +9 -10
- package/lib/extensions/manifest.js +2 -2
- package/lib/extensions/resolveSource.js +11 -7
- package/lib/extensions/secretsUtils.js +3 -3
- package/lib/extensions/types.js +24 -0
- package/lib/extensions/updateHelper.js +1 -1
- package/lib/extensions/utils.js +1 -2
- package/lib/extensions/warnings.js +10 -4
- package/lib/firestore/encodeFirestoreValue.js +11 -8
- package/lib/fsAsync.js +3 -3
- package/lib/functions/env.js +5 -1
- package/lib/functionsConfig.js +18 -15
- package/lib/functionsConfigClone.js +10 -12
- package/lib/gcp/cloudfunctions.js +2 -15
- package/lib/gcp/rules.js +3 -4
- package/lib/gcp/runtimeconfig.js +2 -2
- package/lib/hosting/api.js +9 -11
- package/lib/hosting/expireUtils.js +2 -2
- package/lib/hosting/proxy.js +1 -1
- package/lib/init/features/hosting/github.js +1 -1
- package/lib/init/features/hosting/index.js +2 -2
- package/lib/localFunction.js +4 -4
- package/lib/management/projects.js +6 -7
- package/lib/previews.js +1 -1
- package/lib/profileReport.js +24 -22
- package/lib/prompt.js +1 -2
- package/lib/rc.js +12 -2
- package/lib/rulesDeploy.js +2 -2
- package/lib/serve/index.js +4 -5
- package/lib/utils.js +30 -6
- package/npm-shrinkwrap.json +2 -2
- package/package.json +10 -9
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.setAccountInfoImpl = exports.resetPassword = exports.SESSION_COOKIE_MAX_VALID_DURATION = exports.CUSTOM_TOKEN_AUDIENCE = exports.authOperations = void 0;
|
|
3
|
+
exports.parseBlockingFunctionJwt = exports.setAccountInfoImpl = exports.resetPassword = exports.SESSION_COOKIE_MAX_VALID_DURATION = exports.CUSTOM_TOKEN_AUDIENCE = exports.authOperations = void 0;
|
|
4
4
|
const url_1 = require("url");
|
|
5
5
|
const jsonwebtoken_1 = require("jsonwebtoken");
|
|
6
|
+
const node_fetch_1 = require("node-fetch");
|
|
7
|
+
const abort_controller_1 = require("abort-controller");
|
|
6
8
|
const utils_1 = require("./utils");
|
|
7
9
|
const errors_1 = require("./errors");
|
|
8
10
|
const types_1 = require("../types");
|
|
@@ -102,12 +104,13 @@ const MFA_INELIGIBLE_PROVIDER = new Set([
|
|
|
102
104
|
state_1.PROVIDER_CUSTOM,
|
|
103
105
|
state_1.PROVIDER_GAME_CENTER,
|
|
104
106
|
]);
|
|
105
|
-
function signUp(state, reqBody, ctx) {
|
|
106
|
-
var _a;
|
|
107
|
+
async function signUp(state, reqBody, ctx) {
|
|
108
|
+
var _a, _b, _c, _d;
|
|
107
109
|
(0, errors_1.assert)(!state.disableAuth, "PROJECT_DISABLED");
|
|
108
110
|
let provider;
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
+
const timestamp = new Date();
|
|
112
|
+
let updates = {
|
|
113
|
+
lastLoginAt: timestamp.getTime().toString(),
|
|
111
114
|
};
|
|
112
115
|
if ((_a = ctx.security) === null || _a === void 0 ? void 0 : _a.Oauth2) {
|
|
113
116
|
if (reqBody.idToken) {
|
|
@@ -168,19 +171,31 @@ function signUp(state, reqBody, ctx) {
|
|
|
168
171
|
if (reqBody.idToken) {
|
|
169
172
|
({ user } = parseIdToken(state, reqBody.idToken));
|
|
170
173
|
}
|
|
174
|
+
let extraClaims;
|
|
171
175
|
if (!user) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
176
|
+
updates.createdAt = timestamp.getTime().toString();
|
|
177
|
+
const localId = (_b = reqBody.localId) !== null && _b !== void 0 ? _b : state.generateLocalId();
|
|
178
|
+
if (reqBody.email && !((_c = ctx.security) === null || _c === void 0 ? void 0 : _c.Oauth2)) {
|
|
179
|
+
const userBeforeCreate = Object.assign({ localId }, updates);
|
|
180
|
+
const blockingResponse = await fetchBlockingFunction(state, state_1.BlockingFunctionEvents.BEFORE_CREATE, userBeforeCreate, { signInMethod: "password" });
|
|
181
|
+
updates = Object.assign(Object.assign({}, updates), blockingResponse.updates);
|
|
175
182
|
}
|
|
176
|
-
|
|
177
|
-
|
|
183
|
+
user = state.createUserWithLocalId(localId, updates);
|
|
184
|
+
(0, errors_1.assert)(user, "DUPLICATE_LOCAL_ID");
|
|
185
|
+
if (reqBody.email && !((_d = ctx.security) === null || _d === void 0 ? void 0 : _d.Oauth2)) {
|
|
186
|
+
if (!user.disabled) {
|
|
187
|
+
const blockingResponse = await fetchBlockingFunction(state, state_1.BlockingFunctionEvents.BEFORE_SIGN_IN, user, { signInMethod: "password" });
|
|
188
|
+
updates = blockingResponse.updates;
|
|
189
|
+
extraClaims = blockingResponse.extraClaims;
|
|
190
|
+
user = state.updateUserByLocalId(user.localId, updates);
|
|
191
|
+
}
|
|
192
|
+
(0, errors_1.assert)(!user.disabled, "USER_DISABLED");
|
|
178
193
|
}
|
|
179
194
|
}
|
|
180
195
|
else {
|
|
181
196
|
user = state.updateUserByLocalId(user.localId, updates);
|
|
182
197
|
}
|
|
183
|
-
return Object.assign({ kind: "identitytoolkit#SignupNewUserResponse", localId: user.localId, displayName: user.displayName, email: user.email }, (provider ? issueTokens(state, user, provider) : {}));
|
|
198
|
+
return Object.assign({ kind: "identitytoolkit#SignupNewUserResponse", localId: user.localId, displayName: user.displayName, email: user.email }, (provider ? issueTokens(state, user, provider, { extraClaims }) : {}));
|
|
184
199
|
}
|
|
185
200
|
function lookup(state, reqBody, ctx) {
|
|
186
201
|
var _a, _b, _c, _d, _e;
|
|
@@ -479,7 +494,7 @@ function createAuthUri(state, reqBody) {
|
|
|
479
494
|
}
|
|
480
495
|
const SESSION_COOKIE_MIN_VALID_DURATION = 5 * 60;
|
|
481
496
|
exports.SESSION_COOKIE_MAX_VALID_DURATION = 14 * 24 * 60 * 60;
|
|
482
|
-
function createSessionCookie(state, reqBody
|
|
497
|
+
function createSessionCookie(state, reqBody) {
|
|
483
498
|
(0, errors_1.assert)(reqBody.idToken, "MISSING_ID_TOKEN");
|
|
484
499
|
const validDuration = Number(reqBody.validDuration) || exports.SESSION_COOKIE_MAX_VALID_DURATION;
|
|
485
500
|
(0, errors_1.assert)(validDuration >= SESSION_COOKIE_MIN_VALID_DURATION &&
|
|
@@ -936,9 +951,10 @@ function signInWithCustomToken(state, reqBody) {
|
|
|
936
951
|
}
|
|
937
952
|
let user = state.getUserByLocalId(localId);
|
|
938
953
|
const isNewUser = !user;
|
|
954
|
+
const timestamp = new Date();
|
|
939
955
|
const updates = {
|
|
940
956
|
customAuth: true,
|
|
941
|
-
lastLoginAt:
|
|
957
|
+
lastLoginAt: timestamp.getTime().toString(),
|
|
942
958
|
tenantId: state instanceof state_1.TenantProjectState ? state.tenantId : undefined,
|
|
943
959
|
};
|
|
944
960
|
if (user) {
|
|
@@ -946,6 +962,7 @@ function signInWithCustomToken(state, reqBody) {
|
|
|
946
962
|
user = state.updateUserByLocalId(localId, updates);
|
|
947
963
|
}
|
|
948
964
|
else {
|
|
965
|
+
updates.createdAt = timestamp.getTime().toString();
|
|
949
966
|
user = state.createUserWithLocalId(localId, updates);
|
|
950
967
|
if (!user) {
|
|
951
968
|
throw new Error(`Internal assertion error: trying to create duplicate localId: ${localId}`);
|
|
@@ -953,8 +970,7 @@ function signInWithCustomToken(state, reqBody) {
|
|
|
953
970
|
}
|
|
954
971
|
return Object.assign({ kind: "identitytoolkit#VerifyCustomTokenResponse", isNewUser }, issueTokens(state, user, state_1.PROVIDER_CUSTOM, { extraClaims }));
|
|
955
972
|
}
|
|
956
|
-
function signInWithEmailLink(state, reqBody) {
|
|
957
|
-
var _a;
|
|
973
|
+
async function signInWithEmailLink(state, reqBody) {
|
|
958
974
|
(0, errors_1.assert)(!state.disableAuth, "PROJECT_DISABLED");
|
|
959
975
|
(0, errors_1.assert)(state.enableEmailLinkSignin, "OPERATION_NOT_ALLOWED");
|
|
960
976
|
const userFromIdToken = reqBody.idToken ? parseIdToken(state, reqBody.idToken).user : undefined;
|
|
@@ -965,7 +981,11 @@ function signInWithEmailLink(state, reqBody) {
|
|
|
965
981
|
(0, errors_1.assert)(oob && oob.requestType === "EMAIL_SIGNIN", "INVALID_OOB_CODE");
|
|
966
982
|
(0, errors_1.assert)(email === oob.email, "INVALID_EMAIL : The email provided does not match the sign-in email address.");
|
|
967
983
|
state.deleteOobCode(reqBody.oobCode);
|
|
968
|
-
const
|
|
984
|
+
const userFromEmail = state.getUserByEmail(email);
|
|
985
|
+
let user = userFromIdToken || userFromEmail;
|
|
986
|
+
const isNewUser = !user;
|
|
987
|
+
const timestamp = new Date();
|
|
988
|
+
let updates = {
|
|
969
989
|
email,
|
|
970
990
|
emailVerified: true,
|
|
971
991
|
emailLinkSignin: true,
|
|
@@ -973,19 +993,31 @@ function signInWithEmailLink(state, reqBody) {
|
|
|
973
993
|
if (state instanceof state_1.TenantProjectState) {
|
|
974
994
|
updates.tenantId = state.tenantId;
|
|
975
995
|
}
|
|
976
|
-
let
|
|
977
|
-
const isNewUser = !user && !userFromIdToken;
|
|
996
|
+
let extraClaims;
|
|
978
997
|
if (!user) {
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
}
|
|
982
|
-
|
|
983
|
-
|
|
998
|
+
updates.createdAt = timestamp.getTime().toString();
|
|
999
|
+
const localId = state.generateLocalId();
|
|
1000
|
+
const userBeforeCreate = Object.assign({ localId }, updates);
|
|
1001
|
+
const blockingResponse = await fetchBlockingFunction(state, state_1.BlockingFunctionEvents.BEFORE_CREATE, userBeforeCreate, { signInMethod: "emailLink" });
|
|
1002
|
+
updates = Object.assign(Object.assign({}, updates), blockingResponse.updates);
|
|
1003
|
+
user = state.createUserWithLocalId(localId, updates);
|
|
1004
|
+
if (!user.disabled && !isMfaEnabled(state, user)) {
|
|
1005
|
+
const blockingResponse = await fetchBlockingFunction(state, state_1.BlockingFunctionEvents.BEFORE_SIGN_IN, user, { signInMethod: "emailLink" });
|
|
1006
|
+
updates = blockingResponse.updates;
|
|
1007
|
+
extraClaims = blockingResponse.extraClaims;
|
|
1008
|
+
user = state.updateUserByLocalId(user.localId, updates);
|
|
984
1009
|
}
|
|
985
1010
|
}
|
|
986
1011
|
else {
|
|
987
1012
|
(0, errors_1.assert)(!user.disabled, "USER_DISABLED");
|
|
988
|
-
|
|
1013
|
+
if (userFromIdToken && userFromEmail) {
|
|
1014
|
+
(0, errors_1.assert)(userFromIdToken.localId === userFromEmail.localId, "EMAIL_EXISTS");
|
|
1015
|
+
}
|
|
1016
|
+
if (!user.disabled && !isMfaEnabled(state, user)) {
|
|
1017
|
+
const blockingResponse = await fetchBlockingFunction(state, state_1.BlockingFunctionEvents.BEFORE_SIGN_IN, Object.assign(Object.assign({}, user), updates), { signInMethod: "emailLink" });
|
|
1018
|
+
updates = Object.assign(Object.assign({}, updates), blockingResponse.updates);
|
|
1019
|
+
extraClaims = blockingResponse.extraClaims;
|
|
1020
|
+
}
|
|
989
1021
|
user = state.updateUserByLocalId(user.localId, updates);
|
|
990
1022
|
}
|
|
991
1023
|
const response = {
|
|
@@ -994,17 +1026,17 @@ function signInWithEmailLink(state, reqBody) {
|
|
|
994
1026
|
localId: user.localId,
|
|
995
1027
|
isNewUser,
|
|
996
1028
|
};
|
|
997
|
-
|
|
998
|
-
|
|
1029
|
+
(0, errors_1.assert)(!user.disabled, "USER_DISABLED");
|
|
1030
|
+
if (isMfaEnabled(state, user)) {
|
|
999
1031
|
return Object.assign(Object.assign({}, response), mfaPending(state, user, state_1.PROVIDER_PASSWORD));
|
|
1000
1032
|
}
|
|
1001
1033
|
else {
|
|
1002
1034
|
user = state.updateUserByLocalId(user.localId, { lastLoginAt: Date.now().toString() });
|
|
1003
|
-
return Object.assign(Object.assign({}, response), issueTokens(state, user, state_1.PROVIDER_PASSWORD));
|
|
1035
|
+
return Object.assign(Object.assign({}, response), issueTokens(state, user, state_1.PROVIDER_PASSWORD, { extraClaims }));
|
|
1004
1036
|
}
|
|
1005
1037
|
}
|
|
1006
|
-
function signInWithIdp(state, reqBody) {
|
|
1007
|
-
var _a, _b
|
|
1038
|
+
async function signInWithIdp(state, reqBody) {
|
|
1039
|
+
var _a, _b;
|
|
1008
1040
|
(0, errors_1.assert)(!state.disableAuth, "PROJECT_DISABLED");
|
|
1009
1041
|
if (reqBody.returnRefreshToken) {
|
|
1010
1042
|
throw new errors_1.NotImplementedError("returnRefreshToken is not implemented yet.");
|
|
@@ -1085,15 +1117,55 @@ function signInWithIdp(state, reqBody) {
|
|
|
1085
1117
|
screenName: response.screenName,
|
|
1086
1118
|
};
|
|
1087
1119
|
let user;
|
|
1120
|
+
let extraClaims;
|
|
1121
|
+
const oauthTokens = {
|
|
1122
|
+
oauthIdToken: response.oauthIdToken,
|
|
1123
|
+
oauthAccessToken: response.oauthAccessToken,
|
|
1124
|
+
oauthRefreshToken: response.oauthRefreshToken,
|
|
1125
|
+
oauthTokenSecret: response.oauthTokenSecret,
|
|
1126
|
+
oauthExpiresIn: coercePrimitiveToString(response.oauthExpireIn),
|
|
1127
|
+
};
|
|
1088
1128
|
if (response.isNewUser) {
|
|
1089
|
-
|
|
1129
|
+
let updates = Object.assign(Object.assign({}, accountUpdates.fields), { lastLoginAt: Date.now().toString(), providerUserInfo: [providerUserInfo], tenantId: state instanceof state_1.TenantProjectState ? state.tenantId : undefined });
|
|
1130
|
+
const localId = state.generateLocalId();
|
|
1131
|
+
const userBeforeCreate = Object.assign({ localId }, updates);
|
|
1132
|
+
const blockingResponse = await fetchBlockingFunction(state, state_1.BlockingFunctionEvents.BEFORE_CREATE, userBeforeCreate, {
|
|
1133
|
+
signInMethod: response.providerId,
|
|
1134
|
+
rawUserInfo: response.rawUserInfo,
|
|
1135
|
+
signInAttributes: JSON.stringify(signInAttributes),
|
|
1136
|
+
}, oauthTokens);
|
|
1137
|
+
updates = Object.assign(Object.assign({}, updates), blockingResponse.updates);
|
|
1138
|
+
user = state.createUserWithLocalId(localId, updates);
|
|
1090
1139
|
response.localId = user.localId;
|
|
1140
|
+
if (!user.disabled && !isMfaEnabled(state, user)) {
|
|
1141
|
+
const blockingResponse = await fetchBlockingFunction(state, state_1.BlockingFunctionEvents.BEFORE_SIGN_IN, user, {
|
|
1142
|
+
signInMethod: response.providerId,
|
|
1143
|
+
rawUserInfo: response.rawUserInfo,
|
|
1144
|
+
signInAttributes: JSON.stringify(signInAttributes),
|
|
1145
|
+
}, oauthTokens);
|
|
1146
|
+
updates = blockingResponse.updates;
|
|
1147
|
+
extraClaims = blockingResponse.extraClaims;
|
|
1148
|
+
user = state.updateUserByLocalId(user.localId, updates);
|
|
1149
|
+
}
|
|
1091
1150
|
}
|
|
1092
1151
|
else {
|
|
1093
1152
|
if (!response.localId) {
|
|
1094
1153
|
throw new Error("Internal assertion error: localId not set for exising user.");
|
|
1095
1154
|
}
|
|
1096
|
-
|
|
1155
|
+
const maybeUser = state.getUserByLocalId(response.localId);
|
|
1156
|
+
(0, errors_1.assert)(maybeUser, "USER_NOT_FOUND");
|
|
1157
|
+
user = maybeUser;
|
|
1158
|
+
let updates = Object.assign({}, accountUpdates.fields);
|
|
1159
|
+
if (!user.disabled && !isMfaEnabled(state, user)) {
|
|
1160
|
+
const blockingResponse = await fetchBlockingFunction(state, state_1.BlockingFunctionEvents.BEFORE_SIGN_IN, Object.assign(Object.assign({}, user), updates), {
|
|
1161
|
+
signInMethod: response.providerId,
|
|
1162
|
+
rawUserInfo: response.rawUserInfo,
|
|
1163
|
+
signInAttributes: JSON.stringify(signInAttributes),
|
|
1164
|
+
}, oauthTokens);
|
|
1165
|
+
extraClaims = blockingResponse.extraClaims;
|
|
1166
|
+
updates = Object.assign(Object.assign({}, updates), blockingResponse.updates);
|
|
1167
|
+
}
|
|
1168
|
+
user = state.updateUserByLocalId(response.localId, updates, {
|
|
1097
1169
|
upsertProviders: [providerUserInfo],
|
|
1098
1170
|
});
|
|
1099
1171
|
}
|
|
@@ -1103,17 +1175,16 @@ function signInWithIdp(state, reqBody) {
|
|
|
1103
1175
|
if (state instanceof state_1.TenantProjectState) {
|
|
1104
1176
|
response.tenantId = state.tenantId;
|
|
1105
1177
|
}
|
|
1106
|
-
if ((state
|
|
1107
|
-
((_c = user.mfaInfo) === null || _c === void 0 ? void 0 : _c.length)) {
|
|
1178
|
+
if (isMfaEnabled(state, user)) {
|
|
1108
1179
|
return Object.assign(Object.assign({}, response), mfaPending(state, user, providerId));
|
|
1109
1180
|
}
|
|
1110
1181
|
else {
|
|
1111
1182
|
user = state.updateUserByLocalId(user.localId, { lastLoginAt: Date.now().toString() });
|
|
1112
|
-
|
|
1183
|
+
(0, errors_1.assert)(!(user === null || user === void 0 ? void 0 : user.disabled), "USER_DISABLED");
|
|
1184
|
+
return Object.assign(Object.assign({}, response), issueTokens(state, user, providerId, { signInAttributes, extraClaims }));
|
|
1113
1185
|
}
|
|
1114
1186
|
}
|
|
1115
|
-
function signInWithPassword(state, reqBody) {
|
|
1116
|
-
var _a;
|
|
1187
|
+
async function signInWithPassword(state, reqBody) {
|
|
1117
1188
|
(0, errors_1.assert)(!state.disableAuth, "PROJECT_DISABLED");
|
|
1118
1189
|
(0, errors_1.assert)(state.allowPasswordSignup, "PASSWORD_LOGIN_DISABLED");
|
|
1119
1190
|
(0, errors_1.assert)(reqBody.email, "MISSING_EMAIL");
|
|
@@ -1136,16 +1207,17 @@ function signInWithPassword(state, reqBody) {
|
|
|
1136
1207
|
localId: user.localId,
|
|
1137
1208
|
email,
|
|
1138
1209
|
};
|
|
1139
|
-
if ((state
|
|
1140
|
-
((_a = user.mfaInfo) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
1210
|
+
if (isMfaEnabled(state, user)) {
|
|
1141
1211
|
return Object.assign(Object.assign({}, response), mfaPending(state, user, state_1.PROVIDER_PASSWORD));
|
|
1142
1212
|
}
|
|
1143
1213
|
else {
|
|
1144
|
-
|
|
1145
|
-
|
|
1214
|
+
const { updates, extraClaims } = await fetchBlockingFunction(state, state_1.BlockingFunctionEvents.BEFORE_SIGN_IN, user, { signInMethod: "password" });
|
|
1215
|
+
user = state.updateUserByLocalId(user.localId, Object.assign(Object.assign({}, updates), { lastLoginAt: Date.now().toString() }));
|
|
1216
|
+
(0, errors_1.assert)(!user.disabled, "USER_DISABLED");
|
|
1217
|
+
return Object.assign(Object.assign({}, response), issueTokens(state, user, state_1.PROVIDER_PASSWORD, { extraClaims }));
|
|
1146
1218
|
}
|
|
1147
1219
|
}
|
|
1148
|
-
function signInWithPhoneNumber(state, reqBody) {
|
|
1220
|
+
async function signInWithPhoneNumber(state, reqBody) {
|
|
1149
1221
|
var _a;
|
|
1150
1222
|
(0, errors_1.assert)(!state.disableAuth, "PROJECT_DISABLED");
|
|
1151
1223
|
(0, errors_1.assert)(state instanceof state_1.AgentProjectState, "UNSUPPORTED_TENANT_OPERATION");
|
|
@@ -1161,34 +1233,50 @@ function signInWithPhoneNumber(state, reqBody) {
|
|
|
1161
1233
|
(0, errors_1.assert)(reqBody.code, "MISSING_CODE");
|
|
1162
1234
|
phoneNumber = verifyPhoneNumber(state, reqBody.sessionInfo, reqBody.code);
|
|
1163
1235
|
}
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1236
|
+
const userFromPhoneNumber = state.getUserByPhoneNumber(phoneNumber);
|
|
1237
|
+
const userFromIdToken = reqBody.idToken ? parseIdToken(state, reqBody.idToken).user : undefined;
|
|
1238
|
+
if (userFromPhoneNumber && userFromIdToken) {
|
|
1239
|
+
if (userFromPhoneNumber.localId !== userFromIdToken.localId) {
|
|
1240
|
+
(0, errors_1.assert)(!reqBody.temporaryProof, "PHONE_NUMBER_EXISTS");
|
|
1241
|
+
return Object.assign({}, state.createTemporaryProof(phoneNumber));
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
let user = userFromIdToken || userFromPhoneNumber;
|
|
1245
|
+
const isNewUser = !user;
|
|
1246
|
+
const timestamp = new Date();
|
|
1247
|
+
let updates = {
|
|
1167
1248
|
phoneNumber,
|
|
1168
|
-
lastLoginAt:
|
|
1249
|
+
lastLoginAt: timestamp.getTime().toString(),
|
|
1169
1250
|
};
|
|
1170
|
-
|
|
1251
|
+
let extraClaims;
|
|
1171
1252
|
if (!user) {
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
}
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1253
|
+
updates.createdAt = timestamp.getTime().toString();
|
|
1254
|
+
const localId = state.generateLocalId();
|
|
1255
|
+
const userBeforeCreate = Object.assign({ localId }, updates);
|
|
1256
|
+
const blockingResponse = await fetchBlockingFunction(state, state_1.BlockingFunctionEvents.BEFORE_CREATE, userBeforeCreate, { signInMethod: "phone" });
|
|
1257
|
+
updates = Object.assign(Object.assign({}, updates), blockingResponse.updates);
|
|
1258
|
+
user = state.createUserWithLocalId(localId, updates);
|
|
1259
|
+
if (!user.disabled) {
|
|
1260
|
+
const blockingResponse = await fetchBlockingFunction(state, state_1.BlockingFunctionEvents.BEFORE_SIGN_IN, user, { signInMethod: "phone" });
|
|
1261
|
+
updates = blockingResponse.updates;
|
|
1262
|
+
extraClaims = blockingResponse.extraClaims;
|
|
1263
|
+
user = state.updateUserByLocalId(user.localId, updates);
|
|
1179
1264
|
}
|
|
1180
1265
|
}
|
|
1181
1266
|
else {
|
|
1182
1267
|
(0, errors_1.assert)(!user.disabled, "USER_DISABLED");
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
}
|
|
1187
|
-
|
|
1268
|
+
(0, errors_1.assert)(!((_a = user.mfaInfo) === null || _a === void 0 ? void 0 : _a.length), "UNSUPPORTED_FIRST_FACTOR : A phone number cannot be set as a first factor on an SMS based MFA user.");
|
|
1269
|
+
if (!user.disabled) {
|
|
1270
|
+
const blockingResponse = await fetchBlockingFunction(state, state_1.BlockingFunctionEvents.BEFORE_SIGN_IN, Object.assign(Object.assign({}, user), updates), { signInMethod: "phone" });
|
|
1271
|
+
updates = Object.assign(Object.assign({}, updates), blockingResponse.updates);
|
|
1272
|
+
extraClaims = blockingResponse.extraClaims;
|
|
1188
1273
|
}
|
|
1189
1274
|
user = state.updateUserByLocalId(user.localId, updates);
|
|
1190
1275
|
}
|
|
1191
|
-
|
|
1276
|
+
(0, errors_1.assert)(!(user === null || user === void 0 ? void 0 : user.disabled), "USER_DISABLED");
|
|
1277
|
+
const tokens = issueTokens(state, user, state_1.PROVIDER_PHONE, {
|
|
1278
|
+
extraClaims,
|
|
1279
|
+
});
|
|
1192
1280
|
return Object.assign({ isNewUser,
|
|
1193
1281
|
phoneNumber, localId: user.localId }, tokens);
|
|
1194
1282
|
}
|
|
@@ -1336,7 +1424,7 @@ function mfaSignInStart(state, reqBody) {
|
|
|
1336
1424
|
},
|
|
1337
1425
|
};
|
|
1338
1426
|
}
|
|
1339
|
-
function mfaSignInFinalize(state, reqBody) {
|
|
1427
|
+
async function mfaSignInFinalize(state, reqBody) {
|
|
1340
1428
|
var _a, _b;
|
|
1341
1429
|
(0, errors_1.assert)(!state.disableAuth, "PROJECT_DISABLED");
|
|
1342
1430
|
(0, errors_1.assert)((state.mfaConfig.state === "ENABLED" || state.mfaConfig.state === "MANDATORY") &&
|
|
@@ -1352,10 +1440,12 @@ function mfaSignInFinalize(state, reqBody) {
|
|
|
1352
1440
|
const phoneNumber = verifyPhoneNumber(state, sessionInfo, code);
|
|
1353
1441
|
let { user, signInProvider } = parsePendingCredential(state, reqBody.mfaPendingCredential);
|
|
1354
1442
|
const enrollment = (_b = user.mfaInfo) === null || _b === void 0 ? void 0 : _b.find((enrollment) => enrollment.unobfuscatedPhoneInfo === phoneNumber);
|
|
1443
|
+
const { updates, extraClaims } = await fetchBlockingFunction(state, state_1.BlockingFunctionEvents.BEFORE_SIGN_IN, user, { signInMethod: signInProvider, signInSecondFactor: "phone" });
|
|
1444
|
+
user = state.updateUserByLocalId(user.localId, Object.assign(Object.assign({}, updates), { lastLoginAt: Date.now().toString() }));
|
|
1355
1445
|
(0, errors_1.assert)(enrollment && enrollment.mfaEnrollmentId, "MFA_ENROLLMENT_NOT_FOUND");
|
|
1356
|
-
user = state.updateUserByLocalId(user.localId, { lastLoginAt: Date.now().toString() });
|
|
1357
1446
|
(0, errors_1.assert)(!user.disabled, "USER_DISABLED");
|
|
1358
1447
|
const { idToken, refreshToken } = issueTokens(state, user, signInProvider, {
|
|
1448
|
+
extraClaims,
|
|
1359
1449
|
secondFactor: { identifier: enrollment.mfaEnrollmentId, provider: state_1.PROVIDER_PHONE },
|
|
1360
1450
|
});
|
|
1361
1451
|
return {
|
|
@@ -1363,7 +1453,7 @@ function mfaSignInFinalize(state, reqBody) {
|
|
|
1363
1453
|
refreshToken,
|
|
1364
1454
|
};
|
|
1365
1455
|
}
|
|
1366
|
-
function getConfig(state
|
|
1456
|
+
function getConfig(state) {
|
|
1367
1457
|
(0, errors_1.assert)(state instanceof state_1.AgentProjectState, "((Can only get top-level configurations on agent projects.))");
|
|
1368
1458
|
return state.config;
|
|
1369
1459
|
}
|
|
@@ -1844,12 +1934,12 @@ function listTenants(state, reqBody, ctx) {
|
|
|
1844
1934
|
tenants,
|
|
1845
1935
|
};
|
|
1846
1936
|
}
|
|
1847
|
-
function deleteTenant(state
|
|
1937
|
+
function deleteTenant(state) {
|
|
1848
1938
|
(0, errors_1.assert)(state instanceof state_1.TenantProjectState, "((Can only delete tenant on tenant projects.))");
|
|
1849
1939
|
state.delete();
|
|
1850
1940
|
return {};
|
|
1851
1941
|
}
|
|
1852
|
-
function getTenant(state
|
|
1942
|
+
function getTenant(state) {
|
|
1853
1943
|
(0, errors_1.assert)(state instanceof state_1.TenantProjectState, "((Can only get tenant on tenant projects.))");
|
|
1854
1944
|
return state.tenantConfig;
|
|
1855
1945
|
}
|
|
@@ -1857,3 +1947,185 @@ function updateTenant(state, reqBody, ctx) {
|
|
|
1857
1947
|
(0, errors_1.assert)(state instanceof state_1.TenantProjectState, "((Can only update tenant on tenant projects.))");
|
|
1858
1948
|
return state.updateTenant(reqBody, ctx.params.query.updateMask);
|
|
1859
1949
|
}
|
|
1950
|
+
function isMfaEnabled(state, user) {
|
|
1951
|
+
var _a;
|
|
1952
|
+
return ((state.mfaConfig.state === "ENABLED" || state.mfaConfig.state === "MANDATORY") &&
|
|
1953
|
+
((_a = user.mfaInfo) === null || _a === void 0 ? void 0 : _a.length));
|
|
1954
|
+
}
|
|
1955
|
+
async function fetchBlockingFunction(state, event, user, options = {}, oauthTokens = {}, timeoutMs = 60000) {
|
|
1956
|
+
const url = state.getBlockingFunctionUri(event);
|
|
1957
|
+
if (!url) {
|
|
1958
|
+
return { updates: {} };
|
|
1959
|
+
}
|
|
1960
|
+
const jwt = generateBlockingFunctionJwt(state, event, url, timeoutMs, user, options, oauthTokens);
|
|
1961
|
+
const reqBody = {
|
|
1962
|
+
data: {
|
|
1963
|
+
jwt,
|
|
1964
|
+
},
|
|
1965
|
+
};
|
|
1966
|
+
const controller = new abort_controller_1.default();
|
|
1967
|
+
const timeout = setTimeout(() => {
|
|
1968
|
+
controller.abort();
|
|
1969
|
+
}, timeoutMs);
|
|
1970
|
+
let response;
|
|
1971
|
+
try {
|
|
1972
|
+
const res = await (0, node_fetch_1.default)(url, {
|
|
1973
|
+
method: "POST",
|
|
1974
|
+
headers: { "Content-Type": "application/json" },
|
|
1975
|
+
body: JSON.stringify(reqBody),
|
|
1976
|
+
signal: controller.signal,
|
|
1977
|
+
});
|
|
1978
|
+
const text = await res.text();
|
|
1979
|
+
(0, errors_1.assert)(res.ok, `BLOCKING_FUNCTION_ERROR_RESPONSE: ((HTTP request to ${url} returned HTTP error${res.status}: ${text}))`);
|
|
1980
|
+
response = JSON.parse(text);
|
|
1981
|
+
}
|
|
1982
|
+
catch (thrown) {
|
|
1983
|
+
const err = thrown instanceof Error ? thrown : new Error(thrown);
|
|
1984
|
+
const isAbortError = err.name.includes("AbortError");
|
|
1985
|
+
if (isAbortError) {
|
|
1986
|
+
throw new errors_1.InternalError(`BLOCKING_FUNCTION_ERROR_RESPONSE: ((Deadline exceeded making request to ${url}.))`, err.message);
|
|
1987
|
+
}
|
|
1988
|
+
throw new errors_1.InternalError(`BLOCKING_FUNCTION_ERROR_RESPONSE: ((Failed to make request to ${url}.))`, err.message);
|
|
1989
|
+
}
|
|
1990
|
+
finally {
|
|
1991
|
+
clearTimeout(timeout);
|
|
1992
|
+
}
|
|
1993
|
+
return processBlockingFunctionResponse(event, response);
|
|
1994
|
+
}
|
|
1995
|
+
function processBlockingFunctionResponse(event, response) {
|
|
1996
|
+
let extraClaims;
|
|
1997
|
+
const updates = {};
|
|
1998
|
+
if (response.userRecord) {
|
|
1999
|
+
const userRecord = response.userRecord;
|
|
2000
|
+
(0, errors_1.assert)(userRecord.updateMask, "BLOCKING_FUNCTION_ERROR_RESPONSE: ((Response UserRecord is missing updateMask.))");
|
|
2001
|
+
const mask = userRecord.updateMask;
|
|
2002
|
+
const fields = mask.split(",");
|
|
2003
|
+
for (const field of fields) {
|
|
2004
|
+
switch (field) {
|
|
2005
|
+
case "displayName":
|
|
2006
|
+
case "photoUrl":
|
|
2007
|
+
updates[field] = coercePrimitiveToString(userRecord[field]);
|
|
2008
|
+
break;
|
|
2009
|
+
case "disabled":
|
|
2010
|
+
case "emailVerified":
|
|
2011
|
+
updates[field] = !!userRecord[field];
|
|
2012
|
+
break;
|
|
2013
|
+
case "customClaims":
|
|
2014
|
+
validateSerializedCustomClaims(userRecord.customClaims);
|
|
2015
|
+
updates.customAttributes = userRecord.customClaims;
|
|
2016
|
+
break;
|
|
2017
|
+
case "sessionClaims":
|
|
2018
|
+
if (event !== state_1.BlockingFunctionEvents.BEFORE_SIGN_IN) {
|
|
2019
|
+
break;
|
|
2020
|
+
}
|
|
2021
|
+
try {
|
|
2022
|
+
extraClaims = JSON.parse(userRecord.sessionClaims);
|
|
2023
|
+
}
|
|
2024
|
+
catch (_a) {
|
|
2025
|
+
throw new errors_1.BadRequestError("BLOCKING_FUNCTION_ERROR_RESPONSE: ((Response has malformed session claims.))");
|
|
2026
|
+
}
|
|
2027
|
+
break;
|
|
2028
|
+
default:
|
|
2029
|
+
break;
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
return { updates, extraClaims };
|
|
2034
|
+
}
|
|
2035
|
+
function generateBlockingFunctionJwt(state, event, url, timeoutMs, user, options, oauthTokens) {
|
|
2036
|
+
const issuedAt = (0, utils_1.toUnixTimestamp)(new Date());
|
|
2037
|
+
const jwt = {
|
|
2038
|
+
iss: `https://securetoken.google.com/${state.projectId}`,
|
|
2039
|
+
aud: url,
|
|
2040
|
+
iat: issuedAt,
|
|
2041
|
+
exp: issuedAt + timeoutMs / 100,
|
|
2042
|
+
event_id: (0, utils_1.randomBase64UrlStr)(16),
|
|
2043
|
+
event_type: event,
|
|
2044
|
+
user_agent: "NotYetSupportedInFirebaseAuthEmulator",
|
|
2045
|
+
ip_address: "127.0.0.1",
|
|
2046
|
+
locale: "en",
|
|
2047
|
+
user_record: {
|
|
2048
|
+
uid: user.localId,
|
|
2049
|
+
email: user.email,
|
|
2050
|
+
email_verified: user.emailVerified,
|
|
2051
|
+
display_name: user.displayName,
|
|
2052
|
+
photo_url: user.photoUrl,
|
|
2053
|
+
disabled: user.disabled,
|
|
2054
|
+
phone_number: user.phoneNumber,
|
|
2055
|
+
custom_claims: user.customAttributes,
|
|
2056
|
+
},
|
|
2057
|
+
sub: user.localId,
|
|
2058
|
+
sign_in_method: options.signInMethod,
|
|
2059
|
+
sign_in_second_factor: options.signInSecondFactor,
|
|
2060
|
+
sign_in_attributes: options.signInAttributes,
|
|
2061
|
+
raw_user_info: options.rawUserInfo,
|
|
2062
|
+
};
|
|
2063
|
+
if (state instanceof state_1.TenantProjectState) {
|
|
2064
|
+
jwt.tenant_id = state.tenantId;
|
|
2065
|
+
jwt.user_record.tenant_id = state.tenantId;
|
|
2066
|
+
}
|
|
2067
|
+
const provider_data = [];
|
|
2068
|
+
if (user.providerUserInfo) {
|
|
2069
|
+
for (const providerUserInfo of user.providerUserInfo) {
|
|
2070
|
+
const provider = {
|
|
2071
|
+
provider_id: providerUserInfo.providerId,
|
|
2072
|
+
display_name: providerUserInfo.displayName,
|
|
2073
|
+
photo_url: providerUserInfo.photoUrl,
|
|
2074
|
+
email: providerUserInfo.email,
|
|
2075
|
+
uid: providerUserInfo.rawId,
|
|
2076
|
+
phone_number: providerUserInfo.phoneNumber,
|
|
2077
|
+
};
|
|
2078
|
+
provider_data.push(provider);
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
jwt.user_record.provider_data = provider_data;
|
|
2082
|
+
if (user.mfaInfo) {
|
|
2083
|
+
const enrolled_factors = [];
|
|
2084
|
+
for (const mfaEnrollment of user.mfaInfo) {
|
|
2085
|
+
if (!mfaEnrollment.mfaEnrollmentId) {
|
|
2086
|
+
continue;
|
|
2087
|
+
}
|
|
2088
|
+
const enrolledFactor = {
|
|
2089
|
+
uid: mfaEnrollment.mfaEnrollmentId,
|
|
2090
|
+
display_name: mfaEnrollment.displayName,
|
|
2091
|
+
enrollment_time: mfaEnrollment.enrolledAt,
|
|
2092
|
+
phone_number: mfaEnrollment.phoneInfo,
|
|
2093
|
+
factor_id: state_1.PROVIDER_PHONE,
|
|
2094
|
+
};
|
|
2095
|
+
enrolled_factors.push(enrolledFactor);
|
|
2096
|
+
}
|
|
2097
|
+
jwt.user_record.multi_factor = {
|
|
2098
|
+
enrolled_factors,
|
|
2099
|
+
};
|
|
2100
|
+
}
|
|
2101
|
+
if (user.lastLoginAt || user.createdAt) {
|
|
2102
|
+
jwt.user_record.metadata = {
|
|
2103
|
+
last_sign_in_time: user.lastLoginAt,
|
|
2104
|
+
creation_time: user.createdAt,
|
|
2105
|
+
};
|
|
2106
|
+
}
|
|
2107
|
+
if (state.shouldForwardCredentialToBlockingFunction("accessToken")) {
|
|
2108
|
+
jwt.oauth_access_token = oauthTokens.oauthAccessToken;
|
|
2109
|
+
jwt.oauth_token_secret = oauthTokens.oauthTokenSecret;
|
|
2110
|
+
jwt.oauth_expires_in = oauthTokens.oauthExpiresIn;
|
|
2111
|
+
}
|
|
2112
|
+
if (state.shouldForwardCredentialToBlockingFunction("idToken")) {
|
|
2113
|
+
jwt.oauth_id_token = oauthTokens.oauthIdToken;
|
|
2114
|
+
}
|
|
2115
|
+
if (state.shouldForwardCredentialToBlockingFunction("refreshToken")) {
|
|
2116
|
+
jwt.oauth_refresh_token = oauthTokens.oauthRefreshToken;
|
|
2117
|
+
}
|
|
2118
|
+
const jwtStr = (0, jsonwebtoken_1.sign)(jwt, "", {
|
|
2119
|
+
algorithm: "none",
|
|
2120
|
+
});
|
|
2121
|
+
return jwtStr;
|
|
2122
|
+
}
|
|
2123
|
+
function parseBlockingFunctionJwt(jwt) {
|
|
2124
|
+
const decoded = (0, jsonwebtoken_1.decode)(jwt, { json: true });
|
|
2125
|
+
(0, errors_1.assert)(decoded, "((Invalid blocking function jwt.))");
|
|
2126
|
+
(0, errors_1.assert)(decoded.iss, "((Invalid blocking function jwt, missing `iss` claim.))");
|
|
2127
|
+
(0, errors_1.assert)(decoded.aud, "((Invalid blocking function jwt, missing `aud` claim.))");
|
|
2128
|
+
(0, errors_1.assert)(decoded.user_record, "((Invalid blocking function jwt, missing `user_record` claim.))");
|
|
2129
|
+
return decoded;
|
|
2130
|
+
}
|
|
2131
|
+
exports.parseBlockingFunctionJwt = parseBlockingFunctionJwt;
|
|
@@ -381,12 +381,12 @@ function wrapValidateBody(pluginContext) {
|
|
|
381
381
|
if (op.validateBody && !op._authEmulatorValidateBodyWrapped) {
|
|
382
382
|
const validateBody = op.validateBody.bind(op);
|
|
383
383
|
op.validateBody = (body) => {
|
|
384
|
-
return validateAndFixRestMappingRequestBody(validateBody, body
|
|
384
|
+
return validateAndFixRestMappingRequestBody(validateBody, body);
|
|
385
385
|
};
|
|
386
386
|
op._authEmulatorValidateBodyWrapped = true;
|
|
387
387
|
}
|
|
388
388
|
}
|
|
389
|
-
function validateAndFixRestMappingRequestBody(validate, body
|
|
389
|
+
function validateAndFixRestMappingRequestBody(validate, body) {
|
|
390
390
|
var _a;
|
|
391
391
|
body = convertKeysToCamelCase(body);
|
|
392
392
|
let result;
|