feat: the password is turned off by hand in the account, with a passkey in place; password change; tabs sized by their titles
This commit is contained in:
1 parent
67222e2e05
commit
6dd1120a41
9 files changed
+212
-25
No files matched your search
@@ -1,6 +1,6 @@
|
||||
// The account button in the top bar: a dialog with who is signed in, their
|
||||
// passkeys (add one, remove one) and signing out. Once there is a passkey,
|
||||
// the password no longer signs this account in.
|
||||
// passkeys (add one, remove one), the password switch and signing out. The
|
||||
// password can be turned off once there is a passkey to sign in with.
|
||||
(function () {
|
||||
'use strict';
|
||||
var btn = document.getElementById('acct');
|
||||
@@ -34,11 +34,20 @@
|
||||
'<div class="dlg-b acct">' +
|
||||
' <div class="acct-who"><span class="acct-ava"></span><div><div class="acct-name"></div><div class="muted acct-mode"></div></div></div>' +
|
||||
' <h3>Ключи доступа</h3>' +
|
||||
' <p class="muted acct-hint">Вход отпечатком, лицом, PIN-кодом устройства или аппаратным ключом. Пока у аккаунта есть хоть один ключ, войти по паролю нельзя - держите второй ключ или другого администратора, который сможет их сбросить.</p>' +
|
||||
' <p class="muted acct-hint">Вход отпечатком, лицом, PIN-кодом устройства или аппаратным ключом. Ключей может быть несколько - например, телефон и ноутбук.</p>' +
|
||||
' <ul class="acct-keys"></ul>' +
|
||||
' <div class="acct-add"><input type="text" class="acct-keyname" maxlength="60" placeholder="название, например «телефон»">' +
|
||||
' <button type="button" class="acct-addbtn">Добавить ключ</button></div>' +
|
||||
' <p class="acct-msg"></p>' +
|
||||
' <label class="acct-pw"><span><b>Вход по паролю</b><small class="muted acct-pwnote"></small></span>' +
|
||||
' <input type="checkbox" class="sw" role="switch"></label>' +
|
||||
' <details class="acct-chpw"><summary>Сменить пароль</summary>' +
|
||||
' <form class="acct-pwform" autocomplete="on">' +
|
||||
' <input type="text" name="username" autocomplete="username" hidden>' +
|
||||
' <input type="password" name="current" placeholder="текущий пароль" autocomplete="current-password" required>' +
|
||||
' <input type="password" name="new" placeholder="новый пароль, от 8 символов" autocomplete="new-password" minlength="8" required>' +
|
||||
' <input type="password" name="again" placeholder="новый ещё раз" autocomplete="new-password" required>' +
|
||||
' <button type="submit">Сменить</button></form></details>' +
|
||||
' <form method="post" action="/logout" class="acct-out"><input type="hidden" name="csrf"><button type="submit" class="btn ghost">Выйти</button></form>' +
|
||||
'</div>';
|
||||
document.body.appendChild(dlg);
|
||||
@@ -54,8 +63,14 @@
|
||||
function load() {
|
||||
return fetch('/api/panel/account', {cache: 'no-store'}).then(function (r) { return r.json(); }).then(function (d) {
|
||||
$('.acct-name').textContent = d.username;
|
||||
dlg.querySelector('.acct-pwform [name=username]').value = d.username;
|
||||
$('.acct-ava').textContent = (d.username || '?').slice(0, 1).toUpperCase();
|
||||
$('.acct-mode').textContent = d.keys.length ? 'вход только по ключу доступа' : 'вход по паролю';
|
||||
$('.acct-mode').textContent = d.password_off ? 'вход только по ключу доступа' : d.keys.length ? 'вход по паролю или ключу' : 'вход по паролю';
|
||||
const sw = $('.acct-pw .sw');
|
||||
sw.checked = !d.password_off;
|
||||
sw.disabled = !d.keys.length;
|
||||
$('.acct-pwnote').textContent = !d.keys.length ? 'выключить можно, когда есть хотя бы один ключ'
|
||||
: d.password_off ? 'выключен: войти можно только ключом' : 'можно выключить и входить только ключом';
|
||||
var ul = $('.acct-keys');
|
||||
ul.innerHTML = d.keys.length ? '' : '<li class="muted">Ключей пока нет.</li>';
|
||||
d.keys.forEach(function (k) {
|
||||
@@ -65,7 +80,7 @@
|
||||
'<button type="button" class="btn danger small" title="Удалить ключ">Удалить</button>';
|
||||
li.querySelector('button').onclick = function () {
|
||||
var last = d.keys.length === 1;
|
||||
if (!confirm('Удалить ключ «' + k.name + '»?' + (last ? ' Это последний ключ: вход по паролю снова станет возможен.' : ''))) return;
|
||||
if (!confirm('Удалить ключ «' + k.name + '»?' + (last && d.password_off ? ' Это последний ключ: вход по паролю снова включится.' : ''))) return;
|
||||
fetch('/api/panel/account/keys/' + k.id + '/delete', {method: 'POST'}).then(function (r) { return r.json(); })
|
||||
.then(function (r) { if (!r.ok) msg(r.error, true); else { msg('ключ удалён'); load(); } });
|
||||
};
|
||||
@@ -102,6 +117,33 @@
|
||||
msg(e && e.name === 'NotAllowedError' ? 'отменено' : e && e.name === 'InvalidStateError' ? 'этот ключ уже добавлен' : 'не вышло: ' + (e && e.message || e), true);
|
||||
}).then(function () { add.disabled = false; });
|
||||
};
|
||||
$('.acct-pwform').onsubmit = function (ev) {
|
||||
ev.preventDefault();
|
||||
const f = ev.target;
|
||||
if (f.new.value !== f.again.value) { msg('новые пароли не совпадают', true); return; }
|
||||
f.querySelector('button').disabled = true;
|
||||
fetch('/api/panel/account/password/change', {method: 'POST', headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({current: f.current.value, new: f.new.value})})
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (r) {
|
||||
if (!r.ok) { msg(r.error, true); return; }
|
||||
f.reset();
|
||||
dlg.querySelector('.acct-chpw').open = false;
|
||||
msg('пароль сменён');
|
||||
})
|
||||
.catch(function () { msg('ошибка сети', true); })
|
||||
.then(function () { f.querySelector('button').disabled = false; });
|
||||
};
|
||||
$('.acct-pw .sw').onchange = function (ev) {
|
||||
const off = !ev.target.checked;
|
||||
if (off && !confirm('Выключить вход по паролю? Войти можно будет только ключом доступа. Если ключи потеряются, их сможет сбросить другой администратор в «Настройках».')) {
|
||||
ev.target.checked = true;
|
||||
return;
|
||||
}
|
||||
fetch('/api/panel/account/password', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({off: off})})
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (r) { if (!r.ok) msg(r.error, true); else msg(off ? 'вход по паролю выключен' : 'вход по паролю включён'); load(); });
|
||||
};
|
||||
btn.onclick = function () {
|
||||
msg('');
|
||||
load().then(function () { dlg.showModal(); dlg.focus(); });
|
||||
|
||||
Reference in new issue
Block a user