diff --git a/app/assets/javascripts/discourse/app/routes/application.js b/app/assets/javascripts/discourse/app/routes/application.js index 076c5979560..5a12117a151 100644 --- a/app/assets/javascripts/discourse/app/routes/application.js +++ b/app/assets/javascripts/discourse/app/routes/application.js @@ -47,6 +47,7 @@ const ApplicationRoute = DiscourseRoute.extend({ router: service(), site: service(), siteSettings: service(), + restrictedRouting: service(), get isOnlyOneExternalLoginMethod() { return ( @@ -68,6 +69,19 @@ const ApplicationRoute = DiscourseRoute.extend({ return false; }, + @action + willTransition(transition) { + if ( + this.restrictedRouting.isRestricted && + !this.restrictedRouting.isAllowedRoute(transition.to.name) + ) { + transition.abort(); + return false; + } + + return true; + }, + @action willResolveModel(transition) { this.historyStore.willResolveModel(transition); diff --git a/app/assets/javascripts/discourse/app/routes/preferences-profile.js b/app/assets/javascripts/discourse/app/routes/preferences-profile.js index 56d75a99c37..0ac07d167af 100644 --- a/app/assets/javascripts/discourse/app/routes/preferences-profile.js +++ b/app/assets/javascripts/discourse/app/routes/preferences-profile.js @@ -1,26 +1,7 @@ -import { action } from "@ember/object"; -import { service } from "@ember/service"; import RestrictedUserRoute from "discourse/routes/restricted-user"; export default class PreferencesProfile extends RestrictedUserRoute { - @service currentUser; - setupController(controller, model) { controller.set("model", model); } - - @action - willTransition(transition) { - super.willTransition(...arguments); - - if ( - this.currentUser?.needs_required_fields_check && - !transition?.to.name.startsWith("admin") - ) { - transition.abort(); - return false; - } - - return true; - } } diff --git a/app/assets/javascripts/discourse/app/routes/preferences-second-factor.js b/app/assets/javascripts/discourse/app/routes/preferences-second-factor.js index d6e78fafb5d..bd9dca51137 100644 --- a/app/assets/javascripts/discourse/app/routes/preferences-second-factor.js +++ b/app/assets/javascripts/discourse/app/routes/preferences-second-factor.js @@ -1,10 +1,7 @@ -import { action } from "@ember/object"; import { service } from "@ember/service"; import RestrictedUserRoute from "discourse/routes/restricted-user"; export default class PreferencesSecondFactor extends RestrictedUserRoute { - @service currentUser; - @service siteSettings; @service router; model() { @@ -33,34 +30,4 @@ export default class PreferencesSecondFactor extends RestrictedUserRoute { .catch(controller.popupAjaxError) .finally(() => controller.set("loading", false)); } - - @action - willTransition(transition) { - super.willTransition(...arguments); - - // NOTE: Matches the should_enforce_2fa? and disqualified_from_2fa_enforcement - // methods in ApplicationController. - const enforcing2fa = - (this.siteSettings.enforce_second_factor === "staff" && - this.currentUser.staff) || - this.siteSettings.enforce_second_factor === "all"; - - const disqualifiedFrom2faEnforcement = - !this.currentUser || - this.currentUser.is_anonymous || - this.currentUser.second_factor_enabled || - (!this.siteSettings.enforce_second_factor_on_external_auth && - this.currentUser.login_method === "oauth"); - - if ( - transition.targetName === "preferences.second-factor" || - disqualifiedFrom2faEnforcement || - !enforcing2fa - ) { - return true; - } - - transition.abort(); - return false; - } } diff --git a/app/assets/javascripts/discourse/app/services/restricted-routing.js b/app/assets/javascripts/discourse/app/services/restricted-routing.js new file mode 100644 index 00000000000..133308698c4 --- /dev/null +++ b/app/assets/javascripts/discourse/app/services/restricted-routing.js @@ -0,0 +1,62 @@ +import Service, { inject as service } from "@ember/service"; + +export default class RestrictedRouting extends Service { + @service currentUser; + @service siteSettings; + + get isRestricted() { + return this._needsRequiredFields || this._needs2fa; + } + + isAllowedRoute(path) { + const alwaysAllowed = ["faq", "about", "tos", "privacy"]; + + if (alwaysAllowed.includes(path)) { + return true; + } + + if (this._needs2fa) { + if (path === "preferences.second-factor") { + return true; + } + + return false; + } + + if (this._needsRequiredFields) { + if (path.startsWith("admin")) { + return true; + } + + if (path === "preferences.profile") { + return true; + } + + return false; + } + + return true; + } + + get _needs2fa() { + // NOTE: Matches the should_enforce_2fa? and disqualified_from_2fa_enforcement + // methods in ApplicationController. + const enforcing2fa = + (this.siteSettings.enforce_second_factor === "staff" && + this.currentUser.staff) || + this.siteSettings.enforce_second_factor === "all"; + + const exemptedFrom2faEnforcement = + !this.currentUser || + this.currentUser.is_anonymous || + this.currentUser.second_factor_enabled || + (!this.siteSettings.enforce_second_factor_on_external_auth && + this.currentUser.login_method === "oauth"); + + return enforcing2fa && !exemptedFrom2faEnforcement; + } + + get _needsRequiredFields() { + return this.currentUser?.needs_required_fields_check; + } +}