2023-07-23 15:06:57 +02:00
|
|
|
function base32_nopad_encode(slice) {
|
|
|
|
const encoder = new base32.Encoder({ type: "rfc4648", lc: true });
|
|
|
|
const code = encoder.write(slice).finalize();
|
|
|
|
return code.replaceAll('=', '');
|
|
|
|
}
|
|
|
|
|
|
|
|
function base64_decode(str_b64) {
|
|
|
|
const raw_str = atob(str_b64);
|
|
|
|
const length = raw_str.length;
|
|
|
|
var b = [];
|
|
|
|
for (var i = 0; i < length; i++) {
|
|
|
|
b.push(raw_str.charCodeAt(i));
|
|
|
|
}
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
2023-07-25 18:52:01 +02:00
|
|
|
class Account {
|
2023-07-25 21:46:03 +02:00
|
|
|
constructor(local_part, separator, domain, key) {
|
2023-07-23 15:06:57 +02:00
|
|
|
this.local_part = local_part;
|
|
|
|
this.domain = domain;
|
|
|
|
this.separator = separator;
|
2023-07-25 21:46:03 +02:00
|
|
|
if (Array.isArray(key)) {
|
|
|
|
this.key = key;
|
|
|
|
} else {
|
|
|
|
this.key = base64_decode(key);
|
|
|
|
}
|
2023-07-23 15:06:57 +02:00
|
|
|
}
|
|
|
|
|
2023-07-25 18:50:04 +02:00
|
|
|
getName() {
|
|
|
|
return `${this.local_part}@${this.domain}`;
|
|
|
|
}
|
|
|
|
|
2023-07-23 15:06:57 +02:00
|
|
|
genSubAddr(sub_addr_name) {
|
|
|
|
var hasher = sha256.hmac.create(this.key);
|
|
|
|
hasher.update(this.local_part);
|
|
|
|
hasher.update(this.separator);
|
|
|
|
hasher.update(sub_addr_name);
|
|
|
|
const hash = hasher.array();
|
|
|
|
const offset = hash[hash.length - 1] & 0xf;
|
|
|
|
const reduced_hash = hash.slice(offset, offset + 5);
|
|
|
|
const code = base32_nopad_encode(reduced_hash);
|
|
|
|
return `${this.local_part}${this.separator}${sub_addr_name}${this.separator}${code}@${this.domain}`
|
|
|
|
}
|
2023-07-25 21:46:03 +02:00
|
|
|
|
|
|
|
register() {
|
|
|
|
localStorage.setItem(this.getName(), JSON.stringify(this));
|
|
|
|
}
|
2023-07-23 15:06:57 +02:00
|
|
|
}
|
|
|
|
|
2023-07-25 21:46:03 +02:00
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
// Functions to open and close a modal
|
|
|
|
function openModal() {
|
|
|
|
document.querySelector('#modal-add-account').classList.add('is-active');
|
|
|
|
}
|
|
|
|
|
|
|
|
function closeModal() {
|
|
|
|
if (localStorage.length !== 0) {
|
|
|
|
document.querySelector('#modal-add-account').classList.remove('is-active');
|
|
|
|
syncAccountList();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Function to synchronize the account list
|
|
|
|
function syncAccountList() {
|
|
|
|
var acc_list = document.querySelector('#account-name');
|
|
|
|
while (acc_list.lastElementChild) {
|
|
|
|
acc_list.removeChild(acc_list.lastElementChild);
|
|
|
|
}
|
|
|
|
for (var i = 0, len = localStorage.length; i < len; ++i) {
|
|
|
|
const account_string = localStorage.getItem(localStorage.key(i));
|
|
|
|
const account_raw = JSON.parse(account_string);
|
|
|
|
const account = new Account(
|
|
|
|
account_raw.local_part,
|
|
|
|
account_raw.separator,
|
|
|
|
account_raw.domain,
|
|
|
|
account_raw.key,
|
|
|
|
);
|
|
|
|
const new_elem = new Option(account.getName(), account.getName());
|
|
|
|
acc_list.appendChild(new_elem);
|
|
|
|
}
|
|
|
|
if (localStorage.length === 0) {
|
|
|
|
openModal();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
syncAccountList();
|
|
|
|
|
|
|
|
// Add a click event on buttons to open a specific modal
|
|
|
|
(document.querySelectorAll('.js-modal-trigger') || []).forEach(($trigger) => {
|
|
|
|
$trigger.addEventListener('click', () => {
|
|
|
|
openModal();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// Add a click event on various child elements to close the parent modal
|
|
|
|
(document.querySelectorAll('.modal-background, .modal-close, .modal-card-head .delete, .modal-card-foot .button-close') || []).forEach(($close) => {
|
|
|
|
$close.addEventListener('click', () => {
|
|
|
|
closeModal();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// Add a keyboard event to close all modals
|
|
|
|
document.addEventListener('keydown', (event) => {
|
|
|
|
if (event.code === 'Escape') {
|
|
|
|
closeModal();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// Add a click event on the new account button to register the new account
|
|
|
|
document.querySelector('#btn-new-account').addEventListener('click', (event) => {
|
|
|
|
console.log('Adding new account…');
|
|
|
|
const new_account = new Account(
|
|
|
|
document.querySelector('#new-addr-local-part').value,
|
|
|
|
document.querySelector('#new-addr-separator').value,
|
|
|
|
document.querySelector('#new-addr-domain').value,
|
|
|
|
document.querySelector('#new-addr-key').value,
|
|
|
|
);
|
|
|
|
console.log(new_account);
|
|
|
|
new_account.register();
|
|
|
|
console.log(`Account ${new_account.getName()} added.`);
|
|
|
|
closeModal();
|
|
|
|
});
|
2023-07-23 15:06:57 +02:00
|
|
|
|
2023-07-25 21:46:03 +02:00
|
|
|
// Add a click event on the new address button to generate it
|
|
|
|
document.querySelector('#btn-generate').addEventListener('click', (event) => {
|
|
|
|
console.log('Generating a new address…');
|
|
|
|
event.preventDefault();
|
|
|
|
// TODO
|
2023-07-25 19:01:38 +02:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2023-07-23 15:06:57 +02:00
|
|
|
window.addEventListener('load', () => {
|
|
|
|
if ('serviceWorker' in navigator) {
|
|
|
|
navigator.serviceWorker.register('/sw.js');
|
|
|
|
}
|
|
|
|
});
|