style: tab indentation
This commit is contained in:
@@ -1,85 +1,85 @@
|
|||||||
async function decrypt(ciphertext, password) {
|
async function decrypt(ciphertext, password) {
|
||||||
const pwUtf8 = new TextEncoder().encode(password);
|
const pwUtf8 = new TextEncoder().encode(password);
|
||||||
const pwHash = await crypto.subtle.digest('SHA-256', pwUtf8);
|
const pwHash = await crypto.subtle.digest('SHA-256', pwUtf8);
|
||||||
const ctUtf8 = new Uint8Array(ciphertext);
|
const ctUtf8 = new Uint8Array(ciphertext);
|
||||||
const iv = ctUtf8.slice(0, 12);
|
const iv = ctUtf8.slice(0, 12);
|
||||||
const alg = { name: 'AES-GCM', iv: iv, additionalData: iv };
|
const alg = { name: 'AES-GCM', iv: iv, additionalData: iv };
|
||||||
const key = await crypto.subtle.importKey('raw', pwHash, alg, false, ['decrypt']);
|
const key = await crypto.subtle.importKey('raw', pwHash, alg, false, ['decrypt']);
|
||||||
try {
|
try {
|
||||||
const buf = await crypto.subtle.decrypt(alg, key, ctUtf8.slice(12));
|
const buf = await crypto.subtle.decrypt(alg, key, ctUtf8.slice(12));
|
||||||
return new TextDecoder().decode(buf);
|
return new TextDecoder().decode(buf);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error('Decrypt failed')
|
throw new Error('Decrypt failed')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setError(text) {
|
function setError(text) {
|
||||||
document.getElementById('msg').innerText = text;
|
document.getElementById('msg').innerText = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setFields(elem, fields) {
|
function setFields(elem, fields) {
|
||||||
for (const [k, v] of Object.entries(fields)) {
|
for (const [k, v] of Object.entries(fields)) {
|
||||||
for (const el of elem.querySelectorAll('#' + k)) {
|
for (const el of elem.querySelectorAll('#' + k)) {
|
||||||
el.innerText = v;
|
el.innerText = v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function apply(data, password) {
|
async function apply(data, password) {
|
||||||
const json = JSON.parse(await decrypt(data, password));
|
const json = JSON.parse(await decrypt(data, password));
|
||||||
const now = new Date().getTime();
|
const now = new Date().getTime();
|
||||||
const vA = new Date(json['valid_since'] + 'T00:00:00');
|
const vA = new Date(json['valid_since'] + 'T00:00:00');
|
||||||
if (vA.getTime() > now) {
|
if (vA.getTime() > now) {
|
||||||
return setError('Member card not valid yet');
|
return setError('Member card not valid yet');
|
||||||
}
|
}
|
||||||
const vZ = new Date(json['valid_until'] + 'T23:59:59');
|
const vZ = new Date(json['valid_until'] + 'T23:59:59');
|
||||||
if (vZ.getTime() < now) {
|
if (vZ.getTime() < now) {
|
||||||
return setError('Member card expired');
|
return setError('Member card expired');
|
||||||
}
|
}
|
||||||
const pass = document.getElementById('pass');
|
const pass = document.getElementById('pass');
|
||||||
const imgElem = pass.querySelector('#img');
|
const imgElem = pass.querySelector('#img');
|
||||||
if (imgElem) {
|
if (imgElem) {
|
||||||
if (json['img']) {
|
if (json['img']) {
|
||||||
imgElem.src = 'data:image;base64,' + json['img'];
|
imgElem.src = 'data:image;base64,' + json['img'];
|
||||||
} else {
|
} else {
|
||||||
imgElem.src = 'img/no-img.svg';
|
imgElem.src = 'img/no-img.svg';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setFields(pass, {
|
setFields(pass, {
|
||||||
name: json['name'],
|
name: json['name'],
|
||||||
member_id: json['id'],
|
member_id: json['id'],
|
||||||
org_name: json['org'],
|
org_name: json['org'],
|
||||||
valid: 'on ' + new Date().toLocaleDateString('en'),
|
valid: 'on ' + new Date().toLocaleDateString('en'),
|
||||||
});
|
});
|
||||||
setFields(pass, json['data']); // may overwrite previous fields
|
setFields(pass, json['data']); // may overwrite previous fields
|
||||||
|
|
||||||
const title = 'Member card for ' + json['name'] + ' – ' + json['org'];
|
const title = 'Member card for ' + json['name'] + ' – ' + json['org'];
|
||||||
document.head.querySelector('title').innerText = title;
|
document.head.querySelector('title').innerText = title;
|
||||||
document.getElementById('msg').classList.add('hidden');
|
document.getElementById('msg').classList.add('hidden');
|
||||||
pass.classList.remove('hidden');
|
pass.classList.remove('hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onLoad() {
|
async function onLoad() {
|
||||||
// reset previous download
|
// reset previous download
|
||||||
document.getElementById('pass').classList.add('hidden');
|
document.getElementById('pass').classList.add('hidden');
|
||||||
const msg = document.getElementById('msg');
|
const msg = document.getElementById('msg');
|
||||||
msg.innerText = msg.dataset.load;
|
msg.innerText = msg.dataset.load;
|
||||||
msg.classList.remove('hidden');
|
msg.classList.remove('hidden');
|
||||||
// download new data
|
// download new data
|
||||||
const [org, uuid, secret] = location.hash.slice(1).split('/');
|
const [org, uuid, secret] = location.hash.slice(1).split('/');
|
||||||
if (!org || !uuid || !secret) {
|
if (!org || !uuid || !secret) {
|
||||||
return setError('Invalid URL');
|
return setError('Invalid URL');
|
||||||
}
|
}
|
||||||
const res = await fetch('./data/' + org + '/' + uuid);
|
const res = await fetch('./data/' + org + '/' + uuid);
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
return setError('Error loading\n\n' + res.status + ' ' + res.statusText);
|
return setError('Error loading\n\n' + res.status + ' ' + res.statusText);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const data = await res.arrayBuffer();
|
const data = await res.arrayBuffer();
|
||||||
await apply(data, secret);
|
await apply(data, secret);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setError(e);
|
setError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// load and parse data
|
// load and parse data
|
||||||
@@ -92,10 +92,10 @@ window.addEventListener('hashchange', onLoad, true);
|
|||||||
// -------------
|
// -------------
|
||||||
|
|
||||||
function onResize() {
|
function onResize() {
|
||||||
const card = document.getElementById('card');
|
const card = document.getElementById('card');
|
||||||
const sw = window.innerWidth / card.offsetWidth;
|
const sw = window.innerWidth / card.offsetWidth;
|
||||||
const sh = window.innerHeight / card.offsetHeight;
|
const sh = window.innerHeight / card.offsetHeight;
|
||||||
card.style.scale = Math.min(Math.min(sw, sh) * 0.97, 2);
|
card.style.scale = Math.min(Math.min(sw, sh) * 0.97, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('resize', onResize, true);
|
window.addEventListener('resize', onResize, true);
|
||||||
@@ -109,16 +109,16 @@ screen?.orientation?.addEventListener('change', onResize, true);
|
|||||||
lastUpdate = new Date().getTime();
|
lastUpdate = new Date().getTime();
|
||||||
|
|
||||||
function needsUpdate() {
|
function needsUpdate() {
|
||||||
// reload page if older than 15min
|
// reload page if older than 15min
|
||||||
const now = new Date().getTime();
|
const now = new Date().getTime();
|
||||||
if (now - lastUpdate > 900_000) {
|
if (now - lastUpdate > 900_000) {
|
||||||
lastUpdate = now;
|
lastUpdate = now;
|
||||||
onLoad();
|
onLoad();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// setInterval(needsUpdate, 1000);
|
// setInterval(needsUpdate, 1000);
|
||||||
window.addEventListener('focus', needsUpdate, true);
|
window.addEventListener('focus', needsUpdate, true);
|
||||||
window.addEventListener('pageshow', needsUpdate, true);
|
window.addEventListener('pageshow', needsUpdate, true);
|
||||||
window.addEventListener('visibilitychange', function () {
|
window.addEventListener('visibilitychange', function () {
|
||||||
!document.hidden && document.visibilityState !== 'hidden' && needsUpdate();
|
!document.hidden && document.visibilityState !== 'hidden' && needsUpdate();
|
||||||
}, true);
|
}, true);
|
||||||
|
|||||||
Reference in New Issue
Block a user