|
|
@ -30,61 +30,77 @@
|
|
|
|
window.addEventListener('load', load);
|
|
|
|
window.addEventListener('load', load);
|
|
|
|
|
|
|
|
|
|
|
|
function load() {
|
|
|
|
function load() {
|
|
|
|
document.getElementById('getpassword').addEventListener('submit', getpassword);
|
|
|
|
let form = document.getElementById('form')
|
|
|
|
|
|
|
|
let password = document.getElementById('password');
|
|
|
|
|
|
|
|
let message = document.getElementById('message');
|
|
|
|
|
|
|
|
let error = document.getElementById('error');
|
|
|
|
|
|
|
|
let details = document.getElementById('details');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
form.addEventListener('submit', submit);
|
|
|
|
|
|
|
|
|
|
|
|
if (window.location.hash)
|
|
|
|
if (window.location.hash)
|
|
|
|
if (crypto.subtle &&
|
|
|
|
if (crypto.subtle &&
|
|
|
|
typeof Uint8Array === 'function' &&
|
|
|
|
typeof Uint8Array === 'function' &&
|
|
|
|
typeof TextEncoder === 'function') {
|
|
|
|
typeof TextEncoder === 'function') {
|
|
|
|
document.getElementById('getpassword').style.display = 'block';
|
|
|
|
form.style.display = 'block';
|
|
|
|
document.getElementById('password').focus();
|
|
|
|
password.focus();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
else {
|
|
|
|
document.getElementById('error').textContent = 'Your browser is not suitable for decrypting messages';
|
|
|
|
error.textContent = 'Your browser is unsuitable for decrypting text';
|
|
|
|
document.getElementById('error').style.display = 'block';
|
|
|
|
error.style.display = 'block';
|
|
|
|
document.getElementById('details').innerHTML =
|
|
|
|
details.innerHTML =
|
|
|
|
'crypto.subtle: ' + (crypto.subtle ? 'Yes' : 'No') + '<br>' +
|
|
|
|
'crypto.subtle: ' + (crypto.subtle ? 'Yes' : 'No') + '<br>' +
|
|
|
|
'Uint8Array: ' + (Uint8Array ? 'Yes' : 'No') + '<br>' +
|
|
|
|
'Uint8Array: ' + (Uint8Array ? 'Yes' : 'No') + '<br>' +
|
|
|
|
'TextEncoder: ' + (TextEncoder ? 'Yes' : 'No') + '<br>';
|
|
|
|
'TextEncoder: ' + (TextEncoder ? 'Yes' : 'No') + '<br>';
|
|
|
|
document.getElementById('details').style.display = 'block';
|
|
|
|
details.style.display = 'block';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
else {
|
|
|
|
document.getElementById('message').textContent = 'Nothing to see here';
|
|
|
|
message.innerHTML = 'Nothing to see here';
|
|
|
|
document.getElementById('message').style.display = 'block';
|
|
|
|
message.style.display = 'block';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
document.getElementById('year').textContent = new Date().getFullYear();
|
|
|
|
document.getElementById('year').textContent = new Date().getFullYear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function getpassword(event) {
|
|
|
|
function submit(event) {
|
|
|
|
event.preventDefault();
|
|
|
|
event.preventDefault();
|
|
|
|
decrypt();
|
|
|
|
decrypt();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function decrypt() {
|
|
|
|
async function decrypt() {
|
|
|
|
document.getElementById('fields').disabled = true;
|
|
|
|
let fields = document.getElementById('fields');
|
|
|
|
|
|
|
|
let form = document.getElementById('form')
|
|
|
|
|
|
|
|
let password = document.getElementById('password');
|
|
|
|
|
|
|
|
let message = document.getElementById('message');
|
|
|
|
|
|
|
|
let error = document.getElementById('error');
|
|
|
|
|
|
|
|
let details = document.getElementById('details');
|
|
|
|
|
|
|
|
let copyright = document.getElementById('copyright');
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
document.getElementById('message').style.display = 'none';
|
|
|
|
fields.disabled = true;
|
|
|
|
document.getElementById('error').style.display = 'none';
|
|
|
|
message.style.display = 'none';
|
|
|
|
document.getElementById('details').style.display = 'none';
|
|
|
|
error.style.display = 'none';
|
|
|
|
let password = document.getElementById('password').value;
|
|
|
|
details.style.display = 'none';
|
|
|
|
if (password) {
|
|
|
|
|
|
|
|
let message = await _decrypt(password);
|
|
|
|
if (!password.value)
|
|
|
|
document.getElementById('getpassword').style.display = 'none';
|
|
|
|
|
|
|
|
document.getElementById('message').innerHTML = message;
|
|
|
|
|
|
|
|
document.getElementById('message').style.display = 'block';
|
|
|
|
|
|
|
|
document.getElementById('copyright').style.display = 'none';
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
throw new Error('Password required');
|
|
|
|
throw new Error('Password required');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let html = await _decrypt(password.value);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
form.style.display = 'none';
|
|
|
|
|
|
|
|
message.innerHTML = html;
|
|
|
|
|
|
|
|
message.style.display = 'block';
|
|
|
|
|
|
|
|
copyright.style.display = 'none';
|
|
|
|
} catch (e) {
|
|
|
|
} catch (e) {
|
|
|
|
console.log("%O", e);
|
|
|
|
console.log("%O", e);
|
|
|
|
document.getElementById('password').value = '';
|
|
|
|
fields.disabled = false;
|
|
|
|
document.getElementById('error').textContent = 'Could not decrypt the message. Is the password correct?';
|
|
|
|
password.value = '';
|
|
|
|
document.getElementById('error').style.display = 'block';
|
|
|
|
password.focus();
|
|
|
|
document.getElementById('details').textContent = e.toString();
|
|
|
|
error.textContent = 'Could not decrypt the message. Is the password correct?';
|
|
|
|
document.getElementById('details').style.display = 'block';
|
|
|
|
error.style.display = 'block';
|
|
|
|
|
|
|
|
details.textContent = e.toString();
|
|
|
|
|
|
|
|
details.style.display = 'block';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
document.getElementById('fields').disabled = false;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function _decrypt(password) {
|
|
|
|
async function _decrypt(password) {
|
|
|
@ -105,7 +121,7 @@
|
|
|
|
const importedKey = await crypto.subtle.importKey('raw', passwordBuffer, 'PBKDF2', false, ['deriveBits']);
|
|
|
|
const importedKey = await crypto.subtle.importKey('raw', passwordBuffer, 'PBKDF2', false, ['deriveBits']);
|
|
|
|
const derivation = await crypto.subtle.deriveBits({name: 'PBKDF2', hash: 'SHA-512', salt: salt, iterations: 120000}, importedKey, 256);
|
|
|
|
const derivation = await crypto.subtle.deriveBits({name: 'PBKDF2', hash: 'SHA-512', salt: salt, iterations: 120000}, importedKey, 256);
|
|
|
|
const importedEncryptionKey = await crypto.subtle.importKey('raw', derivation, {name: 'AES-GCM'}, false, ['decrypt']);
|
|
|
|
const importedEncryptionKey = await crypto.subtle.importKey('raw', derivation, {name: 'AES-GCM'}, false, ['decrypt']);
|
|
|
|
const decrypted = await window.crypto.subtle.decrypt({name: 'AES-GCM', iv: iv, tagLength: 128}, importedEncryptionKey, e);
|
|
|
|
const decrypted = await crypto.subtle.decrypt({name: 'AES-GCM', iv: iv, tagLength: 128}, importedEncryptionKey, e);
|
|
|
|
|
|
|
|
|
|
|
|
return new TextDecoder('UTF-8').decode(decrypted);
|
|
|
|
return new TextDecoder('UTF-8').decode(decrypted);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -114,7 +130,7 @@
|
|
|
|
<body>
|
|
|
|
<body>
|
|
|
|
<p class="noscript" style="color: red; font-weight: bold;">Please enable JavaScript</p>
|
|
|
|
<p class="noscript" style="color: red; font-weight: bold;">Please enable JavaScript</p>
|
|
|
|
|
|
|
|
|
|
|
|
<form id="getpassword" action="#" method="GET" style="display: none;">
|
|
|
|
<form id="form" action="#" method="GET" style="display: none;">
|
|
|
|
<p>
|
|
|
|
<p>
|
|
|
|
Someone sent you password protected text with <a href="https://email.faircode.eu/" target="_blank">FairEmail</a>.
|
|
|
|
Someone sent you password protected text with <a href="https://email.faircode.eu/" target="_blank">FairEmail</a>.
|
|
|
|
</p>
|
|
|
|
</p>
|
|
|
|