|
|
import { initAccessibility } from './a11y.js'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let csrfToken = ''; |
|
|
let discreetLogin = false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function getCsrfToken() { |
|
|
const response = await fetch('/csrf-token'); |
|
|
const data = await response.json(); |
|
|
return data.token; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function getUserList() { |
|
|
const response = await fetch('/api/users/list', { |
|
|
method: 'POST', |
|
|
headers: { |
|
|
'Content-Type': 'application/json', |
|
|
'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; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 }), |
|
|
}); |
|
|
|
|
|
if (!response.ok) { |
|
|
const errorData = await response.json(); |
|
|
return displayError(errorData.error || 'An error occurred'); |
|
|
} |
|
|
|
|
|
showRecoveryBlock(); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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, |
|
|
}, |
|
|
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); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function onUserSelected(user) { |
|
|
|
|
|
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(''); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function displayError(message) { |
|
|
$('#errorMessage').text(message); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function redirectToHome() { |
|
|
|
|
|
const currentUrl = new URL(window.location.href); |
|
|
|
|
|
|
|
|
|
|
|
currentUrl.searchParams.delete('noauto'); |
|
|
|
|
|
|
|
|
currentUrl.pathname = '/'; |
|
|
|
|
|
|
|
|
window.location.href = currentUrl.toString(); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function showRecoveryBlock() { |
|
|
$('#passwordEntryBlock').hide(); |
|
|
$('#passwordRecoveryBlock').show(); |
|
|
displayError(''); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function onCancelRecoveryClick() { |
|
|
$('#passwordRecoveryBlock').hide(); |
|
|
$('#passwordEntryBlock').show(); |
|
|
displayError(''); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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'); |
|
|
const avatarBlock = $('<div></div>').addClass('avatar'); |
|
|
avatarBlock.append($('<img>').attr('src', user.avatar)); |
|
|
userBlock.append(avatarBlock); |
|
|
userBlock.append($('<span></span>').addClass('userName').text(user.name)); |
|
|
userBlock.append($('<small></small>').addClass('userHandle').text(user.handle)); |
|
|
userBlock.on('click', () => onUserSelected(user)); |
|
|
$('#userList').append(userBlock); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 () { |
|
|
initAccessibility(); |
|
|
|
|
|
csrfToken = await getCsrfToken(); |
|
|
const userList = await getUserList(); |
|
|
|
|
|
if (discreetLogin) { |
|
|
configureDiscreetLogin(); |
|
|
} else { |
|
|
configureNormalLogin(userList); |
|
|
} |
|
|
document.getElementById('shadow_popup').style.opacity = ''; |
|
|
$('#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'); |
|
|
} |
|
|
} |
|
|
}); |
|
|
})(); |
|
|
|