SillyTavern/public/scripts/login.js

277 lines
7.7 KiB
JavaScript
Raw Normal View History

/**
* CRSF token for requests.
*/
let csrfToken = '';
2024-04-10 21:00:08 +02:00
let discreetLogin = false;
/**
* Gets a CSRF token from the server.
* @returns {Promise<string>} CSRF token
*/
async function getCsrfToken() {
const response = await fetch('/csrf-token');
const data = await response.json();
return data.token;
}
/**
* Gets a list of users from the server.
* @returns {Promise<object>} List of users
*/
2024-04-07 22:08:19 +02:00
async function getUserList() {
const response = await fetch('/api/users/list', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrfToken,
},
});
2024-04-10 21:00:08 +02:00
if (!response.ok) {
const errorData = await response.json();
return displayError(errorData.error || 'An error occurred');
}
if (response.status === 204) {
discreetLogin = true;
return [];
}
2024-04-07 22:08:19 +02:00
const userListObj = await response.json();
console.log(userListObj);
return userListObj;
}
/**
* Requests a recovery code for the user.
* @param {string} handle User handle
* @returns {Promise<void>}
*/
2024-04-07 22:08:19 +02:00
async function sendRecoveryPart1(handle) {
const response = await fetch('/api/users/recover-step1', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrfToken,
2024-04-07 22:08:19 +02:00
},
body: JSON.stringify({ handle }),
});
if (!response.ok) {
const errorData = await response.json();
return displayError(errorData.error || 'An error occurred');
}
showRecoveryBlock();
}
/**
* Sets a new password for the user using the recovery code.
* @param {string} handle User handle
* @param {string} code Recovery code
* @param {string} newPassword New password
* @returns {Promise<void>}
*/
2024-04-07 22:08:19 +02:00
async function sendRecoveryPart2(handle, code, newPassword) {
const recoveryData = {
handle,
code,
newPassword,
};
const response = await fetch('/api/users/recover-step2', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrfToken,
2024-04-07 22:08:19 +02:00
},
body: JSON.stringify(recoveryData),
});
if (!response.ok) {
const errorData = await response.json();
return displayError(errorData.error || 'An error occurred');
}
console.log(`Successfully recovered password for ${handle}!`);
await performLogin(handle, newPassword);
}
/**
* Attempts to log in the user.
* @param {string} handle User's handle
* @param {string} password User's password
* @returns {Promise<void>}
*/
2024-04-07 22:08:19 +02:00
async function performLogin(handle, password) {
const userInfo = {
handle: handle,
password: password,
};
try {
const response = await fetch('/api/users/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrfToken,
2024-04-07 22:08:19 +02:00
},
body: JSON.stringify(userInfo),
});
if (!response.ok) {
const errorData = await response.json();
return displayError(errorData.error || 'An error occurred');
}
const data = await response.json();
if (data.handle) {
console.log(`Successfully logged in as ${handle}!`);
redirectToHome();
}
} catch (error) {
console.error('Error logging in:', error);
displayError(String(error));
}
}
/**
* Handles the user selection event.
* @param {object} user User object
* @returns {Promise<void>}
*/
async function onUserSelected(user) {
// No password, just log in
if (!user.password) {
return await performLogin(user.handle, '');
}
$('#passwordRecoveryBlock').hide();
$('#passwordEntryBlock').show();
$('#loginButton').off('click').on('click', async () => {
const password = String($('#userPassword').val());
await performLogin(user.handle, password);
});
$('#recoverPassword').off('click').on('click', async () => {
await sendRecoveryPart1(user.handle);
});
$('#sendRecovery').off('click').on('click', async () => {
const code = String($('#recoveryCode').val());
const newPassword = String($('#newPassword').val());
await sendRecoveryPart2(user.handle, code, newPassword);
});
displayError('');
}
/**
* Displays an error message to the user.
* @param {string} message Error message
*/
function displayError(message) {
$('#errorMessage').text(message);
}
/**
* Redirects the user to the home page.
* Preserves the query string.
*/
2024-04-07 22:08:19 +02:00
function redirectToHome() {
window.location.href = '/' + window.location.search;
2024-04-07 22:08:19 +02:00
}
/**
* Hides the password entry block and shows the password recovery block.
*/
2024-04-07 22:08:19 +02:00
function showRecoveryBlock() {
$('#passwordEntryBlock').hide();
$('#passwordRecoveryBlock').show();
displayError('');
}
/**
* Hides the password recovery block and shows the password entry block.
*/
2024-04-07 22:08:19 +02:00
function onCancelRecoveryClick() {
$('#passwordRecoveryBlock').hide();
$('#passwordEntryBlock').show();
displayError('');
}
2024-04-10 21:00:08 +02:00
/**
* 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();
2024-04-07 22:08:19 +02:00
console.log(userList);
for (const user of userList) {
const userBlock = $('<div></div>').addClass('userSelect');
const avatarBlock = $('<div></div>').addClass('avatar');
avatarBlock.append($('<img>').attr('src', user.avatar));
userBlock.append(avatarBlock);
2024-04-13 16:52:37 +02:00
userBlock.append($('<span></span>').addClass('userName').text(user.name));
userBlock.append($('<small></small>').addClass('userHandle').text(user.handle));
2024-04-07 22:08:19 +02:00
userBlock.on('click', () => onUserSelected(user));
$('#userList').append(userBlock);
}
2024-04-10 21:00:08 +02:00
}
/**
* 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 = '';
2024-04-07 22:08:19 +02:00
$('#cancelRecovery').on('click', onCancelRecoveryClick);
$(document).on('keydown', (evt) => {
if (evt.key === 'Enter' && document.activeElement.tagName === 'INPUT') {
if ($('#passwordRecoveryBlock').is(':visible')) {
$('#sendRecovery').trigger('click');
} else {
$('#loginButton').trigger('click');
}
}
});
2024-04-07 22:08:19 +02:00
})();