diff options
Diffstat (limited to 'crates/chat-server/web')
| -rw-r--r-- | crates/chat-server/web/app.js | 54 | ||||
| -rw-r--r-- | crates/chat-server/web/index.html | 4 | ||||
| -rw-r--r-- | crates/chat-server/web/javascript.html | 2 |
3 files changed, 53 insertions, 7 deletions
diff --git a/crates/chat-server/web/app.js b/crates/chat-server/web/app.js index 3c97f66..4b0da63 100644 --- a/crates/chat-server/web/app.js +++ b/crates/chat-server/web/app.js @@ -356,12 +356,58 @@ element('lock').addEventListener('click', () => { if (session) api({ op: 'lock' window.addEventListener('pagehide', clearState); window.addEventListener('pageshow', event => { if (event.persisted) clearState(); }); +async function downloadCrypto() { + const controller = new AbortController(); + let timer; + let reader; + const refreshTimeout = () => { + clearTimeout(timer); + timer = setTimeout(() => controller.abort(), 45000); + }; + try { + refreshTimeout(); + const response = await fetch('/crypto.wasm', { cache: 'no-store', credentials: 'omit', signal: controller.signal }); + if (!response.ok) throw new Error(`Cryptographic module download failed (HTTP ${response.status}). Reload to try again.`); + const length = response.headers.get('content-encoding') ? 0 : Number(response.headers.get('content-length')); + const total = Number.isSafeInteger(length) && length > 0 ? length : 0; + const chunks = []; + let received = 0; + const progress = () => { + const loaded = (received / 1048576).toFixed(1); + if (total) { + const percent = Math.min(100, Math.floor(received * 100 / total)); + const filled = Math.floor(percent / 5); + status(`Downloading cryptographic module... [${'#'.repeat(filled)}${'-'.repeat(20 - filled)}] ${percent}% (${loaded} / ${(total / 1048576).toFixed(1)} MiB)`); + } else status(`Downloading cryptographic module... ${loaded} MiB received`); + }; + progress(); + reader = response.body.getReader(); + for (;;) { + const { done, value } = await reader.read(); + if (done) break; + refreshTimeout(); + chunks.push(value); + received += value.byteLength; + progress(); + } + if (!received) throw new Error('The cryptographic module download was empty. Reload to try again.'); + const bytes = new Uint8Array(received); + let offset = 0; + for (const chunk of chunks) { bytes.set(chunk, offset); offset += chunk.byteLength; } + return bytes.buffer; + } catch (error) { + if (controller.signal.aborted) throw new Error('Cryptographic module download stalled for 45 seconds. Check your connection and reload to try again.'); + throw error; + } finally { + clearTimeout(timer); + reader?.releaseLock(); + } +} + async function start() { - wasm = fetch('/crypto.wasm', { cache: 'no-store', credentials: 'omit' }).then(response => { - if (!response.ok) throw new Error('Build the WASI cryptographic module first'); - return response.arrayBuffer(); - }); + wasm = downloadCrypto(); await wasm; + status('Cryptographic module downloaded. Connecting to chat...'); config = await api({ op: 'config' }); if (config.origin !== location.origin) throw new Error('Server origin mismatch'); show('owner-entry'); diff --git a/crates/chat-server/web/index.html b/crates/chat-server/web/index.html index 79026b0..70f3ebb 100644 --- a/crates/chat-server/web/index.html +++ b/crates/chat-server/web/index.html @@ -41,7 +41,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. <div class="ascii-panel introduction"> <div class="ascii-bar" aria-hidden="true"><span>+</span><span class="ascii-rule">--------------------------------------------------------------------------------</span><span>+</span></div> <div class="panel-body"> -<p class="build-status">EXPERIMENTAL / LOCAL TEST</p> +<p class="build-status">EXPERIMENTAL</p> <p>Keep your file and password. There is no account recovery.<br><a href="/LIMITATIONS.txt">Read the limitations</a> before using this experimental messenger.</p> </div> <div class="ascii-bar" aria-hidden="true"><span>+</span><span class="ascii-rule">--------------------------------------------------------------------------------</span><span>+</span></div> @@ -100,7 +100,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. <noscript>This chat requires free JavaScript and WebAssembly for local cryptography. The main website remains JavaScript-free.</noscript> <footer class="source-footer" aria-label="Licensing and source"> <a class="project-license" href="https://www.gnu.org/licenses/agpl-3.0.html">[ LICENSE ]</a> -<a class="dependency-licenses" href="/THIRD-PARTY-LICENSES.html">[ THIRD PARTY LICENSES ]</a> +<a class="dependency-licenses" href="{{SITE_ORIGIN}}/THIRD-PARTY-LICENSES.html">[ THIRD PARTY LICENSES ]</a> <a href="/SOURCE.tar.gz">[ SOURCE CODE ]</a> </footer> </main> diff --git a/crates/chat-server/web/javascript.html b/crates/chat-server/web/javascript.html index 205a103..644e5a1 100644 --- a/crates/chat-server/web/javascript.html +++ b/crates/chat-server/web/javascript.html @@ -24,5 +24,5 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. <tr><td><a href="/wasi.mjs">wasi.mjs</a></td><td><a href="https://www.gnu.org/licenses/agpl-3.0.html">GNU-AGPL-3.0</a></td><td><a href="/SOURCE.tar.gz">Complete corresponding source</a></td></tr> </tbody></table></div> <p>The WebAssembly module is compiled from the Rust workspace and unmodified OpenSSL 3.6.5, under their respective free software licenses. The source archive includes first-party sources, Cargo dependencies, the OpenSSL source archive, build scripts, and notices. General-purpose Rust and WASI SDK tools are documented with verified download locations in CHAT-OPENSSL-MIGRATION.txt.</p> -<p><a href="/THIRD-PARTY-LICENSES.html">Third-party licenses</a> / <a href="/SOURCE.tar.gz">Source archive</a> / <a href="/">Return</a></p> +<p><a href="{{SITE_ORIGIN}}/THIRD-PARTY-LICENSES.html">Third-party licenses</a> / <a href="/SOURCE.tar.gz">Source archive</a> / <a href="/">Return</a></p> </main></body></html> |
