1
0
Fork 0
mirror of https://github.com/M66B/FairEmail.git synced 2024-12-23 00:06:27 +00:00
FairEmail/decrypt/index.html

231 lines
7.9 KiB
HTML
Raw Normal View History

2022-10-17 07:35:03 +00:00
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
2022-10-19 07:04:18 +00:00
<title>FairEmail - Decrypt</title>
2022-10-18 08:08:10 +00:00
<link rel="shortcut icon" href="https://raw.githubusercontent.com/M66B/FairEmail/master/app/src/main/ic_launcher-web.png">
2022-10-17 07:35:03 +00:00
<meta name="theme-color" content="#006db3">
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
2022-10-19 07:04:18 +00:00
<meta name="description" content="Decrypt password protected content">
2022-10-17 07:35:03 +00:00
<meta name="author" content="M66B">
<meta name="robots" content="noindex">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
2022-10-18 08:08:10 +00:00
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/Sources#sources -->
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self' 'unsafe-inline'; img-src data: https://raw.githubusercontent.com/M66B/FairEmail/master/app/src/main/ic_launcher-web.png;">
2022-10-17 07:35:03 +00:00
<style>
body { padding-left: 10px; padding-right: 10px; font-family: Arial, Helvetica, sans-serif; }
2022-10-19 05:51:27 +00:00
.button { display: inline-block; text-align: center; cursor: pointer; }
.button span:first-child { font-size: x-large; }
.button span:last-child { font-size: smaller; }
2022-10-17 07:35:03 +00:00
</style>
<style>
.noscript { display: none; }
</style>
<noscript>
<style>
.noscript { display: block; }
</style>
</noscript>
2022-10-17 16:40:41 +00:00
<!-- https://github.com/cure53/DOMPurify 2.4.0 -->
2022-10-18 08:08:10 +00:00
<script src="purify.min.js"></script>
2022-10-17 16:40:41 +00:00
2022-10-17 07:35:03 +00:00
<script>
window.addEventListener('load', load);
function load() {
2022-10-19 05:51:27 +00:00
const form = document.getElementById('form')
const message = document.getElementById('message');
const copy = document.getElementById('copy');
const email = document.getElementById('email');
const close = document.getElementById('close');
const error = document.getElementById('error');
const details = document.getElementById('details');
const year = document.getElementById('year');
2022-10-17 13:33:51 +00:00
form.addEventListener('submit', submit);
2022-10-17 07:35:03 +00:00
if (window.location.hash)
if (crypto.subtle &&
typeof Uint8Array === 'function' &&
typeof TextEncoder === 'function') {
2022-10-17 13:33:51 +00:00
form.style.display = 'block';
2022-10-18 15:20:19 +00:00
form.password.focus();
2022-10-17 07:35:03 +00:00
}
else {
2022-10-17 18:15:11 +00:00
error.textContent = 'Your browser is unsuitable for decrypting content';
2022-10-17 13:33:51 +00:00
error.style.display = 'block';
details.innerHTML =
2022-10-17 07:35:03 +00:00
'crypto.subtle: ' + (crypto.subtle ? 'Yes' : 'No') + '<br>' +
'Uint8Array: ' + (Uint8Array ? 'Yes' : 'No') + '<br>' +
'TextEncoder: ' + (TextEncoder ? 'Yes' : 'No') + '<br>';
2022-10-17 13:33:51 +00:00
details.style.display = 'block';
2022-10-17 07:35:03 +00:00
}
else {
2022-10-18 15:20:19 +00:00
error.textContent = 'Nothing to see here';
error.style.display = 'block';
2022-10-17 07:35:03 +00:00
}
2022-10-18 20:20:13 +00:00
copy.onclick = function (event) {
event.preventDefault();
const blob = new Blob([message.innerHTML], { type: 'text/html' });
const clip = new ClipboardItem({ 'text/html': blob });
navigator.clipboard.write([clip]).then(function() {
alert('Copied to clipboard');
}, function() {
alert('Copy failed');
});
}
2022-10-18 20:51:01 +00:00
email.onclick = function (event) {
event.preventDefault();
window.location.href = "mailto:?body=" + encodeURIComponent(message.textContent);
}
2022-10-19 05:51:27 +00:00
close.onclick = function (event) {
event.preventDefault();
form.fields.disabled = false;
form.style.display = 'block';
content.style.display = 'none';
message.innerHTML = '';
form.password.focus();
}
2022-10-18 20:20:13 +00:00
year.textContent = new Date().getFullYear();
2022-10-17 07:35:03 +00:00
}
2022-10-17 13:33:51 +00:00
function submit(event) {
2022-10-17 07:35:03 +00:00
event.preventDefault();
decrypt();
}
async function decrypt() {
2022-10-19 05:51:27 +00:00
const form = document.getElementById('form')
const content = document.getElementById('content');
const message = document.getElementById('message');
const error = document.getElementById('error');
const details = document.getElementById('details');
2022-10-17 13:33:51 +00:00
2022-10-17 07:35:03 +00:00
try {
2022-10-18 15:20:19 +00:00
form.fields.disabled = true;
content.style.display = 'none';
2022-10-17 13:33:51 +00:00
error.style.display = 'none';
details.style.display = 'none';
2022-10-18 15:20:19 +00:00
if (!form.password.value)
2022-10-17 07:35:03 +00:00
throw new Error('Password required');
2022-10-17 13:33:51 +00:00
2022-10-19 05:51:27 +00:00
const dirty = await _decrypt(form.password.value);
const clean = DOMPurify.sanitize(dirty, { USE_PROFILES: { html: true } });
2022-10-17 13:33:51 +00:00
2022-10-19 05:51:27 +00:00
form.password.value = '';
2022-10-17 16:40:41 +00:00
message.innerHTML = clean;
2022-10-19 05:51:27 +00:00
form.style.display = 'none';
2022-10-18 15:20:19 +00:00
content.style.display = 'block';
2022-10-17 07:35:03 +00:00
} catch (e) {
console.log("%O", e);
2022-10-18 15:20:19 +00:00
form.fields.disabled = false;
form.password.value = '';
form.password.focus();
2022-10-17 13:33:51 +00:00
error.textContent = 'Could not decrypt the message. Is the password correct?';
error.style.display = 'block';
details.textContent = e.toString();
details.style.display = 'block';
2022-10-17 07:35:03 +00:00
}
}
async function _decrypt(password) {
2022-10-19 05:51:27 +00:00
const msg = atob(window.location.hash.substr(1).replaceAll('-', '+').replaceAll('_', '/'));
2022-10-17 07:35:03 +00:00
const buf = new Uint8Array(msg.length);
for (let i = 0; i < msg.length; i++)
buf[i] = msg.charCodeAt(i);
const version = buf[0];
const salt = buf.slice(1, 1 + 16);
const iv = buf.slice(1 + 16, 1 + 16 + 12);
const e = buf.slice(1 + 16 + 12, buf.length);
// https://developer.mozilla.org/en-US/docs/Web/API/Crypto/subtle
// https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder
const passwordBuffer = new TextEncoder('UTF-8').encode(password);
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 importedEncryptionKey = await crypto.subtle.importKey('raw', derivation, {name: 'AES-GCM'}, false, ['decrypt']);
2022-10-17 13:33:51 +00:00
const decrypted = await crypto.subtle.decrypt({name: 'AES-GCM', iv: iv, tagLength: 128}, importedEncryptionKey, e);
2022-10-17 07:35:03 +00:00
return new TextDecoder('UTF-8').decode(decrypted);
}
</script>
</head>
<body>
<p class="noscript" style="color: red; font-weight: bold;">Please enable JavaScript</p>
2022-10-17 13:33:51 +00:00
<form id="form" action="#" method="GET" style="display: none;">
2022-10-17 07:35:03 +00:00
<p>
2022-10-17 18:15:11 +00:00
Someone sent you password protected content with <a href="https://email.faircode.eu/" target="_blank">FairEmail</a>.
2022-10-17 07:35:03 +00:00
</p>
2022-10-18 08:54:24 +00:00
<p>
The sender should have provided the password.
</p>
2022-10-19 08:44:01 +00:00
<hr>
2022-10-17 07:35:03 +00:00
<fieldset id="fields" style="border:0 none; margin: 0; padding: 0;">
<p>
2022-10-19 05:51:27 +00:00
<label for="password">Enter password &#x1F511;</label><br>
2022-10-17 07:35:03 +00:00
<input id="password" name="password" type="password" required><br>
<span style="font-size: smaller;">Passwords are case-sensitive </span>
</p>
<p>
2022-10-19 05:51:27 +00:00
<input id="submit" style="padding: 3px;" type="submit" value="&#x1F513; Decrypt">
2022-10-17 07:35:03 +00:00
</p>
</fieldset>
<p style="font-size: smaller;">
2022-10-17 18:15:11 +00:00
Passwords, encrypted, and decrypted content stay in your own browser. See <a href="https://github.com/M66B/FairEmail/blob/master/FAQ.md#user-content-faq184" target="_blank">here</a> for more information.
2022-10-17 07:35:03 +00:00
</p>
2022-10-19 08:44:01 +00:00
<hr>
2022-10-17 07:35:03 +00:00
</form>
2022-10-18 15:20:19 +00:00
<div id="content" style="display: none; width: 100%;">
2022-10-19 05:51:27 +00:00
<p>The sender sent you this password protected content with <a href="https://email.faircode.eu/" target="_blank">FairEmail</a>:</p>
<hr style="margin-top: 30px;">
2022-10-18 15:20:19 +00:00
<p id="message" style="width: 100%;"></p>
2022-10-19 05:51:27 +00:00
<hr style="margin-bottom: 30px;">
<div>
<div id="copy" class="button">
<span>&#x1f4cb;</span><br>
<span>Copy</span>
</div>
&ensp;
<div id="email" class="button">
<span>&#x1F4E7;</span><br>
<span>Email</span>
2022-10-18 21:03:21 +00:00
</div>
&ensp;
2022-10-19 05:51:27 +00:00
<div id="close" class="button">
<span>&#x2715;</span><br>
<span>Close</span>
2022-10-18 21:03:21 +00:00
</div>
</div>
2022-10-18 15:20:19 +00:00
</div>
2022-10-17 07:35:03 +00:00
<p id="error" style="color: red; font-weight: bold; display: none;"></p>
<p id="details" style="font-size: x-small; display: none;"></p>
2022-10-19 05:51:27 +00:00
<p style="padding-top: 30px;">
2022-10-17 07:35:03 +00:00
Copyright &copy; 2018&ndash;<span id="year">2022</span> by Marcel Bokhorst (M66B)
<br>
<br>
<span style="font-size: smaller;">This page is <a href="https://github.com/M66B/FairEmail/blob/master/decrypt/index.html" target="_blank">open source</a>.</span>
</p>
</body>
</html>