diff --git a/src/public/app/widgets/type_widgets/options/multi_factor_authentication.js b/src/public/app/widgets/type_widgets/options/multi_factor_authentication.js
deleted file mode 100644
index f4f5ee365..000000000
--- a/src/public/app/widgets/type_widgets/options/multi_factor_authentication.js
+++ /dev/null
@@ -1,220 +0,0 @@
-import server from "../../../services/server.js";
-import toastService from "../../../services/toast.js";
-import OptionsWidget from "./options_widget.js";
-
-const TPL = `
-
-
What is Multi-Factor Authentication?
-
- Multi-Factor Authentication (MFA) adds an extra layer of security to your account. Instead
- of just entering a password to log in, MFA requires you to provide one or more additional
- pieces of evidence to verify your identity. This way, even if someone gets hold of your
- password, they still ca TOTP_ENABLED is not set in environment variable. Requires restart.n't access your account without the second piece of information.
- It's like adding an extra lock to your door, making it much harder for anyone else to
- break in.
-
-
-
-
OAuth/OpenID
-
OpenID is a standardized way to let you log into websites using an account from another service, like Google, to verify your identity.
-
-
- OAuth/OpenID Enabled
-
-
-
-
-
- User Account: Not logged in!
-
- User Email: Not logged in!
-
-
-
-
-
Time-based One-Time Password
-
-
- TOTP Enabled
-
-
-
-
-
- TOTP (Time-Based One-Time Password) is a security feature that generates a unique, temporary
- code which changes every 30 seconds. You use this code, along with your password to log into your
- account, making it much harder for anyone else to access it.
-
-
-
-
-
Generate TOTP Secret
- TOTP Secret Key
-
- Generate TOTP Secret
-
-
-
-
Single Sign-on Recovery Keys
-
Single sign-on recovery keys are used to login in the event you cannot access your Authenticator codes. Keep them somewhere safe and secure.
-
-
After a recovery key is used it cannot be used again.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Generate Recovery Keys
-
-`;
-
-export default class MultiFactorAuthenticationOptions extends OptionsWidget {
- doRender() {
- this.$widget = $(TPL);
-
- this.$regenerateTotpButton = this.$widget.find(".regenerate-totp");
- this.$totpEnabled = this.$widget.find(".totp-enabled");
- this.$totpSecret = this.$widget.find(".totp-secret");
- this.$totpSecretInput = this.$widget.find(".totp-secret-input");
- this.$authenticatorCode = this.$widget.find(".authenticator-code");
- this.$generateRecoveryCodeButton = this.$widget.find(
- ".generate-recovery-code"
- );
- this.$oAuthEnabledCheckbox = this.$widget.find(".oauth-enabled-checkbox");
- this.$oauthLoginButton = this.$widget.find(".oauth-login-button");
- this.$UserAccountName = this.$widget.find(".user-account-name");
- this.$UserAccountEmail = this.$widget.find(".user-account-email");
- this.$envEnabledTOTP = this.$widget.find(".env-totp-enabled");
- this.$envEnabledOAuth = this.$widget.find(".env-oauth-enabled");
-
-
- this.$recoveryKeys = [];
-
- for (let i = 0; i < 8; i++)
- {
- this.$recoveryKeys.push(this.$widget.find(".key_" + i));
- }
-
- this.$generateRecoveryCodeButton.on("click", async () => {
- this.setRecoveryKeys();
- });
-
- this.$regenerateTotpButton.on("click", async () => {
- this.generateKey();
- });
-
- this.$protectedSessionTimeout = this.$widget.find(
- ".protected-session-timeout-in-seconds"
- );
- this.$protectedSessionTimeout.on("change", () =>
- this.updateOption(
- "protectedSessionTimeout",
- this.$protectedSessionTimeout.val()
- )
- );
-
- this.displayRecoveryKeys();
- }
-
- async setRecoveryKeys() {
- server.get("totp_recovery/generate").then((result) => {
- if (!result.success) {
- toastService.showError("Error in revevery code generation!");
- return;
- }
- this.keyFiller(result.recoveryCodes);
- server.post("totp_recovery/set", {
- recoveryCodes: result.recoveryCodes,
- });
- });
- }
-
- async keyFiller(values) {
- // Forces values to be a string so it doesn't error out when I split.
- // Will be a non-issue when I update everything to typescript.
- const keys = (values + "").split(",");
- for (let i = 0; i < keys.length; i++) this.$recoveryKeys[i].text(keys[i]);
- }
-
- async generateKey() {
- server.get("totp/generate").then((result) => {
- if (result.success) {
- this.$totpSecret.text(result.message);
- } else {
- toastService.showError(result.message);
- }
- });
- }
-
- optionsLoaded(options) {
- server.get("oauth/status").then((result) => {
- if (result.enabled) {
- this.$oAuthEnabledCheckbox.prop("checked", result.enabled);
- this.$UserAccountName.text(result.name);
- this.$UserAccountEmail.text(result.email);
- }else
- this.$envEnabledOAuth.text(
- "set SSO_ENABLED as environment variable to 'true' to enable (Requires restart)"
- );
- });
-
- server.get("totp/status").then((result) => {
- if (result.enabled){
- this.$totpEnabled.prop("checked", result.message);
- this.$authenticatorCode.prop("disabled", !result.message);
- this.$generateRecoveryCodeButton.prop("disabled", !result.message);
- }
- else {
- this.$totpEnabled.prop("checked", false);
- this.$totpEnabled.prop("disabled", true);
- this.$authenticatorCode.prop("disabled", true);
- this.$generateRecoveryCodeButton.prop("disabled", true);
-
- this.$envEnabledTOTP.text(
- "Set TOTP_ENABLED as environment variable to 'true' to enable (Requires restart)"
- );
- }
- });
- this.$protectedSessionTimeout.val(options.protectedSessionTimeout);
- }
-
- displayRecoveryKeys() {
- server.get("totp_recovery/enabled").then((result) => {
- if (!result.success) {
- this.keyFiller(Array(8).fill("Error generating recovery keys!"));
- return;
- }
-
- if (!result.keysExist) {
- this.keyFiller(Array(8).fill("No key set"));
- this.$generateRecoveryCodeButton.text("Generate Recovery Codes");
- return;
- }
- });
- server.get("totp_recovery/used").then((result) => {
- this.keyFiller((result.usedRecoveryCodes + "").split(","));
- this.$generateRecoveryCodeButton.text("Regenerate Recovery Codes");
- });
- }
-}
diff --git a/src/public/app/widgets/type_widgets/options/multi_factor_authentication.ts b/src/public/app/widgets/type_widgets/options/multi_factor_authentication.ts
new file mode 100644
index 000000000..7df18c301
--- /dev/null
+++ b/src/public/app/widgets/type_widgets/options/multi_factor_authentication.ts
@@ -0,0 +1,245 @@
+import server from "../../../services/server.js";
+import toastService from "../../../services/toast.js";
+import OptionsWidget from "./options_widget.js";
+import type { OptionMap } from "../../../../../services/options_interface.js";
+
+const TPL = `
+
+
What is Multi-Factor Authentication?
+
+ Multi-Factor Authentication (MFA) adds an extra layer of security to your account. Instead
+ of just entering a password to log in, MFA requires you to provide one or more additional
+ pieces of evidence to verify your identity. This way, even if someone gets hold of your
+ password, they still can't access your account without the second piece of information.
+ It's like adding an extra lock to your door, making it much harder for anyone else to
+ break in.
+
+
+
+
OAuth/OpenID
+
OpenID is a standardized way to let you log into websites using an account from another service, like Google, to verify your identity.
+
+
+ OAuth/OpenID Enabled
+
+
+
+
+
+ User Account: Not logged in!
+
+ User Email: Not logged in!
+
+
+
+
+
Time-based One-Time Password
+
+
+ TOTP Enabled
+
+
+
+
+
+ TOTP (Time-Based One-Time Password) is a security feature that generates a unique, temporary
+ code which changes every 30 seconds. You use this code, along with your password to log into your
+ account, making it much harder for anyone else to access it.
+
+
+
+
+
Generate TOTP Secret
+ TOTP Secret Key
+
+ Generate TOTP Secret
+
+
+
+
Single Sign-on Recovery Keys
+
Single sign-on recovery keys are used to login in the event you cannot access your Authenticator codes. Keep them somewhere safe and secure.
+
+
After a recovery key is used it cannot be used again.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Generate Recovery Keys
+
+`;
+
+interface OAuthStatus {
+ enabled: boolean;
+ name?: string;
+ email?: string;
+}
+
+interface TOTPStatus {
+ enabled: boolean;
+ message: boolean;
+}
+
+interface RecoveryKeysResponse {
+ success: boolean;
+ recoveryCodes?: string[];
+ keysExist?: boolean;
+ usedRecoveryCodes?: string[];
+}
+
+export default class MultiFactorAuthenticationOptions extends OptionsWidget {
+ private $regenerateTotpButton!: JQuery;
+ private $totpEnabled!: JQuery;
+ private $totpSecret!: JQuery;
+ private $totpSecretInput!: JQuery;
+ private $authenticatorCode!: JQuery;
+ private $generateRecoveryCodeButton!: JQuery;
+ private $oAuthEnabledCheckbox!: JQuery;
+ private $oauthLoginButton!: JQuery;
+ private $UserAccountName!: JQuery;
+ private $UserAccountEmail!: JQuery;
+ private $envEnabledTOTP!: JQuery;
+ private $envEnabledOAuth!: JQuery;
+ private $recoveryKeys: JQuery[] = [];
+ private $protectedSessionTimeout!: JQuery;
+
+ doRender() {
+ this.$widget = $(TPL);
+
+ this.$regenerateTotpButton = this.$widget.find(".regenerate-totp");
+ this.$totpEnabled = this.$widget.find(".totp-enabled");
+ this.$totpSecret = this.$widget.find(".totp-secret");
+ this.$totpSecretInput = this.$widget.find(".totp-secret-input");
+ this.$authenticatorCode = this.$widget.find(".authenticator-code");
+ this.$generateRecoveryCodeButton = this.$widget.find(".generate-recovery-code");
+ this.$oAuthEnabledCheckbox = this.$widget.find(".oauth-enabled-checkbox");
+ this.$oauthLoginButton = this.$widget.find(".oauth-login-button");
+ this.$UserAccountName = this.$widget.find(".user-account-name");
+ this.$UserAccountEmail = this.$widget.find(".user-account-email");
+ this.$envEnabledTOTP = this.$widget.find(".env-totp-enabled");
+ this.$envEnabledOAuth = this.$widget.find(".env-oauth-enabled");
+
+ this.$recoveryKeys = [];
+ for (let i = 0; i < 8; i++) {
+ this.$recoveryKeys.push(this.$widget.find(".key_" + i));
+ }
+
+ this.$generateRecoveryCodeButton.on("click", async () => {
+ await this.setRecoveryKeys();
+ });
+
+ this.$regenerateTotpButton.on("click", async () => {
+ await this.generateKey();
+ });
+
+ this.$protectedSessionTimeout = this.$widget.find(".protected-session-timeout-in-seconds");
+ this.$protectedSessionTimeout.on("change", () => {
+ this.updateOption("protectedSessionTimeout", this.$protectedSessionTimeout.val());
+ });
+
+ this.displayRecoveryKeys();
+ }
+
+ async setRecoveryKeys() {
+ const result = await server.get("totp_recovery/generate");
+ if (!result.success) {
+ toastService.showError("Error in recovery code generation!");
+ return;
+ }
+ if (result.recoveryCodes) {
+ this.keyFiller(result.recoveryCodes);
+ await server.post("totp_recovery/set", {
+ recoveryCodes: result.recoveryCodes,
+ });
+ }
+ }
+
+ private keyFiller(values: string[]) {
+ const keys = values.join(",").split(",");
+ for (let i = 0; i < keys.length; i++) {
+ this.$recoveryKeys[i].text(keys[i]);
+ }
+ }
+
+ async generateKey() {
+ const result = await server.get<{ success: boolean; message: string }>("totp/generate");
+ if (result.success) {
+ this.$totpSecret.text(result.message);
+ } else {
+ toastService.showError(result.message);
+ }
+ }
+
+ optionsLoaded(options: OptionMap) {
+ server.get("oauth/status").then((result) => {
+ if (result.enabled) {
+ this.$oAuthEnabledCheckbox.prop("checked", result.enabled);
+ if (result.name) this.$UserAccountName.text(result.name);
+ if (result.email) this.$UserAccountEmail.text(result.email);
+ } else {
+ this.$envEnabledOAuth.text(
+ "set SSO_ENABLED as environment variable to 'true' to enable (Requires restart)"
+ );
+ }
+ });
+
+ server.get("totp/status").then((result) => {
+ if (result.enabled) {
+ this.$totpEnabled.prop("checked", result.message);
+ this.$authenticatorCode.prop("disabled", !result.message);
+ this.$generateRecoveryCodeButton.prop("disabled", !result.message);
+ } else {
+ this.$totpEnabled.prop("checked", false);
+ this.$totpEnabled.prop("disabled", true);
+ this.$authenticatorCode.prop("disabled", true);
+ this.$generateRecoveryCodeButton.prop("disabled", true);
+
+ this.$envEnabledTOTP.text(
+ "Set TOTP_ENABLED as environment variable to 'true' to enable (Requires restart)"
+ );
+ }
+ });
+ this.$protectedSessionTimeout.val(Number(options.protectedSessionTimeout));
+ }
+
+ async displayRecoveryKeys() {
+ const result = await server.get("totp_recovery/enabled");
+ if (!result.success) {
+ this.keyFiller(Array(8).fill("Error generating recovery keys!"));
+ return;
+ }
+
+ if (!result.keysExist) {
+ this.keyFiller(Array(8).fill("No key set"));
+ this.$generateRecoveryCodeButton.text("Generate Recovery Codes");
+ return;
+ }
+
+ const usedResult = await server.get("totp_recovery/used");
+ if (usedResult.usedRecoveryCodes) {
+ this.keyFiller(usedResult.usedRecoveryCodes);
+ this.$generateRecoveryCodeButton.text("Regenerate Recovery Codes");
+ }
+ }
+}