Files
Ausweis/frontend/example-html/script.js
2023-10-02 23:39:20 +02:00

125 lines
3.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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