mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Enable CSRF for public endpoints. Split users module. Add rate limiter.
This commit is contained in:
@ -1,15 +1,46 @@
|
||||
/**
|
||||
* CRSF token for requests.
|
||||
*/
|
||||
let csrfToken = '';
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
async function getUserList() {
|
||||
const response = await fetch('/api/users/list');
|
||||
const response = await fetch('/api/users/list', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-Token': csrfToken,
|
||||
},
|
||||
});
|
||||
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>}
|
||||
*/
|
||||
async function sendRecoveryPart1(handle) {
|
||||
const response = await fetch('/api/users/recover-step1', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-Token': csrfToken,
|
||||
},
|
||||
body: JSON.stringify({ handle }),
|
||||
});
|
||||
@ -22,6 +53,13 @@ async function sendRecoveryPart1(handle) {
|
||||
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>}
|
||||
*/
|
||||
async function sendRecoveryPart2(handle, code, newPassword) {
|
||||
const recoveryData = {
|
||||
handle,
|
||||
@ -33,6 +71,7 @@ async function sendRecoveryPart2(handle, code, newPassword) {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-Token': csrfToken,
|
||||
},
|
||||
body: JSON.stringify(recoveryData),
|
||||
});
|
||||
@ -46,6 +85,50 @@ async function sendRecoveryPart2(handle, code, newPassword) {
|
||||
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>}
|
||||
*/
|
||||
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,
|
||||
},
|
||||
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) {
|
||||
@ -72,52 +155,33 @@ async function onUserSelected(user) {
|
||||
displayError('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays an error message to the user.
|
||||
* @param {string} message Error message
|
||||
*/
|
||||
function displayError(message) {
|
||||
$('#errorMessage').text(message);
|
||||
}
|
||||
|
||||
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',
|
||||
},
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirects the user to the home page.
|
||||
*/
|
||||
function redirectToHome() {
|
||||
window.location.href = '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the password entry block and shows the password recovery block.
|
||||
*/
|
||||
function showRecoveryBlock() {
|
||||
$('#passwordEntryBlock').hide();
|
||||
$('#passwordRecoveryBlock').show();
|
||||
displayError('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the password recovery block and shows the password entry block.
|
||||
*/
|
||||
function onCancelRecoveryClick() {
|
||||
$('#passwordRecoveryBlock').hide();
|
||||
$('#passwordEntryBlock').show();
|
||||
@ -125,6 +189,7 @@ function onCancelRecoveryClick() {
|
||||
}
|
||||
|
||||
(async function () {
|
||||
csrfToken = await getCsrfToken();
|
||||
const userList = await getUserList();
|
||||
console.log(userList);
|
||||
for (const user of userList) {
|
||||
@ -137,6 +202,6 @@ function onCancelRecoveryClick() {
|
||||
userBlock.on('click', () => onUserSelected(user));
|
||||
$('#userList').append(userBlock);
|
||||
}
|
||||
document.body.style.display = '';
|
||||
document.getElementById('shadow_popup').style.opacity = '';
|
||||
$('#cancelRecovery').on('click', onCancelRecoveryClick);
|
||||
})();
|
||||
|
Reference in New Issue
Block a user