The bundles carried all thirteen translations at once and a page fetched them a
third time as raw source; each page now loads only its own language. Alongside
that: JavaScript is minified, the eight stylesheets are served as one file, the
QR scanner is fetched after the app is up instead of on every visit, Inter ships
once rather than five copies of the same file, and Font Awesome is subset to the
82 icons this app draws instead of all 2468.
1.85 MB across 43 requests becomes under 700 KB across 33. On mobile the page
starts drawing in 1.6 s instead of 6.3 s and is usable in 4.5 s instead of 11 s.
Pages also carry their text in the HTML now. Everything was drawn by JavaScript
into an empty div, so crawlers saw correct metadata around nothing, and twelve of
the thirteen language pages had never been shown to anyone. The documentation is
published under /docs/ with a new FAQ, and unknown addresses return a real 404.
Separately: the localized shells were served with the year-long immutable cache
header meant for static assets, which pinned anyone who opened /de/ or /ru/ to
that build. The header is fixed and the service worker refreshes what it cached.
Claude-Session: https://claude.ai/code/session_014KjzTXxrhzYoDDWChYQ4u2
The site now speaks German, French, Spanish, Ukrainian, Russian, Chinese,
Korean and Hindi alongside English — 623 strings per language, 5,607
translations, covering the landing page, the key exchange, the chat, group
calls and every error along the way.
Each locale is a real page at a real URL (/de/, /fr/, …), generated at build
time from locales/*.json. That is the whole point: the app is client-rendered,
so a language that only swaps strings at runtime has no address for a crawler
to index and no link anyone can share. Each page carries its own canonical, a
reciprocal hreflang cluster and translated schema.org.
The URL decides the language, always. A stored preference only applies where
the address does not say, and nothing ever redirects on Accept-Language —
that is how sites become invisible to search engines outside one country.
robots.txt and sitemap.xml did not exist before; both are generated now.
Bugs found on the way, each with a test that would have caught it:
- partner logos used page-relative paths and 404'd from any /xx/ page
- post-build stamped ?v= only into the root shell, leaving locales behind
- "Back online" appeared on every page load, not just after being offline
- update timestamps were hard-coded to US format for every reader
- t() threw on a partial window, taking whole components down with it
Adds the Double Ratchet (Signal's design) on top of the existing ECDH session
keys, so message protection no longer rests on one set of keys lasting the whole
conversation. Every message gets its own key, derived through a one-way function
and discarded after use, and each change of direction introduces a fresh ECDH
key pair that re-keys the session root.
The ratchet needed no handshake change: both peers already hold each other's
authenticated ECDH public key, and the safety code compared during verification
covers exactly those keys. Its root is derived from the existing shared secret
through its own branch of the key schedule.
Support is negotiated in the invitation and response and used only when both
sides have it; a peer on an earlier release falls back to per-session keys. The
security panel reports which of the two is actually in force.
Out-of-order delivery is supported within fixed bounds (512 skipped keys per
chain, 1024 retained, five-minute expiry), and inbound frames are authenticated
before any ratchet state is committed, so a malformed frame cannot desynchronise
a live session.
Also in this release:
- Verification is enforced as a gate, not a label: control frames (reconnection
signalling, call setup, message deletion, delivery receipts) are acted on only
after both peers have compared the safety code, and verified state is set in a
single guarded place.
- Chat content reaches the interface through one authenticated path; an older,
weaker inbound path was retired.
- The security panel measures what it displays — several checks previously
returned a fixed result and now exercise the subsystem they describe.
- Invitation data is no longer kept in local storage, and entries left by earlier
versions are cleared on first launch.
- View-once and disappearing messages no longer place their text in system
notifications.
- Shared-secret buffers are overwritten once derivation completes; scanned QR
codes are decompressed with a size limit; voice notes are validated against
audio type and size budgets before skipping the consent prompt; the master
password is collected by the app rather than a browser dialog.
- Connection setup no longer fails on networks where STUN/TURN are unreachable:
it proceeds as soon as usable candidates exist and only waits while there are
none.
Test suite grows from 27 to 41 files, covering forward secrecy, post-compromise
re-keying, out-of-order delivery across ratchet steps, the skipped-key bounds,
tamper resistance, negotiation fallback, and byte-level key-derivation
compatibility with 5.6.0.
Add 1:1 voice and video calling over the existing SAS-verified peer
connection. Audio and video tracks ride the same RTCPeerConnection as the
chat, bundled onto one DTLS-SRTP transport, so media inherits the session's
end-to-end encryption. SDP offer/answer is renegotiated in-band over the
verified data channel — no signalling server, so the media's DTLS
fingerprints are authenticated end-to-end. Calls are gated on a connected,
SAS-verified session.
Codecs & adaptation:
- Opus tuned for lossy links (in-band FEC, DTX, RED redundancy); audio is
bandwidth-prioritised and never throttled.
- VP9/AV1 single-encoding SVC with H.264/VP8 fallback; video degrades by
spatial/temporal layer.
- Runtime NetworkAdaptationController trims video bitrate on loss/RTT and
recovers as the link clears — no renegotiation. Live connection-quality
indicator (Excellent/Good/Fair/Weak) in the call UI.
In-call controls: mute, camera on/off (voice→video upgrade in-band),
camera flip, minimize-to-widget, hang up, and accept/decline for incoming
calls. Production logging disabled (DEBUG_MODE=false); temporary call
diagnostic logger removed. Codec rationale in docs/webrtc-config.md.
Ground-up visual redesign across the entire surface (landing, connection
setup, chat header, security verification report, file transfer, PWA
install/update/offline dialogs).
Offline reworked: store-and-forward queue (send while offline → queued,
delivered on reconnect), WhatsApp-style per-message delivery status
(sending/sent/delivered/not-sent) via delivery receipts, offline buffering
for messages to an offline peer, and offline state no longer leaking into
the connection indicator. Resilient chunked file transfer with retransmission
and auto-save. README + screenshots added.
- add iceServers.js: allowlist-based validation/normalization of user-supplied
STUN/TURN URLs (rejects javascript:/data:/http/ws, control chars, enforces limits)
- add iceSettingsStore.js: opt-in persistence encrypted at rest with a
non-extractable AES-GCM device key in IndexedDB; load/save/clear
- add IceServerSettings.jsx modal: public vs custom servers, JSON/line input,
live validation, relay-only toggle, 'Test servers' connectivity check,
save-on-device prompt, forget-saved action
- wire chosen servers/privacy mode into EnhancedSecureWebRTCManager construction
(priority: custom > operator override > built-in defaults)
- entry point on the connection-creation screen next to the relay-only toggle
- add ice-servers-validation.test.mjs to the suite
- Added SecureNotificationManager with cross-browser support (Chrome, Firefox, Safari, Edge)
- Integrated WebRTC message notifications with tab visibility detection
- Implemented XSS protection, URL validation, and rate limiting
- Notifications shown only when chat tab is inactive
- Enforced HTTPS and user gesture requirements
- Deleted BluetoothKeyTransfer.js and related classes
- Removed BluetoothKeyTransfer.jsx UI component
- Cleaned up Bluetooth imports from app-boot.js and bootstrap-modules.js
- Removed Bluetooth buttons and handlers from main app
- Eliminated all Bluetooth functionality due to Web Bluetooth API limitations
- Browsers cannot create GATT servers or advertise devices
- Reduced bundle size by ~78KB
- Application now focuses on supported browser technologies (QR codes, manual key exchange, WebRTC)
- Deleted BluetoothKeyTransfer.js and related classes
- Removed BluetoothKeyTransfer.jsx UI component
- Cleaned up Bluetooth imports from app-boot.js and bootstrap-modules.js
- Removed Bluetooth buttons and handlers from main app
- Eliminated all Bluetooth functionality due to Web Bluetooth API limitations
- Browsers cannot create GATT servers or advertise devices
- Reduced bundle size by ~78KB
- Application now focuses on supported browser technologies (QR codes, manual key exchange, WebRTC)
- Cache only essential PWA assets (manifest, icons, core scripts)
- Use Network First for all other requests
- Remove aggressive caching of UI components and styles
- Preserve PWA installation while minimizing cache footprint
- implemented glowing border effect on cards when cursor is near
- multiple cards can glow simultaneously within proximity
- smooth fade-out without flicker on mouse leave
- improved hover animation for better user experience
- Removed temporary console logs used for debugging
- Disabled DEBUG_MODE flag
- Updated configuration to run in production mode
- Cleaned up leftover debug utilities to reduce noise in console
- Removed session creation and Lightning payment logic
- Refactored security system:
* no more restrictions
* all systems enabled on session creation
- Improved QR code exchange for mobile devices
Replace CDN React/ReactDOM/Babel with local libs; remove Babel and inline scripts
Build Tailwind locally, add safelist; switch to assets/tailwind.css
Self-host Font Awesome and Inter (CSS + woff2); remove external font CDNs
Implement strict CSP (no unsafe-inline/eval; scripts/styles/fonts from self)
Extract inline handlers; move PWA scripts to external files
Add local QR code generation (qrcode lib) and remove api.qrserver.com
Improve SessionTypeSelector visual selection (highlighted background and ring)
Keep PWA working with service worker and offline assets
Refs: CSP hardening, offline-first, no external dependencies