Files
Letters/js/page-unlock.js
biss 1111372dc9
Vercel Deploy / deploy (push) Successful in 1m44s
jiami
2026-06-20 13:59:26 +08:00

79 lines
2.4 KiB
JavaScript

(function () {
const encoder = new TextEncoder();
const decoder = new TextDecoder();
const form = document.getElementById('unlockForm');
const passwordInput = document.getElementById('letterPassword');
const statusEl = document.getElementById('unlockStatus');
const payloadEl = document.getElementById('encryptedPayload');
function fromBase64(value) {
const binary = atob(value);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i += 1) {
bytes[i] = binary.charCodeAt(i);
}
return bytes;
}
async function deriveKey(password, salt, iterations) {
const baseKey = await crypto.subtle.importKey(
'raw',
encoder.encode(password),
'PBKDF2',
false,
['deriveKey']
);
return crypto.subtle.deriveKey(
{
name: 'PBKDF2',
salt,
iterations,
hash: 'SHA-256'
},
baseKey,
{ name: 'AES-GCM', length: 256 },
false,
['decrypt']
);
}
async function unlock(password) {
const payload = JSON.parse(payloadEl.textContent);
const salt = fromBase64(payload.salt);
const iv = fromBase64(payload.iv);
const ciphertext = fromBase64(payload.ciphertext);
const key = await deriveKey(password, salt, payload.iterations);
const plaintext = await crypto.subtle.decrypt(
{ name: 'AES-GCM', iv },
key,
ciphertext
);
return decoder.decode(plaintext);
}
form.addEventListener('submit', async event => {
event.preventDefault();
const password = passwordInput.value;
if (!password) {
statusEl.textContent = '请输入密码。';
return;
}
statusEl.textContent = '正在解锁...';
form.querySelector('button').disabled = true;
try {
const html = await unlock(password);
document.open();
document.write(html);
document.close();
} catch (error) {
statusEl.textContent = '密码不正确,或页面密文已损坏。';
form.querySelector('button').disabled = false;
passwordInput.select();
}
});
}());