From b970e60de11f2e388bc046b8aa6506bbd647a292 Mon Sep 17 00:00:00 2001 From: James Downie Date: Wed, 1 Apr 2026 17:39:33 +1000 Subject: [PATCH] Added pin numbers for library meetups. --- app/index.js | 60 ++++++++++++++++++++++++++++++++++++++++++++ app/index.php | 18 +++++++++++++ dat/live/events.json | 18 ++++++++++--- 3 files changed, 93 insertions(+), 3 deletions(-) diff --git a/app/index.js b/app/index.js index fa2f16e..6fd744c 100755 --- a/app/index.js +++ b/app/index.js @@ -19,6 +19,66 @@ $(document).ready(function () { window.open( url, target ); } }); + + $('.unlock-pin').click(async function() { + const btn = $(this); + const pinDisplay = btn.siblings('.pin-display'); + const ciphertext = btn.data('ciphertext'); + const iv = btn.data('iv'); + const salt = btn.data('salt'); + const tag = btn.data('tag'); + + const password = prompt("Enter the members password to unlock the PIN:"); + if (!password) return; + + try { + const decrypted = await decryptPin(ciphertext, iv, salt, tag, password); + pinDisplay.val(decrypted); + btn.text('Copy').removeClass('unlock-pin').attr('action', 'copy').attr('value', decrypted); + // Re-bind the click event for the new copy action (or use delegation) + btn.off('click').click(function() { + navigator.clipboard.writeText($(this).attr('value')); + alert('PIN copied to clipboard!'); + }); + } catch (e) { + alert(e.message); + } + }); + + async function decryptPin(ciphertextBase64, ivBase64, saltBase64, tagBase64, password) { + const encoder = new TextEncoder(); + const passwordKey = await crypto.subtle.importKey( + "raw", encoder.encode(password), "PBKDF2", false, ["deriveKey"] + ); + const salt = Uint8Array.from(atob(saltBase64), c => c.charCodeAt(0)); + const iv = Uint8Array.from(atob(ivBase64), c => c.charCodeAt(0)); + const tag = Uint8Array.from(atob(tagBase64), c => c.charCodeAt(0)); + const ciphertext = Uint8Array.from(atob(ciphertextBase64), c => c.charCodeAt(0)); + + const data = new Uint8Array(ciphertext.length + tag.length); + data.set(ciphertext); + data.set(tag, ciphertext.length); + + const key = await crypto.subtle.deriveKey( + { name: "PBKDF2", salt, iterations: 100000, hash: "SHA-256" }, + passwordKey, + { name: "AES-GCM", length: 256 }, + false, + ["decrypt"] + ); + + try { + const decrypted = await crypto.subtle.decrypt( + { name: "AES-GCM", iv, tagLength: 128 }, + key, + data + ); + return new TextDecoder().decode(decrypted); + } catch (e) { + throw new Error("Decryption failed. Probably wrong password."); + } + } + var isPhone = /Mobi|Android|iPhone|iPod/i.test(navigator.userAgent) || window.innerWidth <= 768; if (isPhone) { $("body").addClass("phone"); diff --git a/app/index.php b/app/index.php index a0b59a3..e9260ab 100755 --- a/app/index.php +++ b/app/index.php @@ -137,6 +137,24 @@ use Michelf\Markdown; } ?> + +
+ PIN + + + + + "> + + +
+
Description

diff --git a/dat/live/events.json b/dat/live/events.json index 18566cc..e72e9d9 100755 --- a/dat/live/events.json +++ b/dat/live/events.json @@ -5,7 +5,13 @@ "end": "2026-07-23T21:30", "title": "July 2026 In Person Catch Up", "description": "Monthly In Person Get Together. Check Discourse for room details.", - "location": "Carindale Library" + "location": "Carindale Library", + "pin": { + "ciphertext": "XUFjTcV3", + "iv": "WtpvNa5aSMRMHoVL", + "salt": "jEZ5NzPNSCnhuBzmdybmkw==", + "tag": "cD15oQ0UJM5UNQ8Wb8GlIg==" + } }, { "coordinates": "", @@ -21,7 +27,13 @@ "end": "2026-06-25T21:30", "title": "June 2026 In Person Catch Up", "description": "Monthly In Person Get Together. Check Discourse for room details.", - "location": "Carindale Library" + "location": "Carindale Library", + "pin": { + "ciphertext": "XUFjTcV3", + "iv": "WtpvNa5aSMRMHoVL", + "salt": "jEZ5NzPNSCnhuBzmdybmkw==", + "tag": "cD15oQ0UJM5UNQ8Wb8GlIg==" + } }, { "coordinates": "", @@ -213,4 +225,4 @@ "description": "Getting started with meshtastic", "location": "Jitsi" } -] +] \ No newline at end of file