in src/emulator/auth/operations.ts [145:243]
function signUp(
state: ProjectState,
reqBody: Schemas["GoogleCloudIdentitytoolkitV1SignUpRequest"],
ctx: ExegesisContext
): Schemas["GoogleCloudIdentitytoolkitV1SignUpResponse"] {
assert(!state.disableAuth, "PROJECT_DISABLED");
assert(state.usageMode !== UsageMode.PASSTHROUGH, "UNSUPPORTED_PASSTHROUGH_OPERATION");
let provider: string | undefined;
const updates: Omit<Partial<UserInfo>, "localId" | "providerUserInfo"> = {
lastLoginAt: Date.now().toString(),
};
if (ctx.security?.Oauth2) {
// Privileged request.
if (reqBody.idToken) {
assert(!reqBody.localId, "UNEXPECTED_PARAMETER : User ID");
}
if (reqBody.localId) {
// Fail fast if localId is taken (matching production behavior).
assert(!state.getUserByLocalId(reqBody.localId), "DUPLICATE_LOCAL_ID");
}
updates.displayName = reqBody.displayName;
updates.photoUrl = reqBody.photoUrl;
updates.emailVerified = reqBody.emailVerified || false;
if (reqBody.phoneNumber) {
assert(isValidPhoneNumber(reqBody.phoneNumber), "INVALID_PHONE_NUMBER : Invalid format.");
assert(!state.getUserByPhoneNumber(reqBody.phoneNumber), "PHONE_NUMBER_EXISTS");
updates.phoneNumber = reqBody.phoneNumber;
}
if (reqBody.disabled) {
updates.disabled = true;
}
} else {
assert(!reqBody.localId, "UNEXPECTED_PARAMETER : User ID");
if (reqBody.idToken || reqBody.password || reqBody.email) {
// Creating / linking email password account.
updates.displayName = reqBody.displayName;
updates.emailVerified = false;
assert(reqBody.email, "MISSING_EMAIL");
assert(reqBody.password, "MISSING_PASSWORD");
provider = PROVIDER_PASSWORD;
assert(state.allowPasswordSignup, "OPERATION_NOT_ALLOWED");
} else {
// Most attributes are ignored when creating anon user without privilege.
provider = PROVIDER_ANONYMOUS;
assert(state.enableAnonymousUser, "ADMIN_ONLY_OPERATION");
}
}
if (reqBody.email) {
assert(isValidEmailAddress(reqBody.email), "INVALID_EMAIL");
const email = canonicalizeEmailAddress(reqBody.email);
assert(!state.getUserByEmail(email), "EMAIL_EXISTS");
updates.email = email;
}
if (reqBody.password) {
assert(
reqBody.password.length >= PASSWORD_MIN_LENGTH,
`WEAK_PASSWORD : Password should be at least ${PASSWORD_MIN_LENGTH} characters`
);
updates.salt = "fakeSalt" + randomId(20);
updates.passwordHash = hashPassword(reqBody.password, updates.salt);
updates.passwordUpdatedAt = Date.now();
updates.validSince = toUnixTimestamp(new Date()).toString();
}
if (reqBody.mfaInfo) {
updates.mfaInfo = getMfaEnrollmentsFromRequest(state, reqBody.mfaInfo, {
generateEnrollmentIds: true,
});
}
if (state instanceof TenantProjectState) {
updates.tenantId = state.tenantId;
}
let user: UserInfo | undefined;
if (reqBody.idToken) {
({ user } = parseIdToken(state, reqBody.idToken));
}
if (!user) {
if (reqBody.localId) {
user = state.createUserWithLocalId(reqBody.localId, updates);
assert(user, "DUPLICATE_LOCAL_ID");
} else {
user = state.createUser(updates);
}
} else {
user = state.updateUserByLocalId(user.localId, updates);
}
return {
kind: "identitytoolkit#SignupNewUserResponse",
localId: user.localId,
displayName: user.displayName,
email: user.email,
...(provider ? issueTokens(state, user, provider) : {}),
};
}