Spaces:
Running
Running
save load keys
Browse files- index.html +3 -2
- wasm-demo.js +85 -24
index.html
CHANGED
@@ -403,8 +403,9 @@ sequenceDiagram
|
|
403 |
<p id="keygenStatus" class="status" aria-live="polite">Ready to generate keys</p>
|
404 |
<span id="keygenSpin" class="loader" hidden aria-label="Generating keys"></span>
|
405 |
</div>
|
406 |
-
<div style="margin-top:
|
407 |
-
<button id="btnKeygen"
|
|
|
408 |
</div>
|
409 |
</div>
|
410 |
</section>
|
|
|
403 |
<p id="keygenStatus" class="status" aria-live="polite">Ready to generate keys</p>
|
404 |
<span id="keygenSpin" class="loader" hidden aria-label="Generating keys"></span>
|
405 |
</div>
|
406 |
+
<div style="display:flex; gap:var(--spacing-unit); margin-top:auto">
|
407 |
+
<button id="btnKeygen" class="btn" aria-describedby="keygenStatus">π Generate keys</button>
|
408 |
+
<button id="btnLoadSaved" class="btn" aria-describedby="keygenStatus">ποΈ Load keys</button>
|
409 |
</div>
|
410 |
</div>
|
411 |
</section>
|
wasm-demo.js
CHANGED
@@ -26,6 +26,22 @@ function uint8ToBase64(uint8) {
|
|
26 |
});
|
27 |
}
|
28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
const $ = id => document.getElementById(id);
|
30 |
const enable = (id, ok=true) => $(id).disabled = !ok;
|
31 |
const show = (id, visible=true) => $(id).hidden = !visible;
|
@@ -55,29 +71,7 @@ show('tokenizerSpin', false);
|
|
55 |
|
56 |
try {
|
57 |
// Initialize encryption worker
|
58 |
-
|
59 |
-
encryptWorker.onmessage = function(e) {
|
60 |
-
if (e.data.type === 'ready') {
|
61 |
-
console.log('[Main] Encryption worker ready');
|
62 |
-
} else if (e.data.type === 'success') {
|
63 |
-
encTokens = e.data.result;
|
64 |
-
console.log(`[Main] Encryption completed: ${encTokens.length} bytes`);
|
65 |
-
show('encryptSpin', false);
|
66 |
-
show('encIcon', true);
|
67 |
-
enable('btnEncrypt', true);
|
68 |
-
enable('btnSend');
|
69 |
-
$('encStatus').textContent = 'Your text is encrypted π';
|
70 |
-
} else if (e.data.type === 'error') {
|
71 |
-
console.error('[Main] Encryption error:', e.data.error);
|
72 |
-
show('encryptSpin', false);
|
73 |
-
enable('btnEncrypt', true);
|
74 |
-
$('encStatus').textContent = `Encryption failed: ${e.data.error}`;
|
75 |
-
alert(`Encryption failed: ${e.data.error}`);
|
76 |
-
}
|
77 |
-
};
|
78 |
-
|
79 |
-
// Initialize the worker with the client key
|
80 |
-
encryptWorker.postMessage({ type: 'init', clientKey });
|
81 |
|
82 |
console.log('[Main] Sending server key to server...');
|
83 |
$('keygenStatus').textContent = 'Keys generated, sending server key...';
|
@@ -104,6 +98,14 @@ show('tokenizerSpin', false);
|
|
104 |
console.log('[Main] Server key sent and UID received:', sessionUid);
|
105 |
$('keygenStatus').textContent = 'Keys generated & UID received β';
|
106 |
enable('btnEncrypt');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
107 |
} catch (error) {
|
108 |
console.error('[Main] Server key submission error:', error);
|
109 |
$('keygenStatus').textContent = `Server key submission failed: ${error.message}`;
|
@@ -140,6 +142,39 @@ $('btnKeygen').onclick = async () => {
|
|
140 |
}
|
141 |
};
|
142 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
143 |
// Add token counter functionality
|
144 |
$('tokenInput').addEventListener('input', () => {
|
145 |
const text = $('tokenInput').value.trim();
|
@@ -361,4 +396,30 @@ $('btnDecrypt').onclick = () => {
|
|
361 |
console.error('[Main] Decryption error:', e);
|
362 |
$('decResult').textContent = `Decryption failed: ${e.message}`;
|
363 |
}
|
364 |
-
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
});
|
27 |
}
|
28 |
|
29 |
+
// βββ local key cache helpers ββββββββββββββββββββββββββββββ
|
30 |
+
const KEYS_STORAGE_KEY = 'synthid_keys_v1';
|
31 |
+
|
32 |
+
/** base64 β Uint8Array (works in all browsers, avoids atob size limits) */
|
33 |
+
function base64ToUint8(base64) {
|
34 |
+
const binStr = atob(base64);
|
35 |
+
const len = binStr.length;
|
36 |
+
const bytes = new Uint8Array(len);
|
37 |
+
for (let i = 0; i < len; i++) bytes[i] = binStr.charCodeAt(i);
|
38 |
+
return bytes;
|
39 |
+
}
|
40 |
+
|
41 |
+
function getSavedKeys() { return JSON.parse(localStorage.getItem(KEYS_STORAGE_KEY) || '{}'); }
|
42 |
+
function saveKeys(map) { localStorage.setItem(KEYS_STORAGE_KEY, JSON.stringify(map)); }
|
43 |
+
function saveKeyset(uid, b64){ const m = getSavedKeys(); m[uid] = b64; saveKeys(m); }
|
44 |
+
|
45 |
const $ = id => document.getElementById(id);
|
46 |
const enable = (id, ok=true) => $(id).disabled = !ok;
|
47 |
const show = (id, visible=true) => $(id).hidden = !visible;
|
|
|
71 |
|
72 |
try {
|
73 |
// Initialize encryption worker
|
74 |
+
initEncryptWorkerWithKey(clientKey);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
|
76 |
console.log('[Main] Sending server key to server...');
|
77 |
$('keygenStatus').textContent = 'Keys generated, sending server key...';
|
|
|
98 |
console.log('[Main] Server key sent and UID received:', sessionUid);
|
99 |
$('keygenStatus').textContent = 'Keys generated & UID received β';
|
100 |
enable('btnEncrypt');
|
101 |
+
|
102 |
+
// Persist clientKey β· uid for reuse
|
103 |
+
uint8ToBase64(clientKey)
|
104 |
+
.then(b64 => {
|
105 |
+
saveKeyset(sessionUid, b64);
|
106 |
+
console.log(`[Main] Saved clientKey for uid ${sessionUid} to localStorage`);
|
107 |
+
})
|
108 |
+
.catch(err => console.warn('[Main] Failed to save key:', err));
|
109 |
} catch (error) {
|
110 |
console.error('[Main] Server key submission error:', error);
|
111 |
$('keygenStatus').textContent = `Server key submission failed: ${error.message}`;
|
|
|
142 |
}
|
143 |
};
|
144 |
|
145 |
+
$('btnLoadSaved').onclick = async () => {
|
146 |
+
const saved = getSavedKeys();
|
147 |
+
const ids = Object.keys(saved);
|
148 |
+
if (!ids.length) {
|
149 |
+
alert('No saved keys found on this machine.');
|
150 |
+
return;
|
151 |
+
}
|
152 |
+
|
153 |
+
// Very lightweight UI: ask which uid to use
|
154 |
+
const uid = prompt(
|
155 |
+
`Saved key sets:\n${ids.join('\n')}\n\nEnter the uid you want to use:`,
|
156 |
+
ids[0]
|
157 |
+
);
|
158 |
+
if (!uid || !saved[uid]) {
|
159 |
+
alert('Invalid or unknown uid.');
|
160 |
+
return;
|
161 |
+
}
|
162 |
+
|
163 |
+
try {
|
164 |
+
sessionUid = uid;
|
165 |
+
clientKey = base64ToUint8(saved[uid]);
|
166 |
+
|
167 |
+
// Make sure we have an encryption worker ready
|
168 |
+
initEncryptWorkerWithKey(clientKey);
|
169 |
+
|
170 |
+
$('keygenStatus').textContent = `Loaded saved keys for ${uid} β`;
|
171 |
+
enable('btnEncrypt');
|
172 |
+
} catch (err) {
|
173 |
+
console.error('[Main] Failed to load key:', err);
|
174 |
+
alert(`Failed to load saved key: ${err.message}`);
|
175 |
+
}
|
176 |
+
};
|
177 |
+
|
178 |
// Add token counter functionality
|
179 |
$('tokenInput').addEventListener('input', () => {
|
180 |
const text = $('tokenInput').value.trim();
|
|
|
396 |
console.error('[Main] Decryption error:', e);
|
397 |
$('decResult').textContent = `Decryption failed: ${e.message}`;
|
398 |
}
|
399 |
+
};
|
400 |
+
|
401 |
+
function encryptWorker_onmessage(e) {
|
402 |
+
if (e.data.type === 'ready') {
|
403 |
+
console.log('[Main] Encryption worker ready');
|
404 |
+
} else if (e.data.type === 'success') {
|
405 |
+
encTokens = e.data.result;
|
406 |
+
console.log(`[Main] Encryption completed: ${encTokens.length} bytes`);
|
407 |
+
show('encryptSpin', false);
|
408 |
+
show('encIcon', true);
|
409 |
+
enable('btnEncrypt', true);
|
410 |
+
enable('btnSend');
|
411 |
+
$('encStatus').textContent = 'Your text is encrypted π';
|
412 |
+
} else if (e.data.type === 'error') {
|
413 |
+
console.error('[Main] Encryption error:', e.data.error);
|
414 |
+
show('encryptSpin', false);
|
415 |
+
enable('btnEncrypt', true);
|
416 |
+
$('encStatus').textContent = `Encryption failed: ${e.data.error}`;
|
417 |
+
alert(`Encryption failed: ${e.data.error}`);
|
418 |
+
}
|
419 |
+
}
|
420 |
+
|
421 |
+
function initEncryptWorkerWithKey(keyUint8) {
|
422 |
+
encryptWorker = new Worker(new URL('./encrypt-worker.js', import.meta.url), { type: 'module' });
|
423 |
+
encryptWorker.onmessage = encryptWorker_onmessage;
|
424 |
+
encryptWorker.postMessage({ type: 'init', clientKey: keyUint8 });
|
425 |
+
}
|