S00-018: Bound standalone XML ingress before Stanza parsing and import
Changes: Add an isolated public transport integration with finite byte, depth, element and attribute budgets; validate complete text XML with pinned saxes before real JXT parsing/import. Add adversarial and boundary fixtures, terminal cleanup tests, dependency notices and a proposed parser ADR. Validation: Fresh-cache npm ci and npm test passed all 55 tests with Node 24.21.0/npm 11.19.0. Reproduced three stock parser failures, checked ten exact dependency licenses/integrities and 340 unchanged Stanza files; make check passed 72 tooling tests. Scope and whitespace inspected. Browser runtime, live WSS and interoperability were not tested. Task: S00-018 Agent: auto-protocol-89fe6563092c Role: protocol Action: claim Status: review Task title: Validate bounded standalone XML ingress for the XMPP candidate
This commit is contained in:
1 parent
f556fc0deb
commit
e2b4dbdb76
19 files changed
+1648
-8
No files matched your search
@@ -0,0 +1,100 @@
|
||||
# ADR 0002 parser remediation: bounded standalone XML ingress
|
||||
|
||||
- Status: proposed; independent security review pending.
|
||||
- Task: S00-018 (remediation of S00-003).
|
||||
- Date: 2026-10-15.
|
||||
- Owner: auto-protocol-89fe6563092c (protocol).
|
||||
- Reviewer: not yet assigned.
|
||||
|
||||
Input: reviewed scope/stack/SASL ADRs, S00-003 parser blocker and bounded probe,
|
||||
shipped Stanza parser/transport declarations and RFC 7395. Output: one isolated
|
||||
runnable ingress experiment in experiments/0002-xmpp-library/parser-validation.
|
||||
It does not select Stanza for the product, define production limits/shared
|
||||
contracts, change authentication, or replace remaining S00-003 evidence.
|
||||
|
||||
The stock 12.22.1 transport keeps a StreamParser across WebSocket messages and
|
||||
converts payloads to text. The finite diagnostic reproduced a 1 MiB body, depth
|
||||
256 and 18 separate writes forming one 64 KiB body without errors. StreamParser
|
||||
has no supported resource-budget options. The standalone-frame obligation is
|
||||
[RFC 7395 §3.2/3.3.3](https://www.rfc-editor.org/rfc/rfc7395.html#section-3.3.3).
|
||||
Inference from the shipped transport: stock parser reassembly violates that
|
||||
obligation when each probe write represents a separate WebSocket message.
|
||||
The RFC does not prescribe our numerical limits.
|
||||
|
||||
Propose a new public Client.transports constructor registration, selected alone
|
||||
through config. The public Transport interface lists connect/disconnect/restart/
|
||||
send; Client.connect instantiates the registered constructor with Client,
|
||||
StreamManagement and Registry. This is a supported shipped integration surface,
|
||||
not a private subclass override or ignored vendor patch. Exact shipped API:
|
||||
node_modules/stanza/Client.d.ts, index.d.ts, Client.js, jxt/index.d.ts,
|
||||
jxt/Parser.js and jxt/Registry.js. Upstream [Client source](https://github.com/legastero/stanza/blob/master/src/Client.ts)
|
||||
is supporting context; installed 12.22.1 declarations/behavior are authoritative
|
||||
for this experiment. Future stability is not promised.
|
||||
|
||||
Before any JXT tree/import, require text and finite bytes, then use a new
|
||||
namespace-aware saxes XML 1.0 document parser and close it for completeness.
|
||||
Throw on malformed input or exceeded event counters, reject restricted constructs,
|
||||
and only then run the actual JXT.parse and Registry.import. Local ceilings:
|
||||
|
||||
| Resource | Maximum, inclusive | Enforcement |
|
||||
| --- | --- | --- |
|
||||
| Encoded message | 4096 UTF-8 bytes | Unit precheck, bounded TextEncoder, before SAX |
|
||||
| Depth including root | 8 | SAX opentagstart |
|
||||
| Elements including root | 32 | SAX opentagstart |
|
||||
| Attributes including xmlns | 16 total/document | SAX attribute |
|
||||
| Attribute name+decoded value units | 1024 total/document | SAX attribute |
|
||||
| Element/attribute name units | 128 each | SAX event |
|
||||
| Decoded attribute value units | 256 each | SAX attribute |
|
||||
|
||||
SAX itself stores tokens/namespaces before callbacks; their worst-case source
|
||||
is capped by bytes first. No handwritten XML security parser or regex syntax
|
||||
approximation is introduced. XML declarations, comments, PI and DTDs are
|
||||
conservatively rejected; CDATA/built-in/numeric entities work. No entity fetch
|
||||
or expansion extension is enabled. The entire document is validated before
|
||||
any earlier root can emit. Incomplete documents/multiple roots/binary messages
|
||||
are terminal and cannot be completed by subsequent messages. Close detaches
|
||||
callbacks, clears attempt stream/config state and rejects stale callbacks.
|
||||
Fresh connect creates a fresh transport. No payload is logged or raw-evented.
|
||||
|
||||
Alternatives rejected: post-import counters (too late), stock persistent parser
|
||||
(no budgets/framing), regex or custom security parser (incorrect/unvetted),
|
||||
DOMParser (tree allocated before structural checks), private source patches
|
||||
(unsupported integration). A strict event parser plus byte ceiling provides a
|
||||
bounded preflight without authoring XML syntax. Double parsing retains actual
|
||||
candidate behavior, with bounded cost; complete normalization equivalence is
|
||||
not established and is not claimed.
|
||||
|
||||
New exact dependencies: saxes 6.0.0 (ISC), xmlchars 2.2.0 (MIT); Stanza remains
|
||||
12.22.1 (MIT). Ten exact installed packages are locked with HTTPS registry URLs,
|
||||
SHA512 integrity, full license inventory and notices. Saxes published tarball
|
||||
omits LICENSE; preserved upstream [v6.0.0 license](https://raw.githubusercontent.com/lddubeau/saxes/v6.0.0/LICENSE)
|
||||
includes ISC lineage and an historical MIT notice. Public API/browser constraints
|
||||
were checked against [versioned saxes README](https://raw.githubusercontent.com/lddubeau/saxes/v6.0.0/README.md)
|
||||
and installed saxes.d.ts/source, not assumptions about a parser's strict mode.
|
||||
Sources inspected 2026-10-15. Saxes has an older release; maintenance/advisory
|
||||
clearance is not inferred from version pinning. README conformance claims are
|
||||
upstream claims; our evidence is the bounded tests.
|
||||
|
||||
Verification: pinned Node 24.21.0/npm 11.19.0, fresh-cache npm ci, 55 integrated
|
||||
tests passing; aggregate boundary document and Unicode boundary actually
|
||||
import; all original failure categories and adversarial cases reject without
|
||||
stanza emission/late revival. Registry tracing calls the real import. All 340
|
||||
installed Stanza files byte-match the original candidate; no vendor edits.
|
||||
make check passes 72 tooling tests (foundation only). Commands and setup details
|
||||
are in the experiment README and state/evidence/S00-018-auto-protocol-89fe6563092c.md.
|
||||
|
||||
Browser use requires a CommonJS-capable bundler, native WebSocket/URL/TextEncoder
|
||||
and private fields. Default uses browser WebSocket, fixture injection captures
|
||||
socket effects only; actual Client.connect and its queue/registry/parser execute.
|
||||
No browser build/runtime, actual WSS/TLS handshake, independent server/client
|
||||
interoperability or exhaustion benchmark was run. Byte checks begin after
|
||||
browser message allocation, and do not bound aggregate traffic/Client queues or
|
||||
downstream work. This minimal transport does not implement all error reporting,
|
||||
close negotiation, redirect, keepalive, language inheritance or XMPP sequencing.
|
||||
No TLS/CORS bypass, invented channel binding, crypto primitive, production policy
|
||||
or shared contract is added. ACC-004/NET-003/NET-004 remain obligations of the
|
||||
original selection/product work; existing accepted SASL experiment is unchanged.
|
||||
|
||||
Independent security reviewer must inspect enforcement order/API integration,
|
||||
repeat clean install/tests/license/vendor checks and record acceptance before
|
||||
this ADR or S00-018 is accepted. Coordinator alone commits/launches further work.
|
||||
@@ -0,0 +1,3 @@
|
||||
engine-strict=true
|
||||
strict-ssl=true
|
||||
registry=https://registry.npmjs.org/
|
||||
@@ -0,0 +1,16 @@
|
||||
# Exact dependency license inventory
|
||||
|
||||
Inspected 2026-10-15. Node 24.21.0 / npm 11.19.0. Saxes tarball omits its license text: preserved upstream v6.0.0 LICENSE in licenses/saxes-6.0.0-LICENSE, retrieved via verified HTTPS. Other texts are shipped installed files. No advisory/provenance clearance is claimed.
|
||||
|
||||
| Package | Version | SPDX | License/notice source |
|
||||
| --- | --- | --- | --- |
|
||||
| @types/node | 22.20.5 | MIT | LICENSE |
|
||||
| @types/punycode | 2.1.4 | MIT | LICENSE |
|
||||
| @types/ws | 8.18.2 | MIT | LICENSE |
|
||||
| punycode | 2.3.1 | MIT | LICENSE-MIT.txt |
|
||||
| saxes | 6.0.0 | ISC | saxes-6.0.0-LICENSE |
|
||||
| sdp | 3.2.2 | MIT | LICENSE |
|
||||
| stanza | 12.22.1 | MIT | LICENSE.md, NOTICE.md |
|
||||
| undici-types | 6.21.0 | MIT | LICENSE |
|
||||
| ws | 8.22.0 | MIT | LICENSE |
|
||||
| xmlchars | 2.2.0 | MIT | LICENSE |
|
||||
@@ -0,0 +1,96 @@
|
||||
# Bounded standalone XML ingress experiment (S00-018)
|
||||
|
||||
This fixture experiment uses real Stanza 12.22.1 Client dispatch, JXT.parse and
|
||||
registry.import, preceded by saxes 6.0.0 XML 1.0 namespace-aware validation.
|
||||
It adds a constructor to the public Client.transports registry and selects only
|
||||
that transport via configuration. It does not use the stock persistent parser,
|
||||
subclass private transport fields, intercept already imported events, or patch
|
||||
vendor files. It is not a production transport or a library selection.
|
||||
|
||||
From project root, reuse the reviewed isolated Node runtime (macOS ARM64):
|
||||
|
||||
```sh
|
||||
export PATH=/private/tmp/luma-stack-runtime/node-v24.21.0-darwin-arm64/bin:$PATH
|
||||
npm ci --prefix experiments/0002-xmpp-library/parser-validation --ignore-scripts --no-audit --no-fund --cache /private/tmp/luma-parser-review-cache --fetch-retries=0 --fetch-timeout=15000
|
||||
npm test --prefix experiments/0002-xmpp-library/parser-validation
|
||||
python3 experiments/0002-xmpp-library/parser-validation/check-dependencies.py
|
||||
node experiments/0002-xmpp-library/parser-probe/reproduce.mjs
|
||||
```
|
||||
|
||||
The last command reproduces stock defects; exit 0 is NOT safe parsing.
|
||||
The dependency checker also requires the original candidate already installed in
|
||||
experiments/0002-xmpp-library/node_modules for byte comparison. It checks all 340
|
||||
Stanza files and ten exact locked installed package licenses/integrities. The
|
||||
saxes tarball omits LICENSE: the upstream v6.0.0 license is preserved locally,
|
||||
with source https://raw.githubusercontent.com/lddubeau/saxes/v6.0.0/LICENSE.
|
||||
|
||||
## Enforcement order and local policy
|
||||
|
||||
1. Require primitive string. Reject Blob/ArrayBuffer/typed arrays before coercion.
|
||||
2. Reject more than 4096 UTF-16 units without encoding; then reject more than
|
||||
4096 UTF-8 bytes using TextEncoder. The temporary encoding buffer is bounded
|
||||
by the unit check (at most 12288 bytes for any input); it is not an unbounded
|
||||
copy. First character must be `<` as required by RFC 7395.
|
||||
3. New saxes parser per message, fragment=false, xmlns=true, XML 1.0 forced,
|
||||
no inherited namespace resolver. Throw on the first error; close() checks
|
||||
document completion. No tree is built during this phase.
|
||||
4. At opentagstart reject depth >8 (including root), elements >32, name >128
|
||||
UTF-16 units. At attribute reject total attributes >16 (including xmlns),
|
||||
name >128, decoded value >256, or aggregate decoded attribute name+value
|
||||
units >1024. Checks occur before JXT tree construction/import. Saxes has
|
||||
already stored one completed attribute at its callback; lexical tokens,
|
||||
namespace tables and DTD buffers before callbacks are bounded by 4096 input
|
||||
bytes. No claim of allocation-free SAX processing is made.
|
||||
5. Reject DTDs, comments, processing instructions and XML declarations. Only
|
||||
built-in/numeric entities are available; no DTD fetching/entity expansion is
|
||||
enabled. CDATA is accepted. Declaration rejection is local conservative
|
||||
policy; RFC 7395 discourages but does not forbid declarations.
|
||||
6. Only after complete validation call real JXT.parse and registry.import. An
|
||||
unknown top-level root or candidate parser/import error closes the attempt.
|
||||
Parsed output is delivered through Client stream:data only after import
|
||||
succeeds. No invalid document's earlier root is emitted.
|
||||
7. On rejection close the socket, detach all four callbacks, clear config and
|
||||
stream references before emitting a payload-free error code. Every old
|
||||
captured callback checks the terminal flag. Parsers/trees are synchronous
|
||||
function locals, never retained between messages. A fresh Client.connect
|
||||
creates another transport; restart on a failed transport cannot revive it.
|
||||
|
||||
The combined boundary fixture hits 4096 bytes, depth 8, 32 elements,
|
||||
16 attributes and 1024 attribute units simultaneously and imports a real body.
|
||||
Separate tests cover name/value equality, multibyte byte equality, one-over
|
||||
bounds, stock 1 MiB/depth-256/18-message cases, malformed tails, incomplete XML,
|
||||
binary, duplicate attributes/namespaces/entities/invalid characters, callback
|
||||
replay, fresh connect, stream open/close/restart and outgoing registry export.
|
||||
Tracing registry.import calls the real implementation; it never fakes success.
|
||||
FixtureSocket replaces only browser socket effects; tests use actual Client
|
||||
connect/transport selection and stanza queue events.
|
||||
|
||||
## Constraints
|
||||
|
||||
The default socket constructor is globalThis.WebSocket; browser use requires a
|
||||
CommonJS-capable bundler for Stanza/saxes/xmlchars, native WebSocket, URL and
|
||||
TextEncoder plus support for private class fields. The injected fixture socket
|
||||
is explicitly separate and never chosen by the default path. Only explicit
|
||||
wss URLs and the xmpp subprotocol are allowed. TLS/CORS/binding are unchanged;
|
||||
no real WSS handshake is exercised here. Browser build/runtime and selected
|
||||
browser versions are NOT verified. Node tests run 24.21.0/npm 11.19.0.
|
||||
|
||||
Limits protect application parsing after the browser delivers a complete message.
|
||||
They cannot prevent the browser/network stack from allocating a huge inbound
|
||||
message, nor bound total traffic, Client queue growth, CPU rate, reconnect
|
||||
policy or downstream extension work. Those need separate product/provider
|
||||
policies. The experiment closes locally on violations rather than implementing
|
||||
full XMPP stream-error reporting/close negotiation/redirect/keepalive behavior.
|
||||
It does not enforce complete XMPP stream sequencing or preserve inherited stream
|
||||
language. JXT interpretation/normalization is retained; SAX and JXT equivalence
|
||||
for all accepted XML forms is not established. No auth/crypto changes, complete
|
||||
NET-003 policy, OMEMO, independent server/client interoperability, exhaustion
|
||||
benchmark, advisory/provenance audit, or release acceptance is claimed.
|
||||
|
||||
All ten package license texts/notices are in THIRD_PARTY_NOTICES.md and exact
|
||||
versions in LICENSE_INVENTORY.md/package-lock.json. Saxes is a mature existing
|
||||
strict parser with documented XML/namespace conformance and public event APIs;
|
||||
6.0.0 is an older release, and no ongoing-maintenance SLA is assumed. Its
|
||||
absence of built-in token limits is why the mandatory byte precheck comes first.
|
||||
See proposed docs/decisions/0002-xmpp-parser-validation.md. Independent security
|
||||
review is required; S00-003 remains a separate assignment after reviewed done.
|
||||
@@ -0,0 +1,637 @@
|
||||
# Third-party notices
|
||||
|
||||
Verbatim license/notice texts for this isolated experiment.
|
||||
|
||||
## @types/node 22.20.5 — LICENSE
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
|
||||
## @types/punycode 2.1.4 — LICENSE
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
|
||||
## @types/ws 8.18.2 — LICENSE
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
|
||||
## punycode 2.3.1 — LICENSE-MIT.txt
|
||||
|
||||
Copyright Mathias Bynens <https://mathiasbynens.be/>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
## saxes 6.0.0 — saxes-6.0.0-LICENSE
|
||||
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
====
|
||||
|
||||
The following license is the one that governed sax, from which saxes
|
||||
was forked. Isaac Schlueter is not *directly* involved with saxes so
|
||||
don't go bugging him for saxes issues.
|
||||
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
====
|
||||
|
||||
`String.fromCodePoint` by Mathias Bynens is no longer used, but it can
|
||||
still be found in old commits. It was once used according to terms of
|
||||
MIT License, as follows:
|
||||
|
||||
Copyright Mathias Bynens <https://mathiasbynens.be/>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
## sdp 3.2.2 — LICENSE
|
||||
|
||||
Copyright (c) 2017 Philipp Hancke
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
## stanza 12.22.1 — LICENSE.md
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright © 2013-2019 Lance Stout
|
||||
|
||||
Copyright © 2013-2019 &yet <https://andyet.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
## stanza 12.22.1 — NOTICE.md
|
||||
|
||||
# StanzaJS
|
||||
|
||||
Copyright © 2013-2019 Lance Stout
|
||||
|
||||
Copyright © 2013-2019 &yet <https://andyet.com>
|
||||
|
||||
Portions of this code were adapted from existing projects:
|
||||
|
||||
## SASL
|
||||
|
||||
- saslmechanisms
|
||||
- sasl-anonymous
|
||||
- sasl-digest-md5
|
||||
- sasl-external
|
||||
- sasl-plain
|
||||
- sasl-x-oauth2
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright © 2012-2013 Jared Hanson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
## ltx
|
||||
|
||||
Copyright © 2010 Stephan Maka
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
## xhtml-im.js
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright © 2013 Waqas Hussain
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
## wildemitter
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright © 2012 Henrik Joreteg
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
## hash-base
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Kirill Fomichev
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
## cipher-base
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 crypto-browserify contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
## sha.js
|
||||
|
||||
Copyright (c) 2013-2018 sha.js contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
Copyright (c) 1998 - 2009, Paul Johnston & Contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
Neither the name of the author nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific prior
|
||||
written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
## md5.js
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Kirill Fomichev
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
## create-hash
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 crypto-browserify contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
## create-hmac
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 crypto-browserify contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
## randombytes
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 crypto-browserify
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
## uuid
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2010-2016 Robert Kieffer and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
## strict-event-emitter-types
|
||||
|
||||
ISC License (ISC)
|
||||
|
||||
Copyright 2018 Brian Terlson
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose
|
||||
with or without fee is hereby granted, provided that the above copyright notice
|
||||
and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
|
||||
## capsdb
|
||||
|
||||
capsdb - A collection of XMPP caps with hashes
|
||||
|
||||
Written in 2015 by Thijs Alkemade me@thijsalkema.de
|
||||
|
||||
To the extent possible under law, the author(s) have dedicated all copyright and
|
||||
related and neighboring rights to this software to the public domain worldwide.
|
||||
This software is distributed without any warranty.
|
||||
|
||||
You should have received a copy of the CC0 Public Domain Dedication along with
|
||||
this software. If not, see http://creativecommons.org/publicdomain/zero/1.0/.
|
||||
|
||||
## undici-types 6.21.0 — LICENSE
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) Matteo Collina and Undici contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
## ws 8.22.0 — LICENSE
|
||||
|
||||
Copyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
Copyright (c) 2013 Arnout Kazemier and contributors
|
||||
Copyright (c) 2016 Luigi Pinca and contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
## xmlchars 2.2.0 — LICENSE
|
||||
|
||||
Copyright Louis-Dominique Dubeau and contributors to xmlchars
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,146 @@
|
||||
import {SaxesParser} from 'saxes';
|
||||
import jxt from 'stanza/jxt/index.js';
|
||||
|
||||
// Experiment policy only. The byte ceiling bounds SAX token/namespace storage
|
||||
// even before callbacks can inspect a completed name or attribute value.
|
||||
export const LIMITS = Object.freeze({bytes: 4096, depth: 8, elements: 32,
|
||||
attributes: 16, attributeChars: 1024, nameChars: 128, valueChars: 256});
|
||||
class IngressError extends Error {
|
||||
constructor(code) { super(code); this.code = code; }
|
||||
}
|
||||
const fail = code => { throw new IngressError(code); };
|
||||
|
||||
export function validateMessage(data) {
|
||||
if (typeof data !== 'string') fail('text-required');
|
||||
// Avoid encoding an attacker-sized string. UTF-8 bytes >= UTF-16 units for
|
||||
// valid XML; isolated surrogates are subsequently rejected by saxes.
|
||||
if (data.length > LIMITS.bytes) fail('bytes');
|
||||
if (new TextEncoder().encode(data).length > LIMITS.bytes) fail('bytes');
|
||||
if (!data.startsWith('<')) fail('framing');
|
||||
let depth = 0, elements = 0, attributes = 0, attributeChars = 0, ended = false;
|
||||
const parser = new SaxesParser({xmlns: true, fragment: false,
|
||||
defaultXMLVersion: '1.0', forceXMLVersion: true});
|
||||
parser.on('error', () => fail('invalid-xml'));
|
||||
for (const event of ['doctype', 'comment', 'processinginstruction', 'xmldecl']) {
|
||||
parser.on(event, () => fail('restricted-xml'));
|
||||
}
|
||||
parser.on('opentagstart', tag => {
|
||||
if (++depth > LIMITS.depth) fail('depth');
|
||||
if (++elements > LIMITS.elements) fail('elements');
|
||||
if (tag.name.length > LIMITS.nameChars) fail('name');
|
||||
});
|
||||
parser.on('attribute', attr => {
|
||||
if (++attributes > LIMITS.attributes) fail('attributes');
|
||||
if (attr.name.length > LIMITS.nameChars) fail('name');
|
||||
if (attr.value.length > LIMITS.valueChars) fail('attribute-value');
|
||||
attributeChars += attr.name.length + attr.value.length;
|
||||
if (attributeChars > LIMITS.attributeChars) fail('attribute-chars');
|
||||
});
|
||||
parser.on('closetag', () => { depth--; });
|
||||
parser.on('end', () => { ended = true; });
|
||||
// close() detects unfinished XML. Throwing from callbacks aborts immediately;
|
||||
// there is no recovery listener, DTD fetch, custom entity or tree construction.
|
||||
parser.write(data).close();
|
||||
if (!ended || depth !== 0 || elements === 0) fail('framing');
|
||||
}
|
||||
|
||||
export function importMessage(data, registry, config) {
|
||||
validateMessage(data);
|
||||
// Only bounded, complete documents reach the actual candidate parser/import.
|
||||
const xml = jxt.parse(data, {allowComments: false});
|
||||
if (!xml) fail('invalid-xml');
|
||||
const kind = registry.getImportKey(xml);
|
||||
const stanza = registry.import(xml, {lang: config.lang,
|
||||
acceptLanguages: config.acceptLanguages});
|
||||
if (!kind || !stanza) fail('unknown-root');
|
||||
return {kind, stanza};
|
||||
}
|
||||
|
||||
// Public Transport interface and Client.transports constructor registry.
|
||||
// Socket injection is solely for finite fixtures; default is browser WebSocket.
|
||||
export function installBoundedTransport(client, Socket = globalThis.WebSocket) {
|
||||
class BoundedTransport {
|
||||
#client; #registry; #sm; #socket; #config; #closed = true;
|
||||
hasStream = false;
|
||||
stream;
|
||||
constructor(agent, sm, registry) {
|
||||
this.#client = agent; this.#sm = sm; this.#registry = registry;
|
||||
}
|
||||
connect(config) {
|
||||
if (this.#socket || !this.#closed) throw new Error('Fresh transport required');
|
||||
if (new URL(config.url).protocol !== 'wss:') throw new Error('WSS required');
|
||||
this.#config = config;
|
||||
this.#closed = false;
|
||||
const socket = this.#socket = new Socket(config.url, 'xmpp');
|
||||
socket.onopen = () => {
|
||||
if (this.#closed) return;
|
||||
if (socket.protocol !== 'xmpp') return this.#reject('subprotocol');
|
||||
this.#sm.started = false;
|
||||
this.#client.emit('connected');
|
||||
this.restart();
|
||||
};
|
||||
socket.onmessage = event => {
|
||||
if (this.#closed) return;
|
||||
let parsed;
|
||||
try { parsed = importMessage(event.data, this.#registry, this.#config); }
|
||||
catch (error) { return this.#reject(error instanceof IngressError ? error.code : 'invalid-xml'); }
|
||||
// No raw payload event/log or async parser continuation escapes ingress.
|
||||
if (parsed.kind === 'stream') {
|
||||
if (parsed.stanza.action === 'open') {
|
||||
this.hasStream = true;
|
||||
this.stream = parsed.stanza;
|
||||
this.#client.emit('stream:start', parsed.stanza);
|
||||
} else {
|
||||
this.#client.emit('stream:end');
|
||||
this.disconnect(false);
|
||||
}
|
||||
} else {
|
||||
this.#client.emit('stream:data', parsed.stanza, parsed.kind);
|
||||
}
|
||||
};
|
||||
socket.onerror = () => this.#reject('socket-error');
|
||||
socket.onclose = () => this.disconnect(false);
|
||||
}
|
||||
#reject(code) {
|
||||
if (this.#closed) return;
|
||||
// Close/clear before notifying consumers; a reentrant callback cannot
|
||||
// revive the attempt. Never expose parser error text containing input.
|
||||
this.disconnect(false);
|
||||
this.#client.emit('ingress:rejected', code);
|
||||
}
|
||||
disconnect(clean = true) {
|
||||
if (this.#closed) return;
|
||||
this.#closed = true;
|
||||
const socket = this.#socket;
|
||||
this.#socket = undefined;
|
||||
if (socket) {
|
||||
socket.onopen = socket.onmessage = socket.onerror = socket.onclose = null;
|
||||
if (clean && this.hasStream && socket.readyState === 1) {
|
||||
socket.send(this.#registry.export('stream', {action: 'close'}).toString());
|
||||
}
|
||||
socket.close();
|
||||
}
|
||||
this.hasStream = false;
|
||||
this.stream = undefined;
|
||||
this.#config = undefined;
|
||||
if (this.#client.transport === this) this.#client.emit('--transport-disconnected');
|
||||
}
|
||||
restart() {
|
||||
if (this.#closed) return;
|
||||
this.hasStream = false;
|
||||
this.stream = undefined;
|
||||
this.#write(this.#registry.export('stream', {action: 'open',
|
||||
lang: this.#config.lang, to: this.#config.server, version: '1.0'}).toString());
|
||||
}
|
||||
#write(data) {
|
||||
if (this.#closed || this.#socket?.readyState !== 1) throw new Error('Socket closed');
|
||||
this.#socket.send(data);
|
||||
}
|
||||
async send(name, data) {
|
||||
const xml = this.#registry.export(name, data);
|
||||
if (!xml) throw new Error('Unknown outgoing stanza');
|
||||
this.#write(xml.toString());
|
||||
}
|
||||
}
|
||||
client.transports['bounded-websocket'] = BoundedTransport;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
"""Check exact installed graph, preserved notices, and unchanged candidate files."""
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
root = Path(__file__).resolve().parent
|
||||
lock = json.loads((root / 'package-lock.json').read_text())
|
||||
manifest = json.loads((root / 'package.json').read_text())
|
||||
assert manifest['engines'] == {'node': '24.21.0', 'npm': '11.19.0'}
|
||||
assert manifest['dependencies'] == {'saxes': '6.0.0', 'stanza': '12.22.1', 'xmlchars': '2.2.0'}
|
||||
notices = (root / 'THIRD_PARTY_NOTICES.md').read_text()
|
||||
inventory = (root / 'LICENSE_INVENTORY.md').read_text()
|
||||
count = 0
|
||||
for key, entry in lock['packages'].items():
|
||||
if not key:
|
||||
continue
|
||||
count += 1
|
||||
assert entry['resolved'].startswith('https://registry.npmjs.org/')
|
||||
assert entry['integrity'].startswith('sha512-')
|
||||
installed = root / key
|
||||
meta = json.loads((installed / 'package.json').read_text())
|
||||
assert meta['version'] == entry['version']
|
||||
assert meta['license'] == entry['license']
|
||||
assert f"| {meta['name']} | {meta['version']} | {meta['license']} |" in inventory
|
||||
files = [p for p in installed.iterdir() if p.is_file() and
|
||||
(p.name.lower().startswith('license') or p.name.lower().startswith('notice'))]
|
||||
if meta['name'] == 'saxes':
|
||||
files = [root / 'licenses/saxes-6.0.0-LICENSE']
|
||||
assert files
|
||||
for path in files:
|
||||
assert path.read_text().strip() in notices
|
||||
assert count == 10
|
||||
# Independent previously installed candidate; no ignored vendor patches.
|
||||
candidate = root / 'node_modules/stanza'
|
||||
original = root.parent / 'node_modules/stanza'
|
||||
files = [p for p in candidate.rglob('*') if p.is_file()]
|
||||
assert files
|
||||
for path in files:
|
||||
assert path.read_bytes() == (original / path.relative_to(candidate)).read_bytes(), path
|
||||
print(f'{count} exact dependency licenses/integrities; {len(files)} unchanged Stanza files')
|
||||
for name in ['package-lock.json', 'bounded-ingress.mjs', 'licenses/saxes-6.0.0-LICENSE']:
|
||||
print(f'{name} SHA256 {hashlib.sha256((root / name).read_bytes()).hexdigest()}')
|
||||
@@ -0,0 +1,64 @@
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
====
|
||||
|
||||
The following license is the one that governed sax, from which saxes
|
||||
was forked. Isaac Schlueter is not *directly* involved with saxes so
|
||||
don't go bugging him for saxes issues.
|
||||
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
====
|
||||
|
||||
`String.fromCodePoint` by Mathias Bynens is no longer used, but it can
|
||||
still be found in old commits. It was once used according to terms of
|
||||
MIT License, as follows:
|
||||
|
||||
Copyright Mathias Bynens <https://mathiasbynens.be/>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,119 @@
|
||||
{
|
||||
"name": "luma-bounded-xml-ingress-experiment",
|
||||
"version": "0.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "luma-bounded-xml-ingress-experiment",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"saxes": "6.0.0",
|
||||
"stanza": "12.22.1",
|
||||
"xmlchars": "2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "24.21.0",
|
||||
"npm": "11.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.20.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.5.tgz",
|
||||
"integrity": "sha512-U2+DNr+wSjpsTS/wZGYHq7GcwfuSmKiKvoPvK22zwTlRhU91yOniN4qRR5KhIjvif7ysw/dz/hKmfDH0Ris4aA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/punycode": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/punycode/-/punycode-2.1.4.tgz",
|
||||
"integrity": "sha512-trzh6NzBnq8yw5e35f8xe8VTYjqM3NE7bohBtvDVf/dtUer3zYTLK1Ka3DG3p7bdtoaOHZucma6FfVKlQ134pQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/ws": {
|
||||
"version": "8.18.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.2.tgz",
|
||||
"integrity": "sha512-67MQl+fpWKVTT1NYdnmo3U4sc/xPo/zQBncVnI74qmQa0z/b+1g6iYqNmGCPbxO+zz2aklb08a0oHfegiVd0/w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/punycode": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/saxes": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
|
||||
"integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"xmlchars": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=v12.22.7"
|
||||
}
|
||||
},
|
||||
"node_modules/sdp": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/sdp/-/sdp-3.2.2.tgz",
|
||||
"integrity": "sha512-xZocWwfyp4hkbN4hLWxMjmv2Q8aNa9MhmOZ7L9aCZPT+dZsgRr6wZRrSYE3HTdyk/2pZKPSgqI7ns7Een1xMSA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/stanza": {
|
||||
"version": "12.22.1",
|
||||
"resolved": "https://registry.npmjs.org/stanza/-/stanza-12.22.1.tgz",
|
||||
"integrity": "sha512-WwoSl3u5cCEAbed5ao+yt8ByH6AsBJcPDY0gax3JGQkBX/7wEZ2oxu9nMJ7O1tm8slDyH4FBYIpeluHrT+g/LA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "^22.0.0",
|
||||
"@types/punycode": "^2.1.0",
|
||||
"@types/ws": "^8.18.1",
|
||||
"punycode": "^2.1.1",
|
||||
"sdp": "^3.0.2",
|
||||
"ws": "^8.18.2"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.22.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.22.0.tgz",
|
||||
"integrity": "sha512-Ydggc987+RO0AnWtZ/7Wq9FtNvcrL1b/RO0ud9mWjUPgDrsAAwQSF51sm2hm1XofbU/4jkpGEsLFsZZxU+1DOg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/xmlchars": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
|
||||
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "luma-bounded-xml-ingress-experiment",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"engines": {"node": "24.21.0", "npm": "11.19.0"},
|
||||
"packageManager": "npm@11.19.0",
|
||||
"scripts": {"test": "node --test test/*.test.mjs"},
|
||||
"dependencies": {"saxes": "6.0.0", "stanza": "12.22.1", "xmlchars": "2.2.0"}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
export const opening = '<message xmlns="jabber:client"><body>';
|
||||
export const closing = '</body></message>';
|
||||
export const message = text => opening + text + closing;
|
||||
export const valid = message('finite fixture');
|
||||
export const deep = n => '<message xmlns="jabber:client">' + '<x>'.repeat(n - 1) +
|
||||
'</x>'.repeat(n - 1) + '</message>';
|
||||
export const elements = n => '<message xmlns="jabber:client">' + '<x/>'.repeat(n - 1) + '</message>';
|
||||
export const attributes = n => '<message xmlns="jabber:client"' +
|
||||
Array.from({length: n - 1}, (_, i) => ` a${i}="x"`).join('') + '/>';
|
||||
export function boundary() {
|
||||
// 16 attributes / 1024 name+value UTF-16 units including xmlns.
|
||||
let attrs = ' xmlns="jabber:client"';
|
||||
let chars = 'xmlns'.length + 'jabber:client'.length;
|
||||
for (let i = 0; i < 15; i++) {
|
||||
const name = `a${i}`;
|
||||
const value = 'v'.repeat(i === 14 ? 1024 - chars - name.length : 60);
|
||||
attrs += ` ${name}="${value}"`;
|
||||
chars += name.length + value.length;
|
||||
}
|
||||
// Root + body + chain of 7 + 23 siblings = 32 elements; depth 8.
|
||||
const before = `<message${attrs}><body>`;
|
||||
const after = '</body>' + '<x>'.repeat(7) + '</x>'.repeat(7) + '<x/>'.repeat(23) + '</message>';
|
||||
return {xml: before + 'z'.repeat(4096 - before.length - after.length) + after,
|
||||
body: 'z'.repeat(4096 - before.length - after.length)};
|
||||
}
|
||||
export const invalid = [
|
||||
['large stock body', message('b'.repeat(1048576)), 'bytes'],
|
||||
['deep stock XML', deep(257), 'depth'],
|
||||
['unfinished opening', opening, 'invalid-xml'],
|
||||
['unfinished attribute', '<message xmlns="jabber:client" a="unfinished', 'invalid-xml'],
|
||||
['unfinished tag', '<message xmlns="jabber:client"', 'invalid-xml'],
|
||||
['unfinished entity', message('&'), 'invalid-xml'],
|
||||
['empty', '', 'framing'],
|
||||
['leading whitespace', ' ' + valid, 'framing'],
|
||||
['text only', 'not xml', 'framing'],
|
||||
['two roots', valid + valid, 'invalid-xml'],
|
||||
['valid root then unfinished root', valid + '<message', 'invalid-xml'],
|
||||
['valid root then junk', valid + 'junk', 'invalid-xml'],
|
||||
['mismatched tags', '<message xmlns="jabber:client"><body></message>', 'invalid-xml'],
|
||||
['depth over', deep(9), 'depth'],
|
||||
['elements over', elements(33), 'elements'],
|
||||
['attributes over', attributes(17), 'attributes'],
|
||||
['attribute value over', `<message xmlns="jabber:client" a="${'x'.repeat(257)}"/>`, 'attribute-value'],
|
||||
['attribute chars over', '<message xmlns="jabber:client" ' +
|
||||
Array.from({length: 4}, (_, i) => `a${i}="${'x'.repeat(256)}"`).join(' ') + '/>', 'attribute-chars'],
|
||||
['oversized name', `<message xmlns="jabber:client"><${'x'.repeat(129)}/></message>`, 'name'],
|
||||
['oversized attribute name', `<message xmlns="jabber:client" ${'x'.repeat(129)}="x"/>`, 'name'],
|
||||
['oversized unfinished token', '<' + 'x'.repeat(4096), 'bytes'],
|
||||
['UTF-8 bytes over with bounded units', message('🦉'.repeat(1100)), 'bytes'],
|
||||
['binary buffer', new Uint8Array([60, 120, 47, 62]), 'text-required'],
|
||||
['binary ArrayBuffer', new ArrayBuffer(4), 'text-required'],
|
||||
['binary Blob', new Blob([valid]), 'text-required'],
|
||||
['boxed string', new String(valid), 'text-required'],
|
||||
['comment', '<!--x-->' + valid, 'restricted-xml'],
|
||||
['DTD internal entity', '<!DOCTYPE message [<!ENTITY x "payload">]>' + message('&x;'), 'restricted-xml'],
|
||||
['external DTD', '<!DOCTYPE message SYSTEM "https://example.invalid/dtd">' + valid, 'restricted-xml'],
|
||||
['processing instruction', '<?test x?>' + valid, 'restricted-xml'],
|
||||
['XML declaration', '<?xml version="1.0"?>' + valid, 'restricted-xml'],
|
||||
['duplicate attribute', '<message xmlns="jabber:client" id="a" id="b"/>', 'invalid-xml'],
|
||||
['duplicate expanded attribute', '<message xmlns="jabber:client" xmlns:a="urn:x" xmlns:b="urn:x" a:id="a" b:id="b"/>', 'invalid-xml'],
|
||||
['unbound namespace', '<p:message/>', 'invalid-xml'],
|
||||
['illegal namespace binding', '<message xmlns="jabber:client" xmlns:xml="urn:wrong"/>', 'invalid-xml'],
|
||||
['unknown entity', message('&unknown;'), 'invalid-xml'],
|
||||
['illegal control', message('\u0000'), 'invalid-xml'],
|
||||
['unpaired surrogate', message('\ud800'), 'invalid-xml'],
|
||||
['invalid char reference', message('�'), 'invalid-xml'],
|
||||
['unknown root', '<unknown xmlns="urn:fixture"/>', 'unknown-root']
|
||||
];
|
||||
@@ -0,0 +1,151 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import {test} from 'node:test';
|
||||
import clientModule from 'stanza/Client.js';
|
||||
import {installBoundedTransport, validateMessage, LIMITS} from '../bounded-ingress.mjs';
|
||||
import {opening, closing, message, valid, deep, elements, attributes, boundary, invalid} from './fixtures.mjs';
|
||||
const Client = clientModule.default;
|
||||
const tick = () => new Promise(resolve => setImmediate(resolve));
|
||||
|
||||
async function harness() {
|
||||
const sockets = [];
|
||||
class FixtureSocket {
|
||||
readyState = 1; protocol = 'xmpp'; sent = []; closes = 0;
|
||||
constructor(url, protocol) { this.url = url; this.requestedProtocol = protocol; sockets.push(this); }
|
||||
send(data) { this.sent.push(data); }
|
||||
close() { this.closes++; this.readyState = 3; }
|
||||
}
|
||||
const client = new Client({autoReconnect: false, server: 'example.invalid'});
|
||||
installBoundedTransport(client, FixtureSocket);
|
||||
client.updateConfig({transports: {'bounded-websocket': 'wss://example.invalid/xmpp'},
|
||||
transportPreferenceOrder: ['bounded-websocket']});
|
||||
const received = [], errors = [], raw = [], stanzas = [], starts = [];
|
||||
client.on('stream:data', (stanza, kind) => received.push({stanza, kind}));
|
||||
client.on('stanza', stanza => stanzas.push(stanza));
|
||||
client.on('stream:start', stanza => starts.push(stanza));
|
||||
client.on('ingress:rejected', code => errors.push(code));
|
||||
client.on('raw', (...args) => raw.push(args));
|
||||
// Tracing calls the real registry.import; proves rejection before import.
|
||||
let imports = 0;
|
||||
const original = client.stanzas.import.bind(client.stanzas);
|
||||
client.stanzas.import = (...args) => { imports++; return original(...args); };
|
||||
await client.connect();
|
||||
const socket = sockets.at(-1);
|
||||
socket.onopen();
|
||||
return {client, sockets, socket, received, errors, raw, stanzas, starts,
|
||||
imports: () => imports, finish: async () => {client.transport?.disconnect(false); await tick();}};
|
||||
}
|
||||
|
||||
for (const [name, xml, code] of invalid) {
|
||||
test(`terminal rejection: ${name}`, async () => {
|
||||
const h = await harness();
|
||||
const late = h.socket.onmessage;
|
||||
late({data: xml});
|
||||
assert.deepEqual(h.errors, [code]);
|
||||
assert.equal(h.socket.closes, 1);
|
||||
assert.equal(h.socket.onmessage, null);
|
||||
assert.equal(h.received.length, 0);
|
||||
assert.equal(h.starts.length, 0);
|
||||
if (code !== 'unknown-root') assert.equal(h.imports(), 0);
|
||||
// Old captured handlers and subsequent messages cannot revive an attempt.
|
||||
late({data: closing}); late({data: valid});
|
||||
await tick();
|
||||
assert.equal(h.stanzas.length, 0);
|
||||
assert.equal(h.received.length, 0);
|
||||
assert.deepEqual(h.errors, [code]);
|
||||
assert.equal(h.client.transport, undefined);
|
||||
assert.equal(h.raw.length, 0);
|
||||
await h.finish();
|
||||
});
|
||||
}
|
||||
|
||||
for (const [name, xml, body] of [
|
||||
['all aggregate limits equal', boundary().xml, boundary().body],
|
||||
['depth equal', deep(LIMITS.depth)],
|
||||
['element count equal', elements(LIMITS.elements)],
|
||||
['attribute count equal', attributes(LIMITS.attributes)],
|
||||
['attribute value equal', `<message xmlns="jabber:client" a="${'v'.repeat(256)}"/>`],
|
||||
['name equal', `<message xmlns="jabber:client"><${'x'.repeat(128)}/></message>`],
|
||||
['UTF-8 byte equality', message('🦉'.repeat(1000) + 'a'.repeat(4096 - message('').length - 4000)), '🦉'.repeat(1000) + 'a'.repeat(4096 - message('').length - 4000)],
|
||||
['escaped text and CDATA', message('<&<![CDATA[<fixture>]]>'), '<&<fixture>'],
|
||||
['prefixed namespace', '<c:message xmlns:c="jabber:client"><c:body>namespace</c:body></c:message>', 'namespace']
|
||||
]) {
|
||||
test(`actual parser/import accepts ${name}`, async () => {
|
||||
const h = await harness();
|
||||
h.socket.onmessage({data: xml});
|
||||
await tick();
|
||||
assert.deepEqual(h.errors, []);
|
||||
assert.equal(h.received.length, 1);
|
||||
assert.equal(h.received[0].kind, 'message');
|
||||
if (body !== undefined) assert.equal(h.received[0].stanza.body, body);
|
||||
assert.equal(h.stanzas.length, 1);
|
||||
assert.ok(h.imports() > 0);
|
||||
await h.finish();
|
||||
});
|
||||
}
|
||||
|
||||
test('bytes one over and UTF-8 one over reject before import', async () => {
|
||||
for (const xml of [boundary().xml + ' ', message('🦉'.repeat(1000) + 'a'.repeat(4097 - message('').length - 4000))]) {
|
||||
const h = await harness(); h.socket.onmessage({data: xml});
|
||||
assert.deepEqual(h.errors, ['bytes']); assert.equal(h.imports(), 0);
|
||||
await h.finish();
|
||||
}
|
||||
});
|
||||
|
||||
test('stock 18-message partial document never accumulates or revives; fresh connect works', async () => {
|
||||
const h = await harness(); const old = h.socket.onmessage;
|
||||
old({data: opening});
|
||||
for (let i = 0; i < 16; i++) old({data: 'a'.repeat(4096)});
|
||||
old({data: closing});
|
||||
await tick();
|
||||
assert.equal(h.received.length, 0); assert.equal(h.imports(), 0);
|
||||
assert.deepEqual(h.errors, ['invalid-xml']);
|
||||
await h.client.connect(); const fresh = h.sockets.at(-1); fresh.onopen();
|
||||
old({data: valid}); assert.equal(h.received.length, 0);
|
||||
fresh.onmessage({data: valid}); await tick();
|
||||
assert.equal(h.received.length, 1); assert.equal(h.stanzas.length, 1);
|
||||
assert.equal(h.received[0].stanza.body, 'finite fixture');
|
||||
await h.finish();
|
||||
});
|
||||
|
||||
test('successive complete documents have no shared namespace/parser state', async () => {
|
||||
const h = await harness();
|
||||
h.socket.onmessage({data: valid}); h.socket.onmessage({data: valid}); await tick();
|
||||
assert.equal(h.stanzas.length, 2);
|
||||
h.socket.onmessage({data: '<c:message/>'}); await tick();
|
||||
assert.deepEqual(h.errors, ['invalid-xml']); assert.equal(h.stanzas.length, 2);
|
||||
await h.finish();
|
||||
});
|
||||
|
||||
test('open, restart, message, outgoing export and close use actual registry', async () => {
|
||||
const h = await harness();
|
||||
h.socket.onmessage({data: '<open xmlns="urn:ietf:params:xml:ns:xmpp-framing" from="example.invalid" version="1.0"/>'});
|
||||
assert.equal(h.client.transport.hasStream, true); assert.equal(h.starts.length, 1);
|
||||
h.client.transport.restart(); assert.equal(h.client.transport.hasStream, false);
|
||||
await h.client.transport.send('message', {body: 'outgoing fixture'});
|
||||
assert.ok(h.socket.sent.at(-1).includes('outgoing fixture'));
|
||||
h.socket.onmessage({data: '<close xmlns="urn:ietf:params:xml:ns:xmpp-framing"/>'});
|
||||
await tick(); assert.equal(h.socket.closes, 1); assert.equal(h.client.transport, undefined);
|
||||
assert.equal(h.errors.length, 0);
|
||||
await h.finish();
|
||||
});
|
||||
|
||||
test('failed subprotocol, socket error, clean disconnect and stale callbacks are terminal', async () => {
|
||||
for (const mode of ['subprotocol', 'error', 'clean']) {
|
||||
const h = await harness(); const old = h.socket.onmessage;
|
||||
if (mode === 'subprotocol') {h.socket.protocol = 'wrong'; h.socket.onopen();}
|
||||
if (mode === 'error') h.socket.onerror(new Error('fixture'));
|
||||
if (mode === 'clean') {
|
||||
h.socket.onmessage({data: '<open xmlns="urn:ietf:params:xml:ns:xmpp-framing"/>'});
|
||||
h.client.transport.disconnect(); assert.ok(h.socket.sent.at(-1).includes('close'));
|
||||
}
|
||||
old({data: valid}); await tick();
|
||||
assert.equal(h.received.length, 0); assert.equal(h.socket.closes, 1);
|
||||
await h.finish();
|
||||
}
|
||||
});
|
||||
|
||||
test('SAX framing validation retains no attempt object', () => {
|
||||
assert.throws(() => validateMessage(opening));
|
||||
assert.throws(() => validateMessage(closing));
|
||||
assert.doesNotThrow(() => validateMessage(valid));
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
# Матрица задач
|
||||
|
||||
Generated; state revision **43**. Canonical status: state/tasks.json.
|
||||
Generated; state revision **45**. Canonical status: state/tasks.json.
|
||||
|
||||
| ID | Этап | Оператор | Reviewer | Статус | Owner | Зависимости | Задача |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
@@ -20,7 +20,7 @@ Generated; state revision **43**. Canonical status: state/tasks.json.
|
||||
| [S00-015](tasks/S00-015.md) | S00 | ci-cd | qa | done | auto-ci-cd-84e209103f24 | S00-001, S00-011, S00-013, S00-014, S00-016 | Устранить прерывание: Fix runner prompt delivery after partial stdin timeout |
|
||||
| [S00-016](tasks/S00-016.md) | S00 | ci-cd | qa | done | auto-ci-cd-351a0cbbabef | S00-001, S00-011, S00-013, S00-014 | Restore reviewer model availability after provider capacity failure |
|
||||
| [S00-017](tasks/S00-017.md) | S00 | protocol | security | done | auto-protocol-599343cd9e3f | S00-001, S00-002 | Establish fail-closed SCRAM server-final validation |
|
||||
| [S00-018](tasks/S00-018.md) | S00 | protocol | security | todo | | S00-001, S00-002, S00-017 | Validate bounded standalone XML ingress for the XMPP candidate |
|
||||
| [S00-018](tasks/S00-018.md) | S00 | protocol | security | review | auto-protocol-89fe6563092c | S00-001, S00-002, S00-017 | Validate bounded standalone XML ingress for the XMPP candidate |
|
||||
| [S00-010](tasks/S00-010.md) | S00 | qa | orchestrator | todo | | S00-001, S00-002, S00-003, S00-004, S00-005, S00-006, S00-007, S00-008, S00-009 | Gate: Профиль и проверка стека |
|
||||
| [S01-001](tasks/S01-001.md) | S01 | orchestrator | security | todo | | S00-010 | Описать identity/model contracts |
|
||||
| [S01-002](tasks/S01-002.md) | S01 | orchestrator | security | todo | | S00-010, S01-001 | Описать async account context |
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
- [S00-015](../tasks/S00-015.md): Устранить прерывание: Fix runner prompt delivery after partial stdin timeout — ci-cd; done.
|
||||
- [S00-016](../tasks/S00-016.md): Restore reviewer model availability after provider capacity failure — ci-cd; done.
|
||||
- [S00-017](../tasks/S00-017.md): Establish fail-closed SCRAM server-final validation — protocol; done.
|
||||
- [S00-018](../tasks/S00-018.md): Validate bounded standalone XML ingress for the XMPP candidate — protocol; todo.
|
||||
- [S00-018](../tasks/S00-018.md): Validate bounded standalone XML ingress for the XMPP candidate — protocol; review.
|
||||
- [S00-010](../tasks/S00-010.md): Gate: Профиль и проверка стека — qa; todo.
|
||||
|
||||
## Граница этапа
|
||||
|
||||
@@ -15,7 +15,7 @@ S00-014,S00,ci-cd,qa,done,auto-ci-cd-14343249da62,"S00-001, S00-011, S00-013",Fi
|
||||
S00-015,S00,ci-cd,qa,done,auto-ci-cd-84e209103f24,"S00-001, S00-011, S00-013, S00-014, S00-016",Устранить прерывание: Fix runner prompt delivery after partial stdin timeout
|
||||
S00-016,S00,ci-cd,qa,done,auto-ci-cd-351a0cbbabef,"S00-001, S00-011, S00-013, S00-014",Restore reviewer model availability after provider capacity failure
|
||||
S00-017,S00,protocol,security,done,auto-protocol-599343cd9e3f,"S00-001, S00-002",Establish fail-closed SCRAM server-final validation
|
||||
S00-018,S00,protocol,security,todo,,"S00-001, S00-002, S00-017",Validate bounded standalone XML ingress for the XMPP candidate
|
||||
S00-018,S00,protocol,security,review,auto-protocol-89fe6563092c,"S00-001, S00-002, S00-017",Validate bounded standalone XML ingress for the XMPP candidate
|
||||
S00-010,S00,qa,orchestrator,todo,,"S00-001, S00-002, S00-003, S00-004, S00-005, S00-006, S00-007, S00-008, S00-009",Gate: Профиль и проверка стека
|
||||
S01-001,S01,orchestrator,security,todo,,S00-010,Описать identity/model contracts
|
||||
S01-002,S01,orchestrator,security,todo,,"S00-010, S01-001",Описать async account context
|
||||
|
||||
|
@@ -0,0 +1,4 @@
|
||||
Bound standalone XML ingress before Stanza parsing and import
|
||||
|
||||
Changes: Add an isolated public transport integration with finite byte, depth, element and attribute budgets; validate complete text XML with pinned saxes before real JXT parsing/import. Add adversarial and boundary fixtures, terminal cleanup tests, dependency notices and a proposed parser ADR.
|
||||
Validation: Fresh-cache npm ci and npm test passed all 55 tests with Node 24.21.0/npm 11.19.0. Reproduced three stock parser failures, checked ten exact dependency licenses/integrities and 340 unchanged Stanza files; make check passed 72 tooling tests. Scope and whitespace inspected. Browser runtime, live WSS and interoperability were not tested.
|
||||
@@ -0,0 +1,118 @@
|
||||
# S00-018 executor evidence
|
||||
|
||||
Agent: auto-protocol-89fe6563092c (protocol). Date: 2026-10-15.
|
||||
Result: bounded standalone XML ingress experiment and proposed ADR; independent security review pending.
|
||||
|
||||
Input: assigned master/startup/role/workflow instructions; resume/show/packet;
|
||||
required TESTING, decisions/README, blocker S00-018; exact ACC-004/NET-003/NET-004;
|
||||
accepted scope/stack/SASL ADRs and all direct dependency evidence/reviews/handoffs;
|
||||
original parser blocker evidence/handoff/probe; shipped Client/Transport/JXT and
|
||||
saxes API/source. No missing required input. No new shared contract is needed.
|
||||
Output: only experiments/0002-xmpp-library/parser-validation and
|
||||
docs/decisions/0002-xmpp-parser-validation.md, plus workflow metadata.
|
||||
|
||||
## Actual changes and demonstrated acceptance
|
||||
|
||||
Public Client.transports constructor registration and explicit single transport
|
||||
selection run real Client.connect. Per-message type/unit/UTF-8 byte checks precede
|
||||
new saxes XML 1.0 namespace-aware document parsing. Callback depth/element/
|
||||
attribute/name/value budgets precede candidate JXT.parse/registry.import.
|
||||
SAX close detects incompleteness; malformed/multiple-root documents never import
|
||||
an earlier complete root. All XML syntax uses existing libraries. Global input
|
||||
bytes bound unfinished/oversized tokens before event callbacks. No vendor patch,
|
||||
late interception, fixture parser or handwritten XML security parser.
|
||||
|
||||
Local inclusive budgets: 4096 UTF-8 bytes, depth 8, elements 32, attributes 16
|
||||
including namespace declarations, aggregate attribute name+decoded value units
|
||||
1024, names 128, decoded attribute values 256. Combined boundary fixture meets
|
||||
all aggregate ceilings simultaneously and yields its exact real imported body;
|
||||
separate Unicode/name/value equality cases pass. Limits remain experiment policy,
|
||||
not product/shared contract decisions. DTD/comment/PI/declaration reject;
|
||||
namespace, entities, malformed chars and duplicate attributes checked by saxes.
|
||||
|
||||
55 tests use actual Client/JXT/registry/queue. FixtureSocket captures only socket
|
||||
effects; registry tracing calls the real import. Original 1 MiB body, depth 256,
|
||||
and 18-message partial-document categories reject terminally. Bad input never
|
||||
delivers stanza or stream:start, invalid syntax/budgets never reach registry
|
||||
import, and old captured callbacks cannot revive the attempt. Callback detachment,
|
||||
stream/config cleanup, fresh Client.connect, successive independent documents,
|
||||
stream open/close/restart, export/send and subprotocol/socket failure are tested.
|
||||
No peer payload/error text is logged or raw-evented.
|
||||
|
||||
## Actual commands and results
|
||||
|
||||
All Node/npm commands used
|
||||
PATH=/private/tmp/luma-stack-runtime/node-v24.21.0-darwin-arm64/bin:$PATH,
|
||||
the previously reviewed isolated Node 24.21.0/npm 11.19.0, from project root.
|
||||
No system install or certificate override. Exact engine pins and strict SSL
|
||||
remain in manifest/.npmrc. No new runtime archive verification claimed.
|
||||
|
||||
| Command | Exit | Observed result |
|
||||
| --- | --- | --- |
|
||||
| python3 scripts/tasks.py resume --agent auto-protocol-89fe6563092c | 0 | Assigned S00-018 in_progress, no repeat claim |
|
||||
| python3 scripts/tasks.py show S00-018; packet S00-018 --agent auto-protocol-89fe6563092c (separate invocations) | 0 each | Scope/prerequisites/requirements confirmed |
|
||||
| node experiments/0002-xmpp-library/parser-probe/reproduce.mjs | 0 | Stock accepted 18 writes/65536 body bytes, 1048576-byte body, 256 nested children; defect reproduction, not safe result |
|
||||
| npm view saxes@6.0.0 version license engines dependencies --json --cache /private/tmp/luma-parser-cache --fetch-retries=0 --fetch-timeout=15000 --strict-ssl=true | 0 | 6.0.0, ISC, Node >=v12.22.7, xmlchars ^2.2.0 |
|
||||
| npm install --prefix experiments/0002-xmpp-library/parser-validation --ignore-scripts --no-audit --no-fund --cache /private/tmp/luma-parser-cache --fetch-retries=0 --fetch-timeout=15000 | 0 | Ten packages, independent lock generated |
|
||||
| npm test --prefix experiments/0002-xmpp-library/parser-validation | 0 | 55 passed, zero failed/skipped/cancelled, 378.193208 ms |
|
||||
| npm ci --prefix experiments/0002-xmpp-library/parser-validation --ignore-scripts --no-audit --no-fund --cache /private/tmp/luma-parser-clean-89fe6563092c --fetch-retries=0 --fetch-timeout=15000 | 0 | Actual clean install with fresh cache, ten packages, scripts disabled |
|
||||
| npm test --prefix experiments/0002-xmpp-library/parser-validation after ci | 0 | 55 passed, zero failed/skipped/cancelled, 341.101792 ms; runtime/test source unchanged afterward |
|
||||
| curl --fail --silent --show-error https://raw.githubusercontent.com/lddubeau/saxes/v6.0.0/LICENSE -o /private/tmp/luma-parser-saxes-LICENSE | 0 | Upstream full ISC lineage/historical MIT notice retrieved through verified HTTPS; preserved in experiment |
|
||||
| Corrected inline Python license collector | 0 | Ten exact installed versions/licenses/HTTPS/SHA512 entries; preserved shipped notices plus upstream saxes LICENSE |
|
||||
| python3 experiments/0002-xmpp-library/parser-validation/check-dependencies.py | 0 | Ten exact graph/license checks; all 340 Stanza files byte-match original candidate |
|
||||
| make check | 0 | 283 tasks, 22 stages, 221 requirements, 211 Web requirements, revision 44; 72 tooling tests in 18.439s |
|
||||
| git diff --check; git status --short --untracked-files=all (separate checks) | 0 each | Scoped source only plus coordinator state claim before evidence |
|
||||
| Inline Python authored-file whitespace/final-newline checks | 0 | All 12 authored experiment/ADR files checked, including untracked files |
|
||||
|
||||
Exploratory failures are not passed checks: guessed transports/index.d.ts absent
|
||||
(actual Transport API is index.d.ts); first license collector failed because
|
||||
saxes tarball omits LICENSE (Python AssertionError, surrounding shell ended 0
|
||||
because following npm ci succeeded). Guessed upstream root saxes.ts URL returned
|
||||
404; subsequent head/rg saw no file (combined command exit 2). Actual upstream
|
||||
LICENSE fetch succeeded; no required artifact is missing and no source patch
|
||||
was attempted. These failures do not affect the reproduced acceptance checks.
|
||||
|
||||
## Primary sources and dependencies
|
||||
|
||||
Opened RFC 7395 §3.2/3.3.3 through web tools; versioned saxes README/package source,
|
||||
upstream Stanza Client source; inspected installed version-pinned declarations
|
||||
and implementation. Direct links and constraints are in ADR. Sources inspected
|
||||
2026-10-15. The supported extension claim rests on public shipped constructor
|
||||
registry/Transport interface and actual Client selection, not private fields.
|
||||
|
||||
New direct pins saxes 6.0.0 ISC / xmlchars 2.2.0 MIT, existing Stanza 12.22.1 MIT.
|
||||
Other exact installed packages: @types/node 22.20.5, @types/punycode 2.1.4,
|
||||
@types/ws 8.18.2, punycode 2.3.1, sdp 3.2.2, undici-types 6.21.0, ws 8.22.0,
|
||||
all MIT. Inventory/notices and lock are preserved. Saxes release is older;
|
||||
continued support/advisory/provenance clearance is not assumed. Node-focused
|
||||
CommonJS packages require browser bundling. Default adapter uses native browser
|
||||
WebSocket, URL, TextEncoder and private fields; fixture injection is explicit.
|
||||
|
||||
SHA256:
|
||||
- package-lock.json: 35b177d57aaf81778eaf3d3321b3f77eb1e755a46abee784ef62b8959aedd63c
|
||||
- bounded-ingress.mjs: e6399ff581f59d1f09b471234d6e4b8f2ed6b61804aa4eb0eef7dd3f8e3f2dbc
|
||||
- licenses/saxes-6.0.0-LICENSE: 0fac2374380621b22e6b50451057721a9c52935b02d16d106a9f04897f061d0e
|
||||
|
||||
## Limits and independent review input
|
||||
|
||||
No browser build/runtime, actual WSS/TLS/server handshake, auth changes,
|
||||
independent client interoperability, load/exhaustion benchmark or security audit
|
||||
was performed. No TLS/CORS bypass, real credentials/conversations, custom crypto
|
||||
or invented binding. Original candidate, reviewed SASL plugin, app modules,
|
||||
shared contracts, immutable specs and plan definitions unchanged. Git mutations
|
||||
and additional task/agent launch were not performed.
|
||||
|
||||
Browser WebSocket allocates a complete inbound message before JavaScript checks;
|
||||
this experiment bounds parser work afterward, not network-stack memory. SAX can
|
||||
store one token/attribute before a callback, bounded by the byte precheck. Total
|
||||
traffic, Client queues, downstream extension work and CPU rate are not bounded.
|
||||
Minimal transport lacks full stream-error/close negotiation/redirect/keepalive/
|
||||
language inheritance/stream sequencing. Complete SAX/JXT semantic equivalence
|
||||
is not certified. See README/ADR; these limits prohibit production-readiness
|
||||
claims but do not invalidate the assigned local parser/framing experiment.
|
||||
|
||||
Separate security reviewer must reproduce README clean install/tests/license
|
||||
checks, inspect actual scope/order/API/cleanup and compare this evidence and
|
||||
executor commit message with actual patch. ADR remains proposed and task is
|
||||
submitted for review, not done. Coordinator commits and launches fresh review;
|
||||
this executor stops after submit and does not resume S00-003.
|
||||
@@ -0,0 +1,39 @@
|
||||
# S00-018 handoff for independent security review
|
||||
|
||||
Executor: auto-protocol-89fe6563092c (protocol), 2026-10-15.
|
||||
Outcome: isolated bounded XML ingress experiment and proposed parser ADR.
|
||||
No blocker; implementation awaits independent security review.
|
||||
|
||||
Actual result: new public Client.transports constructor selected by actual
|
||||
Client.connect, finite byte precheck, fresh saxes strict namespace-aware XML 1.0
|
||||
validation/close per message, then actual JXT.parse/registry.import. Explicit
|
||||
local byte/depth/element/attribute/name/value limits apply before tree/import.
|
||||
Malformed/incomplete/multiple-root/binary/budget violations close attempt,
|
||||
detach callbacks, clear stream/config; stale callbacks cannot revive it. A fresh
|
||||
connection works. No persistent parser, vendor patch or custom XML syntax parser.
|
||||
|
||||
Pinned Node 24.21.0/npm 11.19.0 fresh-cache npm ci and 55 integrated tests passed;
|
||||
stock probe reproduced all three failures; license checks for all ten packages
|
||||
and byte comparison of all 340 Stanza files passed. make check: 72 tests passed.
|
||||
Commands/digests/failures/limits: state/evidence/S00-018-auto-protocol-89fe6563092c.md.
|
||||
|
||||
Next belongs only to security reviewer: inspect proposed
|
||||
docs/decisions/0002-xmpp-parser-validation.md, experiment source/tests/notices,
|
||||
executor diff/message and README. Run README commands with the reviewed isolated
|
||||
runtime at /private/tmp/luma-stack-runtime/node-v24.21.0-darwin-arm64/bin and a
|
||||
fresh reviewer cache. Verify budget/framing checks precede JXT allocations/import,
|
||||
actual Client registry selection, boundary success, zero delivery for bad input,
|
||||
terminal callback replay/cleanup and fresh attempts. check-dependencies.py also
|
||||
needs the original parent candidate installed for vendor comparison. Saxes
|
||||
published package omits LICENSE; preserved v6.0.0 upstream LICENSE and source are
|
||||
recorded. Keep ADR proposed until independent acceptance.
|
||||
|
||||
Limits: fixture socket only, no browser build/runtime or real WSS/server/client
|
||||
interop; byte checks begin after browser allocates the message. No aggregate
|
||||
traffic/Client queue/rate bounds or production policy. Minimal transport lacks
|
||||
full stream-error/close negotiation/redirect/keepalive/language inheritance/
|
||||
sequencing, and exhaustive SAX/JXT equivalence is not certified. Auth/crypto and
|
||||
accepted SASL experiment unchanged. No specs/shared interfaces/app modules or
|
||||
original candidate files changed. S00-003 remains separate; only reviewed done
|
||||
and coordinator commit allow a fresh original executor to continue it. This
|
||||
executor exits after submit; no commit/next agent/original work is performed.
|
||||
+31
-4
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"revision": 43,
|
||||
"revision": 45,
|
||||
"tasks": {
|
||||
"S00-001": {
|
||||
"status": "done",
|
||||
@@ -1236,10 +1236,14 @@
|
||||
"completed_at": "2026-10-14T19:20:57+00:00"
|
||||
},
|
||||
"S00-018": {
|
||||
"status": "todo",
|
||||
"owner": null,
|
||||
"status": "review",
|
||||
"owner": "auto-protocol-89fe6563092c",
|
||||
"external_wait": false,
|
||||
"reason": null
|
||||
"reason": null,
|
||||
"started_at": "2026-10-14T19:24:01+00:00",
|
||||
"updated_at": "2026-10-14T19:31:32+00:00",
|
||||
"evidence": "state/evidence/S00-018-auto-protocol-89fe6563092c.md",
|
||||
"handoff": "state/handoffs/S00-018.md"
|
||||
}
|
||||
},
|
||||
"events": [
|
||||
@@ -1798,6 +1802,29 @@
|
||||
"from": "in_progress",
|
||||
"to": "blocked",
|
||||
"reason": "S00-003 cannot attest parser limits: Stanza 12.22.1 exposes no resource bounds and its persistent WebSocket parser accepts large/deep XML and reassembles incomplete documents across separate input messages."
|
||||
},
|
||||
{
|
||||
"revision": 44,
|
||||
"at": "2026-10-14T19:24:01+00:00",
|
||||
"action": "claim",
|
||||
"task": "S00-018",
|
||||
"agent": "auto-protocol-89fe6563092c",
|
||||
"role": "protocol",
|
||||
"from": "todo",
|
||||
"to": "in_progress",
|
||||
"reason": null
|
||||
},
|
||||
{
|
||||
"revision": 45,
|
||||
"at": "2026-10-14T19:31:32+00:00",
|
||||
"action": "submit",
|
||||
"task": "S00-018",
|
||||
"agent": "auto-protocol-89fe6563092c",
|
||||
"role": null,
|
||||
"from": "in_progress",
|
||||
"to": "review",
|
||||
"reason": null,
|
||||
"evidence": "state/evidence/S00-018-auto-protocol-89fe6563092c.md"
|
||||
}
|
||||
],
|
||||
"retired_agents": [
|
||||
|
||||
Reference in new issue
Block a user