Files
LumaWeb/experiments/0002-xmpp-library/parser-validation/test/fixtures.mjs
T
wt e2b4dbdb76 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
2026-10-15 02:31:33 +07:00

69 lines
4.1 KiB
JavaScript

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('&amp'), '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('&#0;'), 'invalid-xml'],
['unknown root', '<unknown xmlns="urn:fixture"/>', 'unknown-root']
];