FIX: make it possible to use backup code everywhere where 2FA required (#7010)

FIX: make it possible to use backup code everywhere where 2FA required (#7010)

diff --git a/app/assets/javascripts/discourse/components/second-factor-form.js.es6 b/app/assets/javascripts/discourse/components/second-factor-form.js.es6
index f930a4c..7c75b0e 100644
--- a/app/assets/javascripts/discourse/components/second-factor-form.js.es6
+++ b/app/assets/javascripts/discourse/components/second-factor-form.js.es6
@@ -16,17 +16,23 @@ export default Ember.Component.extend({
       : I18n.t("login.second_factor_backup_description");
   },
 
-  @computed("secondFactorMethod")
-  linkText(secondFactorMethod) {
-    return secondFactorMethod === SECOND_FACTOR_METHODS.TOTP
-      ? "login.second_factor_backup"
-      : "login.second_factor";
+  @computed("secondFactorMethod", "isLogin")
+  linkText(secondFactorMethod, isLogin) {
+    if (isLogin) {
+      return secondFactorMethod === SECOND_FACTOR_METHODS.TOTP
+        ? "login.second_factor_backup"
+        : "login.second_factor";
+    } else {
+      return secondFactorMethod === SECOND_FACTOR_METHODS.TOTP
+        ? "user.second_factor_backup.use"
+        : "user.second_factor.use";
+    }
   },
 
   actions: {
     toggleSecondFactorMethod() {
       const secondFactorMethod = this.get("secondFactorMethod");
-      this.set("loginSecondFactor", "");
+      this.set("secondFactorToken", "");
       if (secondFactorMethod === SECOND_FACTOR_METHODS.TOTP) {
         this.set("secondFactorMethod", SECOND_FACTOR_METHODS.BACKUP_CODE);
       } else {
diff --git a/app/assets/javascripts/discourse/controllers/login.js.es6 b/app/assets/javascripts/discourse/controllers/login.js.es6
index 34ca143..d5e6042 100644
--- a/app/assets/javascripts/discourse/controllers/login.js.es6
+++ b/app/assets/javascripts/discourse/controllers/login.js.es6
@@ -106,7 +106,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
         data: {
           login: this.get("loginName"),
           password: this.get("loginPassword"),
-          second_factor_token: this.get("loginSecondFactor"),
+          second_factor_token: this.get("secondFactorToken"),
           second_factor_method: this.get("secondFactorMethod")
         }
       }).then(
diff --git a/app/assets/javascripts/discourse/controllers/password-reset.js.es6 b/app/assets/javascripts/discourse/controllers/password-reset.js.es6
index 7e2ed24..2c74c8f 100644
--- a/app/assets/javascripts/discourse/controllers/password-reset.js.es6
+++ b/app/assets/javascripts/discourse/controllers/password-reset.js.es6
@@ -9,7 +9,7 @@ export default Ember.Controller.extend(PasswordValidation, {
   isDeveloper: Ember.computed.alias("model.is_developer"),
   admin: Ember.computed.alias("model.admin"),
   secondFactorRequired: Ember.computed.alias("model.second_factor_required"),
-  backupEnabled: Ember.computed.alias("model.second_factor_backup_enabled"),
+  backupEnabled: Ember.computed.alias("model.backup_enabled"),
   secondFactorMethod: SECOND_FACTOR_METHODS.TOTP,
   passwordRequired: true,
   errorMessage: null,
@@ -38,7 +38,7 @@ export default Ember.Controller.extend(PasswordValidation, {
         type: "PUT",
         data: {
           password: this.get("accountPassword"),
-          second_factor_token: this.get("secondFactor"),
+          second_factor_token: this.get("secondFactorToken"),
           second_factor_method: this.get("secondFactorMethod")
         }
       })
diff --git a/app/assets/javascripts/discourse/controllers/preferences/second-factor-backup.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/second-factor-backup.js.es6
index e0b703b..5f41061 100644
--- a/app/assets/javascripts/discourse/controllers/preferences/second-factor-backup.js.es6
+++ b/app/assets/javascripts/discourse/controllers/preferences/second-factor-backup.js.es6
@@ -1,6 +1,7 @@
 import { default as computed } from "ember-addons/ember-computed-decorators";
 import { default as DiscourseURL, userPath } from "discourse/lib/url";
 import { popupAjaxError } from "discourse/lib/ajax-error";
+import { SECOND_FACTOR_METHODS } from "discourse/models/user";
 
 export default Ember.Controller.extend({
   loading: false,
@@ -11,10 +12,15 @@ export default Ember.Controller.extend({
     "model.second_factor_remaining_backup_codes"
   ),
   backupCodes: null,
-
-  @computed("secondFactorToken")
-  isValidSecondFactorToken(secondFactorToken) {
-    return secondFactorToken && secondFactorToken.length === 6;
+  secondFactorMethod: SECOND_FACTOR_METHODS.TOTP,
+
+  @computed("secondFactorToken", "secondFactorMethod")
+  isValidSecondFactorToken(secondFactorToken, secondFactorMethod) {
+    if (secondFactorMethod === SECOND_FACTOR_METHODS.TOTP) {
+      return secondFactorToken && secondFactorToken.length === 6;
+    } else if (secondFactorMethod === SECOND_FACTOR_METHODS.BACKUP_CODE) {
+      return secondFactorToken && secondFactorToken.length === 16;
+    }
   },
 
   @computed("isValidSecondFactorToken", "backupEnabled", "loading")
@@ -59,7 +65,12 @@ export default Ember.Controller.extend({
       this.set("loading", true);
 
       this.get("model")
-        .toggleSecondFactor(this.get("secondFactorToken"), false, 2)
+        .toggleSecondFactor(
+          this.get("secondFactorToken"),
+          this.get("secondFactorMethod"),
+          SECOND_FACTOR_METHODS.BACKUP_CODE,
+          false
+        )
         .then(response => {
           if (response.error) {
             this.set("errorMessage", response.error);
@@ -79,7 +90,10 @@ export default Ember.Controller.extend({
       if (!this.get("secondFactorToken")) return;
       this.set("loading", true);
       this.get("model")
-        .generateSecondFactorCodes(this.get("secondFactorToken"))
+        .generateSecondFactorCodes(
+          this.get("secondFactorToken"),
+          this.get("secondFactorMethod")
+        )
         .then(response => {
           if (response.error) {
             this.set("errorMessage", response.error);
diff --git a/app/assets/javascripts/discourse/controllers/preferences/second-factor.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/second-factor.js.es6
index af6e78e..662eb31 100644
--- a/app/assets/javascripts/discourse/controllers/preferences/second-factor.js.es6
+++ b/app/assets/javascripts/discourse/controllers/preferences/second-factor.js.es6
@@ -2,6 +2,7 @@ import { default as computed } from "ember-addons/ember-computed-decorators";
 import { default as DiscourseURL, userPath } from "discourse/lib/url";
 import { popupAjaxError } from "discourse/lib/ajax-error";
 import { findAll } from "discourse/models/login-method";
+import { SECOND_FACTOR_METHODS } from "discourse/models/user";
 
 export default Ember.Controller.extend({
   loading: false,
@@ -13,6 +14,8 @@ export default Ember.Controller.extend({
   showSecondFactorKey: false,
   errorMessage: null,
   newUsername: null,
+  backupEnabled: Ember.computed.alias("model.second_factor_backup_enabled"),
+  secondFactorMethod: SECOND_FACTOR_METHODS.TOTP,
 
   loaded: Ember.computed.and("secondFactorImage", "secondFactorKey"),
 
@@ -41,7 +44,12 @@ export default Ember.Controller.extend({
     this.set("loading", true);
 
     this.get("model")
-      .toggleSecondFactor(this.get("secondFactorToken"), enable, 1)
+      .toggleSecondFactor(
+        this.get("secondFactorToken"),
+        this.get("secondFactorMethod"),
+        SECOND_FACTOR_METHODS.TOTP,
+        enable
+      )
       .then(response => {
         if (response.error) {
           this.set("errorMessage", response.error);
diff --git a/app/assets/javascripts/discourse/models/user.js.es6 b/app/assets/javascripts/discourse/models/user.js.es6
index 80572fe..428f08b 100644
--- a/app/assets/javascripts/discourse/models/user.js.es6
+++ b/app/assets/javascripts/discourse/models/user.js.es6
@@ -367,20 +367,24 @@ const User = RestModel.extend({
     });
   },
 
-  toggleSecondFactor(token, enable, method) {
+  toggleSecondFactor(authToken, authMethod, targetMethod, enable) {
     return ajax("/u/second_factor.json", {
       data: {
-        second_factor_token: token,
-        second_factor_method: method,

[... diff too long, it was truncated ...]

GitHub sha: 6f427589

1 Like

This commit has been mentioned on Discourse Meta. There might be relevant details there: