async confirmCode()

in packages/fxa-auth-server/lib/routes/recovery-phone.ts [270:431]


  async confirmCode(request: AuthRequest, isSetup: boolean) {
    const {
      id: sessionTokenId,
      uid,
      email,
    } = request.auth.credentials as SessionTokenAuthCredential;

    const { code } = request.payload as unknown as {
      code: string;
    };

    if (!email) {
      throw AppError.invalidToken();
    }

    await this.customs.checkAuthenticated(
      request,
      uid,
      'verifyRecoveryPhoneTotpCode'
    );

    let success = false;
    try {
      if (isSetup) {
        // This is the initial setup case, where a user is validating an sms
        // code on their phone for the first time. It does NOT impact the totp
        // token's database state.
        success = await this.recoveryPhoneService.confirmSetupCode(uid, code);
      } else {
        // This is a sign in attempt. This will check the code, and if valid, mark the
        // session token verified. This session will have a security level that allows
        // the user to remove totp devices.
        success = await this.recoveryPhoneService.confirmSigninCode(uid, code);

        // Mark session as verified
        if (success) {
          await this.accountManager.verifySession(
            uid,
            sessionTokenId,
            VerificationMethods.sms2fa
          );
        }
      }
    } catch (error) {
      if (error instanceof RecoveryPhoneNotEnabled) {
        throw AppError.featureNotEnabled();
      }

      if (error instanceof RecoveryNumberAlreadyExistsError) {
        throw AppError.recoveryPhoneNumberAlreadyExists();
      }

      if (error instanceof RecoveryPhoneRegistrationLimitReached) {
        throw AppError.recoveryPhoneRegistrationLimitReached();
      }

      throw AppError.backendServiceFailure(
        'RecoveryPhoneService',
        'confirmCode',
        { uid },
        error
      );
    }

    if (success) {
      await this.glean.twoStepAuthPhoneCode.complete(request);

      const account = await this.db.account(uid);
      const { acceptLanguage, geo, ua } = request.app;

      if (isSetup) {
        this.statsd.increment('account.recoveryPhone.phoneAdded.success');

        try {
          const { phoneNumber, nationalFormat } =
            // User has successfully set up a recovery phone. Give back the
            // full nationalFormat (don't strip it).
            await this.recoveryPhoneService.hasConfirmed(uid);
          await this.mailer.sendPostAddRecoveryPhoneEmail(
            account.emails,
            account,
            {
              acceptLanguage,
              maskedLastFourPhoneNumber: `••••••${this.recoveryPhoneService.stripPhoneNumber(
                phoneNumber || '',
                4
              )}`,
              timeZone: geo.timeZone,
              uaBrowser: ua.browser,
              uaBrowserVersion: ua.browserVersion,
              uaOS: ua.os,
              uaOSVersion: ua.osVersion,
              uaDeviceType: ua.deviceType,
              uid,
            }
          );

          recordSecurityEvent('account.recovery_phone_setup_complete', {
            db: this.db,
            request,
          });

          return {
            phoneNumber,
            nationalFormat,
            status: RecoveryPhoneStatus.SUCCESS,
          };
        } catch (error) {
          // log email send error but don't throw
          // user should be allowed to proceed

          this.log.trace('account.recoveryPhone.phoneAddedNotification.error', {
            error,
          });
        }
      } else {
        this.statsd.increment('account.recoveryPhone.phoneSignin.success');
        // this signals the end of the login flow
        await request.emitMetricsEvent('account.confirmed', { uid });

        recordSecurityEvent('account.recovery_phone_signin_complete', {
          db: this.db,
          request,
        });

        try {
          await this.mailer.sendPostSigninRecoveryPhoneEmail(
            account.emails,
            account,
            {
              acceptLanguage,
              timeZone: geo.timeZone,
              uaBrowser: ua.browser,
              uaBrowserVersion: ua.browserVersion,
              uaOS: ua.os,
              uaOSVersion: ua.osVersion,
              uaDeviceType: ua.deviceType,
              uid,
            }
          );
        } catch (error) {
          // log email send error but don't throw
          // user should be allowed to proceed
          this.log.trace(
            'account.recoveryPhone.phoneSigninNotification.error',
            {
              error,
            }
          );
        }
      }

      return { status: RecoveryPhoneStatus.SUCCESS };
    }

    recordSecurityEvent('account.recovery_phone_signin_failed', {
      db: this.db,
      request,
    });

    throw AppError.invalidOrExpiredOtpCode();
  }