mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-03-30 11:50:09 +02:00
Add discreet login mode
This commit is contained in:
parent
bd4d8847ce
commit
2306a4e34d
@ -22,6 +22,8 @@ basicAuthUser:
|
||||
enableCorsProxy: false
|
||||
# Enable multi-user mode
|
||||
enableUserAccounts: false
|
||||
# Enable discreet login mode: hides user list on the login screen
|
||||
enableDiscreetLogin: false
|
||||
# Used to sign session cookies. Will be auto-generated if not set
|
||||
cookieSecret: ''
|
||||
# Disable security checks - NOT RECOMMENDED
|
||||
|
@ -15,5 +15,6 @@
|
||||
"**/node_modules/*",
|
||||
"public/lib",
|
||||
"backups/*",
|
||||
"data/*"
|
||||
]
|
||||
}
|
||||
|
@ -38,12 +38,20 @@
|
||||
<img src="img/logo.png" alt="SillyTavern" class="logo">
|
||||
<span>Welcome to SillyTavern</span>
|
||||
</h2>
|
||||
<h3>Select a User</h3>
|
||||
<h3 id="normalLoginPrompt">
|
||||
Select a User
|
||||
</h3>
|
||||
<h3 id="discreetLoginPrompt">
|
||||
Enter Login Details
|
||||
</h3>
|
||||
<div id="userListBlock" class="wide100p">
|
||||
<div id="userList" class="flex-container justifyCenter"></div>
|
||||
<div id="handleEntryBlock" style="display:none;" class="flex-container flexFlowColumn alignItemsCenter">
|
||||
<input id="userHandle" class="text_pole" type="text" placeholder="User handle" autocomplete="username">
|
||||
</div>
|
||||
<div id="passwordEntryBlock" style="display:none;"
|
||||
class="flex-container flexFlowColumn alignItemsCenter">
|
||||
<input id="userPassword" class="text_pole" type="password" placeholder="Enter a password...">
|
||||
<input id="userPassword" class="text_pole" type="password" placeholder="Password" autocomplete="current-password">
|
||||
<div class="flex-container">
|
||||
<div id="loginButton" class="menu_button">Login</div>
|
||||
<div id="recoverPassword" class="menu_button">Recover</div>
|
||||
@ -55,8 +63,8 @@
|
||||
Recovery code has been posted to the server console.
|
||||
</div>
|
||||
<input id="recoveryCode" class="text_pole" type="text" placeholder="Recovery code">
|
||||
<input id="newPassword" class="text_pole" type="password" placeholder="New password...">
|
||||
<div class="flex-container">
|
||||
<input id="newPassword" class="text_pole" type="password" placeholder="New password" autocomplete="new-password">
|
||||
<div class="flex-container flexGap10">
|
||||
<div id="sendRecovery" class="menu_button">Send</div>
|
||||
<div id="cancelRecovery" class="menu_button">Cancel</div>
|
||||
</div>
|
||||
|
@ -2,6 +2,7 @@
|
||||
* CRSF token for requests.
|
||||
*/
|
||||
let csrfToken = '';
|
||||
let discreetLogin = false;
|
||||
|
||||
/**
|
||||
* Gets a CSRF token from the server.
|
||||
@ -25,6 +26,17 @@ async function getUserList() {
|
||||
'X-CSRF-Token': csrfToken,
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
return displayError(errorData.error || 'An error occurred');
|
||||
}
|
||||
|
||||
if (response.status === 204) {
|
||||
discreetLogin = true;
|
||||
return [];
|
||||
}
|
||||
|
||||
const userListObj = await response.json();
|
||||
console.log(userListObj);
|
||||
return userListObj;
|
||||
@ -188,9 +200,15 @@ function onCancelRecoveryClick() {
|
||||
displayError('');
|
||||
}
|
||||
|
||||
(async function () {
|
||||
csrfToken = await getCsrfToken();
|
||||
const userList = await getUserList();
|
||||
/**
|
||||
* Configures the login page for normal login.
|
||||
* @param {import('../../src/users').UserViewModel[]} userList List of users
|
||||
*/
|
||||
function configureNormalLogin(userList) {
|
||||
console.log('Discreet login is disabled');
|
||||
$('#handleEntryBlock').hide();
|
||||
$('#normalLoginPrompt').show();
|
||||
$('#discreetLoginPrompt').hide();
|
||||
console.log(userList);
|
||||
for (const user of userList) {
|
||||
const userBlock = $('<div></div>').addClass('userSelect');
|
||||
@ -202,6 +220,47 @@ function onCancelRecoveryClick() {
|
||||
userBlock.on('click', () => onUserSelected(user));
|
||||
$('#userList').append(userBlock);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the login page for discreet login.
|
||||
*/
|
||||
function configureDiscreetLogin() {
|
||||
console.log('Discreet login is enabled');
|
||||
$('#handleEntryBlock').show();
|
||||
$('#normalLoginPrompt').hide();
|
||||
$('#discreetLoginPrompt').show();
|
||||
$('#userList').hide();
|
||||
$('#passwordRecoveryBlock').hide();
|
||||
$('#passwordEntryBlock').show();
|
||||
$('#loginButton').off('click').on('click', async () => {
|
||||
const handle = String($('#userHandle').val());
|
||||
const password = String($('#userPassword').val());
|
||||
await performLogin(handle, password);
|
||||
});
|
||||
|
||||
$('#recoverPassword').off('click').on('click', async () => {
|
||||
const handle = String($('#userHandle').val());
|
||||
await sendRecoveryPart1(handle);
|
||||
});
|
||||
|
||||
$('#sendRecovery').off('click').on('click', async () => {
|
||||
const handle = String($('#userHandle').val());
|
||||
const code = String($('#recoveryCode').val());
|
||||
const newPassword = String($('#newPassword').val());
|
||||
await sendRecoveryPart2(handle, code, newPassword);
|
||||
});
|
||||
}
|
||||
|
||||
(async function () {
|
||||
csrfToken = await getCsrfToken();
|
||||
const userList = await getUserList();
|
||||
|
||||
if (discreetLogin) {
|
||||
configureDiscreetLogin();
|
||||
} else {
|
||||
configureNormalLogin(userList);
|
||||
}
|
||||
document.getElementById('shadow_popup').style.opacity = '';
|
||||
$('#cancelRecovery').on('click', onCancelRecoveryClick);
|
||||
})();
|
||||
|
@ -3,9 +3,10 @@ const storage = require('node-persist');
|
||||
const express = require('express');
|
||||
const { RateLimiterMemory, RateLimiterRes } = require('rate-limiter-flexible');
|
||||
const { jsonParser, getIpFromRequest } = require('../express-common');
|
||||
const { color, Cache } = require('../util');
|
||||
const { color, Cache, getConfigValue } = require('../util');
|
||||
const { KEY_PREFIX, getUserAvatar, toKey, getPasswordHash, getPasswordSalt } = require('../users');
|
||||
|
||||
const DISCREET_LOGIN = getConfigValue('enableDiscreetLogin', false);
|
||||
const MFA_CACHE = new Cache(5 * 60 * 1000);
|
||||
|
||||
const router = express.Router();
|
||||
@ -20,6 +21,10 @@ const recoverLimiter = new RateLimiterMemory({
|
||||
|
||||
router.post('/list', async (_request, response) => {
|
||||
try {
|
||||
if (DISCREET_LOGIN) {
|
||||
return response.sendStatus(204);
|
||||
}
|
||||
|
||||
/** @type {import('../users').User[]} */
|
||||
const users = await storage.values(x => x.key.startsWith(KEY_PREFIX));
|
||||
const viewModels = users
|
||||
|
Loading…
x
Reference in New Issue
Block a user