mirror of
https://github.com/HeyPuter/puter.git
synced 2026-05-04 08:30:39 +00:00
dev(oidc): rewrite "Disable 2FA" window
In lieu of knowing exactly what happened (probably more than one thing), the "Disable 2FA" window was very broken. It was blank, but then after fixing that all the actions were broken. There wasn't much value in keeping the implementation though, because it was already inconsistent with other flows - instead of fixing what was there it made more sense to re-use the pattern of UIWindowChangeUsername and UIWindowChangeEmail, creating UIWindowDisable2FA. After testing this, it works much better (it actaully works), but there is a caching issue unrelated to the UI implementation.
This commit is contained in:
@@ -17,8 +17,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import TeePromise from '../../util/TeePromise.js';
|
||||
import UIComponentWindow from '../UIComponentWindow.js';
|
||||
import UIWindowDisable2FA from '../Settings/UIWindowDisable2FA.js';
|
||||
import UIWindow2FASetup from '../UIWindow2FASetup.js';
|
||||
import UIWindowChangePassword from '../UIWindowChangePassword.js';
|
||||
import UIWindowManageSessions from '../UIWindowManageSessions.js';
|
||||
@@ -148,142 +147,25 @@ const TabSecurity = {
|
||||
});
|
||||
|
||||
$el_window.find('.dashboard-section-security .disable-2fa').on('click', async function (e) {
|
||||
let win;
|
||||
const password_confirm_promise = new TeePromise();
|
||||
|
||||
function openRevalidatePopup (revalidateUrl, onDone) {
|
||||
const url = revalidateUrl || (window.user && window.user.oidc_revalidate_url);
|
||||
if ( ! url ) {
|
||||
onDone && onDone(new Error('No revalidate URL'));
|
||||
return null;
|
||||
}
|
||||
let doneCalled = false;
|
||||
const hint = $win.find('.disable-2fa-oidc-hint');
|
||||
hint.text(i18n('revalidate_sign_in_popup') || 'Sign in with your linked account in the popup.').show();
|
||||
const popup = window.open(url, 'puter-revalidate', 'width=500,height=600');
|
||||
const onMessage = (ev) => {
|
||||
if ( (ev.origin !== window.gui_origin) && (ev.origin !== window.location.origin) ) return;
|
||||
if ( !ev.data || ev.data.type !== 'puter-revalidate-done' ) return;
|
||||
if ( doneCalled ) return;
|
||||
doneCalled = true;
|
||||
window.removeEventListener('message', onMessage);
|
||||
hint.hide();
|
||||
onDone && onDone();
|
||||
};
|
||||
window.addEventListener('message', onMessage);
|
||||
const checkClosed = setInterval(() => {
|
||||
if ( popup && popup.closed ) {
|
||||
clearInterval(checkClosed);
|
||||
window.removeEventListener('message', onMessage);
|
||||
hint.hide();
|
||||
if ( ! doneCalled ) {
|
||||
doneCalled = true;
|
||||
onDone && onDone(new Error('Popup closed'));
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
return popup;
|
||||
}
|
||||
|
||||
const doRequest = () => fetch(`${window.api_origin}/user-protected/disable-2fa`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ password: $win.find('.password-entry').val() }),
|
||||
});
|
||||
|
||||
const try_password = async () => {
|
||||
const resp = await doRequest();
|
||||
if ( resp.status === 200 ) {
|
||||
password_confirm_promise.resolve(true);
|
||||
$(win).close();
|
||||
return;
|
||||
}
|
||||
const data = await resp.json().catch(() => ({}));
|
||||
if ( data.code === 'oidc_revalidation_required' && data.revalidate_url ) {
|
||||
openRevalidatePopup(data.revalidate_url, async (err) => {
|
||||
if ( err ) {
|
||||
$win.find('.error-message').text(err.message || 'Re-validation required.').show();
|
||||
return;
|
||||
}
|
||||
const r2 = await doRequest();
|
||||
if ( r2.status === 200 ) {
|
||||
password_confirm_promise.resolve(true);
|
||||
$(win).close();
|
||||
} else {
|
||||
let message; try {
|
||||
message = (await r2.json()).message;
|
||||
} catch (e) {
|
||||
}
|
||||
$win.find('.error-message').text(message || i18n('error_unknown_cause')).show();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
const message = data.message || i18n('error_unknown_cause');
|
||||
$win.find('.password-entry').addClass('error');
|
||||
$win.find('.error-message').text(message).show();
|
||||
};
|
||||
|
||||
let h = '';
|
||||
h += '<div style="display: flex; flex-direction: column; gap: 20pt; justify-content: center;">';
|
||||
h += '<div>';
|
||||
h += `<h3 style="text-align:center; font-weight: 500; font-size: 20px;">${i18n('disable_2fa_confirm')}</h3>`;
|
||||
h += `<p style="text-align:center; padding: 0 20px;">${i18n('disable_2fa_instructions')}</p>`;
|
||||
h += '</div>';
|
||||
h += '<div style="display: flex; flex-direction: column; gap: 10pt;">';
|
||||
h += '<input type="password" class="password-entry" />';
|
||||
h += '<p class="disable-2fa-oidc-hint" style="margin:0;font-size:12px;color:#666;display:none;"></p>';
|
||||
h += '<span class="error-message" style="color: var(--dashboard-error-text); display: none;"></span>';
|
||||
h += '</div>';
|
||||
h += '<div style="display: flex; gap: 5pt;">';
|
||||
h += `<button class="button confirm-disable-2fa">${i18n('disable_2fa')}</button>`;
|
||||
h += `<button class="button secondary cancel-disable-2fa">${i18n('cancel')}</button>`;
|
||||
h += '</div>';
|
||||
h += '</div>';
|
||||
|
||||
win = await UIComponentWindow({
|
||||
html: h,
|
||||
width: 500,
|
||||
backdrop: true,
|
||||
is_resizable: false,
|
||||
body_css: {
|
||||
width: 'initial',
|
||||
'background-color': 'var(--dashboard-input-background)',
|
||||
'backdrop-filter': 'blur(3px)',
|
||||
padding: '20px',
|
||||
const { promise } = await UIWindowDisable2FA({
|
||||
window_options: {
|
||||
parent_uuid: $el_window.attr('data-element_uuid'),
|
||||
backdrop: true,
|
||||
close_on_backdrop_click: true,
|
||||
parent_center: true,
|
||||
stay_on_top: true,
|
||||
has_head: false,
|
||||
},
|
||||
});
|
||||
const tfa_was_disabled = await promise;
|
||||
|
||||
// Set up event listeners
|
||||
const $win = $(win);
|
||||
const $password_entry = $win.find('.password-entry');
|
||||
|
||||
$password_entry.on('keypress', (e) => {
|
||||
if ( e.which === 13 ) { // Enter key
|
||||
try_password();
|
||||
}
|
||||
});
|
||||
|
||||
$win.find('.confirm-disable-2fa').on('click', () => {
|
||||
try_password();
|
||||
});
|
||||
|
||||
$win.find('.cancel-disable-2fa').on('click', () => {
|
||||
password_confirm_promise.resolve(false);
|
||||
$win.close();
|
||||
});
|
||||
|
||||
$password_entry.focus();
|
||||
|
||||
const ok = await password_confirm_promise;
|
||||
if ( ! ok ) return;
|
||||
|
||||
$el_window.find('.dashboard-section-security .enable-2fa').show();
|
||||
$el_window.find('.dashboard-section-security .disable-2fa').hide();
|
||||
$el_window.find('.dashboard-section-security .user-otp-state').text(i18n('two_factor_disabled'));
|
||||
$el_window.find('.dashboard-section-security .dashboard-settings-card-2fa').removeClass('dashboard-settings-card-success');
|
||||
$el_window.find('.dashboard-section-security .dashboard-settings-card-2fa').addClass('dashboard-settings-card-warning');
|
||||
if ( tfa_was_disabled ) {
|
||||
$el_window.find('.dashboard-section-security .enable-2fa').show();
|
||||
$el_window.find('.dashboard-section-security .disable-2fa').hide();
|
||||
$el_window.find('.dashboard-section-security .user-otp-state').text(i18n('two_factor_disabled'));
|
||||
$el_window.find('.dashboard-section-security .dashboard-settings-card-2fa').removeClass('dashboard-settings-card-success');
|
||||
$el_window.find('.dashboard-section-security .dashboard-settings-card-2fa').addClass('dashboard-settings-card-warning');
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
@@ -16,9 +16,8 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import TeePromise from '../../util/TeePromise.js';
|
||||
import UIComponentWindow from '../UIComponentWindow.js';
|
||||
import UIWindow2FASetup from '../UIWindow2FASetup.js';
|
||||
import UIWindowDisable2FA from './UIWindowDisable2FA.js';
|
||||
|
||||
export default {
|
||||
id: 'security',
|
||||
@@ -82,146 +81,16 @@ export default {
|
||||
});
|
||||
|
||||
$el_window.find('.disable-2fa').on('click', async function (e) {
|
||||
let win;
|
||||
const password_confirm_promise = new TeePromise();
|
||||
const { promise } = await UIWindowDisable2FA();
|
||||
const tfa_was_disabled = await promise;
|
||||
|
||||
function openRevalidatePopup ($win, revalidateUrl, onDone) {
|
||||
const url = revalidateUrl || (window.user && window.user.oidc_revalidate_url);
|
||||
if ( ! url ) {
|
||||
onDone && onDone(new Error('No revalidate URL'));
|
||||
return null;
|
||||
}
|
||||
let doneCalled = false;
|
||||
const hint = $win.find('.disable-2fa-oidc-hint');
|
||||
hint.text(i18n('revalidate_sign_in_popup') || 'Sign in with your linked account in the popup.').show();
|
||||
const popup = window.open(url, 'puter-revalidate', 'width=500,height=600');
|
||||
const onMessage = (ev) => {
|
||||
if ( (ev.origin !== window.gui_origin) && (ev.origin !== window.location.origin) ) return;
|
||||
if ( !ev.data || ev.data.type !== 'puter-revalidate-done' ) return;
|
||||
if ( doneCalled ) return;
|
||||
doneCalled = true;
|
||||
window.removeEventListener('message', onMessage);
|
||||
hint.hide();
|
||||
onDone && onDone();
|
||||
};
|
||||
window.addEventListener('message', onMessage);
|
||||
const checkClosed = setInterval(() => {
|
||||
if ( popup && popup.closed ) {
|
||||
clearInterval(checkClosed);
|
||||
window.removeEventListener('message', onMessage);
|
||||
hint.hide();
|
||||
if ( ! doneCalled ) {
|
||||
doneCalled = true;
|
||||
onDone && onDone(new Error('Popup closed'));
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
return popup;
|
||||
if ( tfa_was_disabled ) {
|
||||
$el_window.find('.enable-2fa').show();
|
||||
$el_window.find('.disable-2fa').hide();
|
||||
$el_window.find('.user-otp-state').text(i18n('two_factor_disabled'));
|
||||
$el_window.find('.settings-card-security').removeClass('settings-card-success');
|
||||
$el_window.find('.settings-card-security').addClass('settings-card-warning');
|
||||
}
|
||||
|
||||
const doRequest = () => fetch(`${window.api_origin}/user-protected/disable-2fa`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
password: win ? $(win).find('.password-entry').val() : '',
|
||||
}),
|
||||
});
|
||||
|
||||
const try_password = async () => {
|
||||
const resp = await doRequest();
|
||||
if ( resp.status === 200 ) {
|
||||
password_confirm_promise.resolve(true);
|
||||
$(win).close();
|
||||
return;
|
||||
}
|
||||
const data = await resp.json().catch(() => ({}));
|
||||
const $win = $(win);
|
||||
if ( data.code === 'oidc_revalidation_required' && data.revalidate_url ) {
|
||||
openRevalidatePopup($win, data.revalidate_url, async (err) => {
|
||||
if ( err ) {
|
||||
$win.find('.error-message').text(err.message || 'Re-validation required.').show();
|
||||
return;
|
||||
}
|
||||
const r2 = await doRequest();
|
||||
if ( r2.status === 200 ) {
|
||||
password_confirm_promise.resolve(true);
|
||||
$(win).close();
|
||||
} else {
|
||||
let message; try {
|
||||
message = (await r2.json()).message;
|
||||
} catch (e) {
|
||||
}
|
||||
$win.find('.error-message').text(message || i18n('error_unknown_cause')).show();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
$win.find('.password-entry').addClass('error');
|
||||
$win.find('.error-message').text(data.message || i18n('error_unknown_cause')).show();
|
||||
};
|
||||
|
||||
const oidc_only = !!(window.user && window.user.oidc_only);
|
||||
let h = '';
|
||||
h += '<div style="display: flex; flex-direction: column; gap: 20pt; justify-content: center;">';
|
||||
h += '<div>';
|
||||
h += `<h3 style="text-align:center; font-weight: 500; font-size: 20px;">${i18n('disable_2fa_confirm')}</h3>`;
|
||||
h += `<p style="text-align:center; padding: 0 20px;">${i18n('disable_2fa_instructions')}</p>`;
|
||||
if ( oidc_only ) {
|
||||
h += `<p class="disable-2fa-oidc-flow-notice" style="text-align:center; padding: 0 20px; margin: 8px 0 0; font-size: 12px; color: #666;">${i18n('revalidate_flow_notice')}</p>`;
|
||||
}
|
||||
h += '</div>';
|
||||
h += '<div style="display: flex; flex-direction: column; gap: 10pt;">';
|
||||
h += '<input type="password" class="password-entry" />';
|
||||
h += '<p class="disable-2fa-oidc-hint" style="margin:0;font-size:12px;color:#666;display:none;"></p>';
|
||||
h += '<span class="error-message" style="color: red; display: none;"></span>';
|
||||
h += `<button class="button confirm-disable-2fa">${i18n('disable_2fa')}</button>`;
|
||||
h += `<button class="button secondary cancel-disable-2fa">${i18n('cancel')}</button>`;
|
||||
h += '</div>';
|
||||
h += '</div>';
|
||||
|
||||
win = await UIComponentWindow({
|
||||
html: h,
|
||||
width: 500,
|
||||
backdrop: true,
|
||||
is_resizable: false,
|
||||
body_css: {
|
||||
width: 'initial',
|
||||
'background-color': 'rgb(245 247 249)',
|
||||
'backdrop-filter': 'blur(3px)',
|
||||
padding: '20px',
|
||||
},
|
||||
});
|
||||
|
||||
// Set up event listeners
|
||||
const $win = $(win);
|
||||
const $password_entry = $win.find('.password-entry');
|
||||
|
||||
$password_entry.on('keypress', (e) => {
|
||||
if ( e.which === 13 ) { // Enter key
|
||||
try_password();
|
||||
}
|
||||
});
|
||||
|
||||
$win.find('.confirm-disable-2fa').on('click', () => {
|
||||
try_password();
|
||||
});
|
||||
|
||||
$win.find('.cancel-disable-2fa').on('click', () => {
|
||||
password_confirm_promise.resolve(false);
|
||||
$win.close();
|
||||
});
|
||||
|
||||
$password_entry.focus();
|
||||
|
||||
const ok = await password_confirm_promise;
|
||||
if ( ! ok ) return;
|
||||
|
||||
$el_window.find('.enable-2fa').show();
|
||||
$el_window.find('.disable-2fa').hide();
|
||||
$el_window.find('.user-otp-state').text(i18n('two_factor_disabled'));
|
||||
$el_window.find('.settings-card-security').removeClass('settings-card-success');
|
||||
$el_window.find('.settings-card-security').addClass('settings-card-warning');
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
/**
|
||||
* Copyright (C) 2026-present Puter Technologies Inc.
|
||||
*
|
||||
* This file is part of Puter.
|
||||
*
|
||||
* Puter is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { openRevalidatePopup } from '../../util/openid.js';
|
||||
import Placeholder from '../../util/Placeholder.js';
|
||||
import TeePromise from '../../util/TeePromise.js';
|
||||
import PasswordEntry from '../Components/PasswordEntry.js';
|
||||
import UIWindow from '../UIWindow.js';
|
||||
|
||||
async function UIWindowDisable2FA (options) {
|
||||
options = options ?? {};
|
||||
|
||||
const promise = new TeePromise();
|
||||
let disabled_successfully = false;
|
||||
|
||||
const password_entry = new PasswordEntry({});
|
||||
const place_password_entry = Placeholder();
|
||||
|
||||
const internal_id = window.uuidv4();
|
||||
let h = '';
|
||||
h += '<div class="disable-2fa" style="padding: 20px; border-bottom: 1px solid #ced7e1;">';
|
||||
h += '<div class="form-error-msg"></div>';
|
||||
h += '<div class="form-success-msg"></div>';
|
||||
h += '<div style="overflow: hidden; margin-top: 10px; margin-bottom: 20px;">';
|
||||
h += `<p style="margin:0;font-size:14px;color:#333;">${i18n('disable_2fa_instructions')}</p>`;
|
||||
h += '</div>';
|
||||
h += '<div class="disable-2fa-auth-row" style="overflow: hidden; margin-top: 10px; margin-bottom: 30px;">';
|
||||
h += '<div class="disable-2fa-password-wrap">';
|
||||
h += `<label>${i18n('account_password')}</label>`;
|
||||
h += `${place_password_entry.html}`;
|
||||
h += '</div>';
|
||||
h += '<div class="disable-2fa-oidc-wrap" style="display:none;">';
|
||||
h += '<p class="disable-2fa-oidc-flow-notice" style="margin:0;font-size:12px;color:#666;"></p>';
|
||||
h += '<span class="disable-2fa-revalidated-msg" style="display:none;"></span>';
|
||||
h += '</div>';
|
||||
h += '<p class="disable-2fa-oidc-hint" style="margin-top:6px;font-size:12px;color:#666;display:none;"></p>';
|
||||
h += '</div>';
|
||||
h += `<button class="disable-2fa-btn button button-primary button-block button-normal">${i18n('disable_2fa')}</button>`;
|
||||
h += '</div>';
|
||||
|
||||
const el_window = await UIWindow({
|
||||
title: i18n('disable_2fa'),
|
||||
app: 'disable-2fa',
|
||||
single_instance: true,
|
||||
icon: null,
|
||||
uid: null,
|
||||
is_dir: false,
|
||||
body_content: h,
|
||||
has_head: true,
|
||||
selectable_body: false,
|
||||
draggable_body: false,
|
||||
allow_context_menu: false,
|
||||
is_resizable: false,
|
||||
is_droppable: false,
|
||||
init_center: true,
|
||||
allow_native_ctxmenu: false,
|
||||
allow_user_select: false,
|
||||
width: 350,
|
||||
height: 'auto',
|
||||
dominant: true,
|
||||
show_in_taskbar: false,
|
||||
on_before_exit: async () => {
|
||||
if ( ! disabled_successfully ) {
|
||||
promise.resolve(false);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
onAppend: function (this_window) {
|
||||
$(this_window).find('.disable-2fa-password-wrap input').get(0)?.focus({ preventScroll: true });
|
||||
const oidc_only = !!(window.user && window.user.oidc_only);
|
||||
const authRow = $(this_window).find('.disable-2fa-auth-row');
|
||||
if ( oidc_only ) {
|
||||
authRow.find('.disable-2fa-password-wrap').hide();
|
||||
const oidcWrap = authRow.find('.disable-2fa-oidc-wrap').show();
|
||||
oidcWrap.find('.disable-2fa-oidc-flow-notice').text(
|
||||
i18n('revalidate_flow_notice') ||
|
||||
'You will be asked to sign in with your linked account when you continue.',
|
||||
);
|
||||
} else {
|
||||
authRow.find('.disable-2fa-oidc-wrap').hide();
|
||||
}
|
||||
},
|
||||
window_class: 'window-publishWebsite',
|
||||
body_css: {
|
||||
width: 'initial',
|
||||
height: '100%',
|
||||
'background-color': 'rgb(245 247 249)',
|
||||
'backdrop-filter': 'blur(3px)',
|
||||
},
|
||||
...options.window_options,
|
||||
});
|
||||
|
||||
password_entry.attach(place_password_entry);
|
||||
|
||||
const origin = window.gui_origin || window.api_origin || '';
|
||||
const apiUrl = `${origin}/user-protected/disable-2fa`;
|
||||
let revalidated = false;
|
||||
|
||||
const hint = $(el_window).find('.disable-2fa-oidc-hint');
|
||||
const REVALIDATE_POPUP_TEXT = i18n('revalidate_sign_in_popup') || 'Sign in with your linked account in the popup.';
|
||||
|
||||
const myOpenRevalidatePopup = async (revalidateUrl) => {
|
||||
revalidateUrl = revalidateUrl || (window.user && window.user.oidc_revalidate_url);
|
||||
$(el_window).find('.disable-2fa-btn').addClass('disabled');
|
||||
hint.text(REVALIDATE_POPUP_TEXT).show();
|
||||
try {
|
||||
await openRevalidatePopup(revalidateUrl);
|
||||
} catch (e) {
|
||||
onError(e.message || 'Authentication failed');
|
||||
return;
|
||||
} finally {
|
||||
hint.hide();
|
||||
}
|
||||
$(el_window).find('.disable-2fa-revalidated-msg').text(i18n('revalidated') || 'Re-validated.').show();
|
||||
};
|
||||
|
||||
$(el_window).find('.disable-2fa-btn').on('click', async function (e) {
|
||||
$(el_window).find('.form-success-msg, .form-error-msg').hide();
|
||||
|
||||
const password = password_entry.get('value');
|
||||
const oidc_only = !!(window.user && window.user.oidc_only);
|
||||
|
||||
if ( !oidc_only && !password ) {
|
||||
$(el_window).find('.form-error-msg').html(i18n('all_fields_required'));
|
||||
$(el_window).find('.form-error-msg').fadeIn();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( oidc_only && !revalidated && !password ) {
|
||||
await myOpenRevalidatePopup();
|
||||
|
||||
const res = await doSubmit({ password: undefined });
|
||||
const data = res.ok ? await res.json().catch(() => ({})) : await res.json().catch(() => ({}));
|
||||
if ( res.ok ) onSuccess();
|
||||
else onError(data.message || 'Request failed');
|
||||
return;
|
||||
}
|
||||
$(el_window).find('.form-error-msg').hide();
|
||||
$(el_window).find('.disable-2fa-btn').addClass('disabled');
|
||||
$(el_window).find('.disable-2fa-password-wrap input').attr('disabled', true);
|
||||
|
||||
let res = await doSubmit({ password });
|
||||
const data = res.ok ? await res.json().catch(() => ({})) : await res.json().catch(() => ({}));
|
||||
|
||||
if ( res.ok ) {
|
||||
onSuccess();
|
||||
return;
|
||||
}
|
||||
if ( data.code === 'oidc_revalidation_required' && data.revalidate_url ) {
|
||||
await myOpenRevalidatePopup(data.revalidate_url);
|
||||
const r = await doSubmit({ password: undefined });
|
||||
if ( r.ok ) onSuccess();
|
||||
else r.json().then((d) => onError(d.message || 'Request failed')).catch(() => onError('Request failed'));
|
||||
return;
|
||||
}
|
||||
onError(data.message || 'Request failed');
|
||||
});
|
||||
|
||||
function doSubmit ({ password }) {
|
||||
return fetch(apiUrl, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
password: password !== undefined && password !== '' ? password : undefined,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
function onError (message) {
|
||||
$(el_window).find('.form-error-msg').html(html_encode(message));
|
||||
$(el_window).find('.form-error-msg').fadeIn();
|
||||
$(el_window).find('.disable-2fa-btn').removeClass('disabled');
|
||||
$(el_window).find('.disable-2fa-password-wrap input').attr('disabled', false);
|
||||
}
|
||||
|
||||
function onSuccess () {
|
||||
disabled_successfully = true;
|
||||
$(el_window).find('.form-success-msg').html(i18n('two_factor_disabled'));
|
||||
$(el_window).find('.form-success-msg').fadeIn();
|
||||
if ( window.user ) window.user.otp = false;
|
||||
$(el_window).find('.disable-2fa-btn').removeClass('disabled');
|
||||
$(el_window).find('.disable-2fa-password-wrap input').attr('disabled', false);
|
||||
promise.resolve(true);
|
||||
$(el_window).close();
|
||||
}
|
||||
|
||||
return { promise };
|
||||
}
|
||||
|
||||
export default UIWindowDisable2FA;
|
||||
Reference in New Issue
Block a user