function signUp()

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) : {}),
  };
}