private async createAccount()

in packages/fxa-auth-server/lib/routes/account.ts [123:248]


  private async createAccount(options: {
    authPW: string;
    authPWVersion2?: string;
    wrapKb?: string;
    wrapKbVersion2?: string;
    clientSalt?: string;
    authSalt: string;
    email: string;
    emailCode: string;
    preVerified: boolean;
    request: AuthRequest;
    service?: string;
    userAgentString: string;
  }) {
    const {
      authPW,
      authPWVersion2,
      wrapKb,
      wrapKbVersion2,
      clientSalt,
      authSalt,
      email,
      emailCode,
      preVerified,
      request,
      service,
      userAgentString,
    } = options;

    const { password, verifyHash } = await this.createPassword(
      authPW,
      authSalt
    );

    // Handle authPWVersion2 credentials
    let password2: any | undefined = undefined;
    let verifyHashVersion2 = undefined;
    let wrapWrapKb = await random.hex(32);
    let wrapWrapKbVersion2 = undefined;
    if (authPWVersion2) {
      password2 = new this.Password(
        authPWVersion2,
        authSalt,
        this.config.verifierVersion
      );
      verifyHashVersion2 = await password2?.verifyHash();
      wrapWrapKbVersion2 = await password2?.wrap(wrapKbVersion2);

      // When version 2 credentials are supplied, the wrapKb will also be supplied.
      // This is necessary to the same kB values are produced for both passwords.
      wrapWrapKb = await password.wrap(wrapKb);
    }

    const kA = await random.hex(32);

    const locale = request.app.acceptLanguage;
    if (!locale) {
      // We're seeing a surprising number of accounts created
      // without a proper locale. Log details to help debug this.
      this.log.info('account.create.emptyLocale', {
        email: email,
        locale: locale,
        agent: userAgentString,
      });
    }

    const account = await this.db.createAccount({
      uid: uuid.v4({}, Buffer.alloc(16)).toString('hex'),
      createdAt: Date.now(),
      email: email,
      emailCode: emailCode,
      emailVerified: preVerified,
      kA,
      wrapWrapKb,
      wrapWrapKbVersion2,
      accountResetToken: null,
      passwordForgotToken: null,
      authSalt: authSalt,
      clientSalt: clientSalt,
      verifierVersion: password.version,
      verifyHash: verifyHash,
      verifyHashVersion2: verifyHashVersion2,
      verifierSetAt: Date.now(),
      locale,
    });

    await request.emitMetricsEvent('account.created', {
      uid: account.uid,
    });

    this.glean.registration.accountCreated(request, {
      uid: account.uid,
    });

    const geoData = request.app.geo;
    const country = geoData.location && geoData.location.country;
    const countryCode = geoData.location && geoData.location.countryCode;
    if (account.emailVerified) {
      await this.log.notifyAttachedServices('verified', request, {
        email: account.email,
        locale: account.locale,
        service,
        uid: account.uid,
        userAgent: userAgentString,
        country,
        countryCode,
      });
    }

    await this.log.notifyAttachedServices('login', request, {
      deviceCount: 1,
      country,
      countryCode,
      email: account.email,
      service,
      uid: account.uid,
      userAgent: userAgentString,
    });

    await this.profileClient.deleteCache(account.uid);
    await this.log.notifyAttachedServices('profileDataChange', request, {
      uid: account.uid,
    });

    return { password, password2, account };
  }