signIn()

in packages/fxa-content-server/app/scripts/views/mixins/signin-mixin.js [33:144]


  signIn(account, password, options = {}) {
    if (
      !account ||
      account.isDefault() ||
      (!account.has('sessionToken') && !password)
    ) {
      return Promise.reject(AuthErrors.toError('UNEXPECTED_ERROR'));
    }

    return this.invokeBrokerMethod('beforeSignIn', account)
      .then(() => {
        // Always pass `signin` for viewName regardless of the actual view
        // because we want to log the real action that is being performed.
        // This is important for the infamous signin-from-signup feature.
        this.logFlowEvent('attempt', 'signin');

        let verificationMethod =
          account.get('verificationMethod') || VerificationMethods.EMAIL_2FA;

        // Check to see if this is an oauth client is requesting 2FA.
        // If it is, set/override the corresponding verificationMethod.
        // Login requests that ask for 2FA but don't have it setup on their account
        // will return an error.
        if (this.relier.isOAuth() && this.relier.wantsTwoStepAuthentication()) {
          verificationMethod = VerificationMethods.TOTP_2FA;
        }

        // Some brokers (e.g. Sync) hand off control of the sessionToken, and hence expect
        // each signin to generate a fresh token.  Make sure that will happen.
        if (
          account.has('sessionToken') &&
          !this.broker.hasCapability('reuseExistingSession')
        ) {
          account.discardSessionToken();
        }

        return this.user.signInAccount(account, password, this.relier, {
          // a resume token is passed in to allow
          // unverified account or session users to complete
          // email verification.
          resume: this.getStringifiedResumeToken(account),
          unblockCode: options.unblockCode,
          verificationMethod: verificationMethod,
        });
      })
      .then((account) => {
        if (this.formPrefill) {
          this.formPrefill.clear();
        }

        if (this.relier.accountNeedsPermissions(account)) {
          return this.navigate('signin_permissions', {
            account: account,
            // the permissions screen will call onSubmitComplete
            // with an updated account
            onSubmitComplete: this.onSignInSuccess.bind(this),
          });
        }

        if (this.relier.shouldOfferToSync(this.viewName)) {
          // flows that are a part of the 'browser' relier which
          // do not pass a service get asked of they want to Sync

          // force_auth attempts do not a choice for Sync
          return this.navigate('would_you_like_to_sync', {
            account: account,
            // ask the user if they want to sync, but don't ask to specify data choices via CWTS
            // see https://github.com/mozilla/fxa/issues/3083 for details
            skipCWTS: true,
            // propagate the onSubmitComplete to choose_what_to_sync screen if needed
            onSubmitComplete: this.onSignInSuccess.bind(this),
          });
        }

        if (typeof options.onSuccess === 'function') {
          options.onSuccess();
        }

        return this.onSignInSuccess(account);
      })
      .catch((err) => {
        if (
          AuthErrors.is(err, 'THROTTLED') ||
          AuthErrors.is(err, 'REQUEST_BLOCKED')
        ) {
          return this.onSignInBlocked(account, password, err);
        }

        if (
          AuthErrors.is(err, 'EMAIL_HARD_BOUNCE') ||
          AuthErrors.is(err, 'EMAIL_SENT_COMPLAINT')
        ) {
          return this.navigate('signin_bounced', {
            email: account.get('email'),
          });
        }

        if (
          AuthErrors.is(err, 'TOTP_REQUIRED') ||
          AuthErrors.is(err, 'INSUFFICIENT_ACR_VALUES') ||
          OAuthErrors.is(err, 'MISMATCH_ACR_VALUES')
        ) {
          return this.navigate('inline_totp_setup', {
            account: account,
            onSubmitComplete: this.onSignInSuccess.bind(this),
          });
        }

        // re-throw error, it'll be handled elsewhere.
        throw err;
      });
  },