102 lines
3.0 KiB
JavaScript
102 lines
3.0 KiB
JavaScript
const gensaltBtn = document.getElementById('gensaltBtn');
|
|
const algorithm = document.getElementById('algorithm');
|
|
const password = document.getElementById('password');
|
|
const salt = document.getElementById('salt');
|
|
const hashBtn = document.getElementById('hashBtn');
|
|
const result = document.getElementById('result');
|
|
const clearBtn = document.getElementById('clearBtn');
|
|
const resultBtn = document.getElementById('resultBtn');
|
|
const username = document.getElementById('username');
|
|
|
|
const MIN_PASS_LEN = 16;
|
|
const MIN_SALT_LEN = 8;
|
|
const MAX_SALT_LEN = 16;
|
|
|
|
gensaltBtn.addEventListener('click', async () => {
|
|
const len = MAX_SALT_LEN; // can be adjusted or user-defined
|
|
const res = await fetch('/gensalt?length=' + len);
|
|
if (!res.ok) { alert('Could not generate salt'); return; }
|
|
const data = await res.json();
|
|
salt.value = data.salt;
|
|
});
|
|
|
|
const updateUI = () => {
|
|
const isCopyparty = algorithm.value === 'argon2_copyparty';
|
|
|
|
salt.disabled = isCopyparty;
|
|
gensaltBtn.disabled = isCopyparty;
|
|
username.disabled = !isCopyparty;
|
|
|
|
if (isCopyparty) {
|
|
salt.value = "LVZ1TJMdAIdLyBla6nWDexFt";
|
|
salt.style.opacity = "0.5";
|
|
} else {
|
|
salt.value = "";
|
|
salt.style.opacity = "";
|
|
username.value = "";
|
|
}
|
|
};
|
|
|
|
algorithm.addEventListener('change', updateUI);
|
|
window.addEventListener('DOMContentLoaded', updateUI);
|
|
|
|
hashBtn.addEventListener('click', async () => {
|
|
const pass = password.value || '';
|
|
const s = salt.value || '';
|
|
const alg = algorithm.value;
|
|
const usr = username.value || '';
|
|
|
|
if (pass.length < MIN_PASS_LEN) {
|
|
alert('Password must be at least ' + MIN_PASS_LEN + ' characters');
|
|
return;
|
|
}
|
|
|
|
if (alg !== 'argon2_copyparty') {
|
|
if (s.length < MIN_SALT_LEN || s.length > MAX_SALT_LEN) {
|
|
alert('Salt must be between ' + MIN_SALT_LEN + ' and ' + MAX_SALT_LEN + ' characters');
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (alg == 'argon2_copyparty') {
|
|
if (usr === '') {
|
|
alert('Please type your username.');
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
const payload = { username: usr, password: pass, salt: s, algorithm: alg };
|
|
const res = await fetch('/hash', {
|
|
method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload)
|
|
});
|
|
|
|
if (!res.ok) {
|
|
const txt = await res.text();
|
|
alert('Error: ' + txt);
|
|
return;
|
|
}
|
|
|
|
const data = await res.json();
|
|
result.textContent = data.hash;
|
|
});
|
|
|
|
clearBtn.addEventListener('click', () => {
|
|
password.value = '';
|
|
salt.value = '';
|
|
result.textContent = 'Result will appear here';
|
|
});
|
|
|
|
resultBtn.addEventListener('click', async () => {
|
|
if (!result.textContent || result.textContent === 'Result will appear here') {
|
|
alert('Nothing to copy.');
|
|
}
|
|
|
|
try {
|
|
await navigator.clipboard.writeText(result.textContent);
|
|
alert('Copied to clipboard.');
|
|
} catch (err) {
|
|
alert('Failed to copy: ' + err);
|
|
}
|
|
});
|