Files
LumaWeb/docs/decisions/0002-xmpp-library.md
wt 8f918bc040 S00-003: Approve bounded XMPP selection after independent WSS and SCRAM checks
Changes: Accept ADR 0002 for pinned Stanza with mandatory bounded transport, verified SASL and SHA512 composition; record independent review findings and handoff with external limits retained.
Validation: Fresh-cache pinned npm ci and browser build succeeded; all 112 tests passed. Verified 51 locked entries, 26 installed notices and 340 unchanged vendor files; six offer permutations and six adversarial XML checks passed; make check passed 72 tooling tests. No actual browser, independent full XMPP server/client, OMEMO or release readiness acceptance.

Task: S00-003
Agent: auto-qa-d49749753ac6
Role: qa
Action: review
Status: done

Task title: Проверить XMPP WSS/auth библиотеку
2026-10-15 18:26:01 +07:00

9.5 KiB
Raw Permalink Blame History

ADR 0002: XMPP library and required browser integration seams

  • Status: accepted for bounded S00-003 library selection; independent QA: state/evidence/S00-003-review.md.
  • Date: 2026-10-15. Owner: auto-protocol-f474114f0168 (protocol).
  • Reviewer: auto-qa-d49749753ac6 (qa), 2026-10-15.
  • Requirements: ACC-004, NET-003, NET-004.
  • Prerequisites: accepted scope/stack ADRs and bounded SASL, parser, SHA-512 experiments (S00-017/018/019); independently reviewed Linux environment S00-020.

Question and decision

Select Stanza 12.22.1 (MIT), with the three reviewed public integration seams mandatory before connect: bounded transport, fail-closed SASL feature, and the SHA-512 mechanism composition. Stock Stanza alone is unsuitable for this profile. Its stock SASL handler does not verify server-final, its browser hyphenated SHA-512 HMAC is wrong, and its persistent parser has no finite resource budgets. The accompanying spike proves the composed candidate; it creates no production adapter, shared contract, crypto implementation or provider deployment.

Option Evidence and tradeoff
Stanza 12.22.1 plus reviewed extensions Selected: actual browser bundle, public Client/Factory/Registry/Transport APIs, verified fixed SCRAM transcripts, loopback WSS and extension fixtures. JSON models and built-in MAM/MUC/Jingle/upload mappings fit the planned adapter boundary. Exact-version alias and replacement plugins require regression checks on upgrades.
Stock Stanza Rejected: the accepted remediation experiments reproduce security/framing defects. Installing the package alone does not meet this decision.
xmpp.js Viable alternative with browser WebSocket and modular packages; its primary README documents MIT and client/component modules. Not installed or executed here; no superiority/security finding or exact pin is claimed. It would require a separate equivalent integration experiment, rather than assuming its SASL/parser meet the profile.

One runnable selection experiment

experiments/0002-xmpp-library/selection-spike combines unchanged reviewed bounded-ingress and SHA-512 alias source with the ordering guard extended to non-PLUS SHA-512/256/1. Existing library crypto implements all hashes, HMAC, SCRAM and SASLprep. No vendor file, private field or primitive is changed.

The real Client.connect, XML registry, feature dispatcher, queue and browser SCRAM backend run against a synthetic loopback HTTPS/WebSocket peer. Its self-signed certificate is generated temporarily by OpenSSL, trusted explicitly by the test socket only, and hostname/certificate checks remain enabled. No system trust store is changed. An uninjected native WebSocket rejects the same untrusted certificate; a plaintext endpoint is rejected before a socket exists. The trusted peer observes TLS plus the xmpp subprotocol, framing open, exact proof and a second open only after a valid server-final. Forged/premature finals never authenticate or restart. This is a real WSS handshake with a fixture peer, not interoperability with a deployed independent XMPP server.

Mechanism policy filters PLUS because browser TLS binding is unavailable, selects SHA-512 then SHA-256 then SHA-1 independent of offer order, and disables all other fallbacks. NET-003 permits a configured protected fallback; this selection enables none. PLUS-only/PLAIN-only/empty offers fail. Diagnostics contain selected mechanism, channelBinding: unavailable, and disabled fallback; no credential, nonce, proof or peer payload. Synthetic tlsUnique is rejected. GS2 n,, and c=biws are verified. A future platform with real binding must add a separately reviewed implementation before offering PLUS.

Parser experiment ceilings are preserved: 4096 UTF-8 bytes, depth 8, 32 elements, 16 attributes, 1024 aggregate attribute units, 128 name units and 256 attribute value units. Standalone complete text XML is preflighted by saxes before JXT import. Oversized and split XML fail on the actual WSS path. These numbers are local experiment limits, not a production message/media-size contract.

Registry fixtures import/export MAM forwarded IDs, MUC join, Jingle terminate, HTTP upload URLs and legacy opaque OMEMO bytes. An explicitly invented opaque namespace demonstrates Client.use/Registry.define extension and namespace isolation. It is not an OMEMO2 implementation or encrypted messaging claim. Imported messages expose both selected body and alternateLanguageBodies; exporting both concatenates text in this version. A regression records it; the MAM fixture exports only the language collection. Future adapters must construct deliberate outbound shapes rather than echo imported objects.

Reproduction, versions and licenses

Follow the experiment README. Exact Node 24.21.0/npm 11.19.0 and Vite 8.3.4 remain from accepted ADR 0001. Stanza 12.22.1, saxes 6.0.0, events 3.3.0 and test peer ws 8.22.0 have exact direct pins; lock v3 includes all optional hosts. These are already reviewed package families, not a new stack. MIT/ISC runtime notices, Stanza bundled ancestry, and build MIT/ISC/BSD/Apache/MPL notices are preserved in inventory/notices; saxes' omitted package license is preserved from the reviewed versioned upstream copy. MPL build code is unmodified. Dependency monitoring, provenance and advisory clearance remain continuing release work.

Browser syntax floors are the accepted Chrome/Edge 111, Firefox 114, Safari 16.4 build targets, not a product support certification. Bundle graph excludes Node platform/crypto and unresolved builtins; events is explicitly bundled. Native WebSocket, secure RNG, URL and TextEncoder are required. Server/test tooling Node crypto is only an independent oracle; it does not replace browser crypto.

Primary sources inspected on 2026-10-15

  • RFC 7395, sections 3.1–3.4, 3.7 and 3.9: subprotocol, complete text XML, framing, restart and TLS.
  • RFC 5802 and RFC 7677: fixed SHA-1/256 exchange vectors and server verification. SHA-512 independent Scramp fixtures and RFC 4231 primitive vectors retain their accepted S00-019 provenance.
  • Stanza upstream and xmpp.js upstream: candidate APIs, browser positioning and licenses. Exact installed Stanza 12.22.1 Client.d.ts/.js, lib/sasl, plugins/features, jxt/Registry and protocol modules are authoritative for shipped extension behavior; all 340 files match the independently installed S00-020 vendor graph. Upstream branches do not establish version guarantees.
  • XEP-0313, XEP-0045, XEP-0166, XEP-0363: fixture namespaces and envelope/extension shapes. Shipped protocol comments identify older revisions; a passing simple fixture does not establish complete current-XEP coverage.

Consequences, limits and review

The spike is sufficient input for bounded selection review. Production still requires S01 contracts and its own implementations/tests. The minimal transport omits complete stream sequencing, error/close negotiation, redirect and keepalive policies. Queue/rate/network-allocation bounds, worker/CPU performance, timeout, full SASL extensions/final-challenge compatibility and constant-time verifier assurance are not established. Library verifier uses string equality. Strict success-only final layout and conservative send-race rejection reduce availability.

No Chrome/Firefox/Safari runtime execution, independent XMPP server/client, real account, OMEMO encryption, production feature semantics, full browser matrix or release readiness was verified. Browser-built code runs in Node with host web APIs; socket injection adds fixture CA trust, not a browser channel-binding API. Old accepted experiment source is unchanged; shared interfaces/specs/stack and network/TLS/CORS policies remain unchanged. Any API incompatibility on upgrade requires a new bounded decision, not a private patch or silent downgrade.

QA should reproduce clean install/build/tests and dependency checks, inspect the stock defect controls, explicit extension projection and scope, then record an independent decision. Evidence: state/evidence/S00-003-auto-protocol-f474114f0168.md. Coordinator owns transition commits; independent acceptance is recorded below.

Independent acceptance

QA reviewer auto-qa-d49749753ac6 accepts this exact-version library selection with all three integration seams mandatory. Fresh-cache locked installation, browser bundle and all 112 tests passed on reviewed Linux Node 24.21.0/npm 11.19.0; 51 locked entries, 26 installed package notices and 340 unchanged vendor files verified. Lock, guard and bundle hashes match executor evidence. Additional six offer permutations selected SHA-512; six adversarial XML documents rejected before registry access and a valid body imported. make check passed 72 tooling tests. Public shipped APIs, composed guard diff, fixture trust boundary and extension projection were inspected. Report: state/evidence/S00-003-review.md. Acceptance covers the bounded combined spike and selection only. All native browser, independent server/client, OMEMO, aggregate resource, lifecycle, timeout/timing and release limitations above remain. Stock Stanza without the required seams is not accepted. Coordinator must commit the review transition before any subsequent fresh task session.