Skip to content

Commit 869ec8b

Browse files
committed
Use @nodable/entities v2.1.0
1 parent 7cb49e5 commit 869ec8b

File tree

15 files changed

+237
-86
lines changed

15 files changed

+237
-86
lines changed

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,21 @@
22

33
Note: Due to some last quick changes on v4, detail of v4.5.3 & v4.5.4 are not updated here. v4.5.4x is the last tag of v4 in github repository. I'm extremely sorry for the confusion
44

5+
**5.7.0**
6+
- Use `@nodable/entities` v2.1.0
7+
- breaking changes
8+
- single entity scan. You're not allowed to user entity value to form another entity name.
9+
- you cant add numeric external entity
10+
- entity error message when expantion limit is crossed might change
11+
- typings are updated for new options related to process entity
12+
- please follow documentation of `@nodable/entities` for more detail.
13+
- performance
14+
- if processEntities is false, then there should not be impact on performance.
15+
- if processEntities is true, but you dont pass entity decoder separately then performance may degrade by approx 8-10%
16+
- if processEntities is true, and you pass entity decoder separately
17+
- if no entity then performance should be same as before
18+
- if there are entities then performance should be increased
19+
520
**5.6.0 / 2026-04-15**
621
- fix: entity replacement for numeric entities
722
- use @nodable/entities to replace entities

docs/v4, v5/2.XMLparseOptions.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,34 @@ Output
351351
## htmlEntities
352352
FXP by default parse XML entities if `processEntities: true`. You can set `htmlEntities` to parse HTML entities. Check [entities](./5.Entities.md) section for more information.
353353

354+
## entityDecoder
355+
356+
`entityDecoder` option is supported v5.7.0 onward. It allows you to set your own entity decoder which supports following methods.
357+
358+
```
359+
type EntityDecoderOptions = {
360+
setExternalEntities: (entities: Record<string, string>) => void;
361+
addInputEntities: (entities: Record<string, string>) => void;
362+
reset: () => void;
363+
decode: (text: string) => string;
364+
setXmlVersion: (version: string) => void;
365+
}
366+
```
367+
368+
We're not explicitely checking the type and required methods but parser may throw error if the provided object doesn't have the required methods.
369+
370+
If XML document has version attribute in xml declaration then it will be passed to `setXmlVersion` method of the decoder to handle NCR gradefully.
371+
372+
When `processEntities` is set to `false` then `entityDecoder` will not be used. But if 'true' and `entityDecoder` is not provided then default entity decoder (`@nodable/entities`) will be used.
373+
374+
When `entityDecoder` is provided then following options which are set ot parser directly will be ignored. User is expected them to set them in decoder's config.
375+
- htmlEntities
376+
- maxTotalExpansions
377+
- maxExpandedLength
378+
379+
380+
381+
354382
## ignoreAttributes
355383

356384
By default, `ignoreAttributes` is set to `true`. This means that attributes are ignored by the parser. If you set any configuration related to attributes without setting `ignoreAttributes: false`, it will not have any effect.

docs/v4, v5/5.Entities.md

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,6 @@ Output:
140140
</note>
141141
```
142142

143-
## Side Effects
144-
145143
FXP silently ignores entities with `&` in their values for security. However, be aware of how multiple entities interact:
146144

147145
```xml
@@ -190,27 +188,7 @@ While FXP blocks many entity-based attacks through its security limits and by re
190188

191189
## HTML Entities
192190

193-
Following HTML entities are supported when `htmlEntities: true`:
194-
195-
| Result | Description | Entity Name | Entity Number |
196-
| :----- | :--------------------------------- | :---------- | :------------ |
197-
| | non-breaking space | `&nbsp;` | `&#160;` |
198-
| < | less than | `&lt;` | `&#60;` |
199-
| > | greater than | `&gt;` | `&#62;` |
200-
| & | ampersand | `&amp;` | `&#38;` |
201-
| " | double quotation mark | `&quot;` | `&#34;` |
202-
| ' | single quotation mark | `&apos;` | `&#39;` |
203-
| ¢ | cent | `&cent;` | `&#162;` |
204-
| £ | pound | `&pound;` | `&#163;` |
205-
| ¥ | yen | `&yen;` | `&#165;` |
206-
|| euro | `&euro;` | `&#8364;` |
207-
| © | copyright | `&copy;` | `&#169;` |
208-
| ® | registered trademark | `&reg;` | `&#174;` |
209-
|| Indian Rupee | `&inr;` | `&#8377;` |
210-
211-
In addition, [numeric character references](https://html.spec.whatwg.org/multipage/syntax.html#syntax-charref) are supported - both decimal (`&#123;`) and hexadecimal (`&#x7B;`).
212-
213-
FXP supports reading Notations and Elements from v5.2.1 onwards. However, it doesn't take any action based on these values.
191+
[Common HTML entities](https://github.com/nodable/val-parsers/blob/main/Entity/src/entities.js#L1152) and numeric (decimal, hex) are supported when `htmlEntities: true`:
214192

215193
## External Entities
216194

@@ -228,4 +206,6 @@ This method also allows you to override default entities.
228206

229207
**Note:** External entities added this way bypass DOCTYPE validation but are still subject to the same security limits when `processEntities: true`.
230208

209+
You can't set numerical or NCR entities as external entity.
210+
231211
[> Next: HTML Document Parsing](./6.HTMLParsing.md)

lib/fxp.d.cts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,14 @@ type ProcessEntitiesOptions = {
219219
tagFilter?: ((tagName: string, jPathOrMatcher: JPathOrMatcher) => boolean) | null;
220220
};
221221

222+
type EntityDecoderOptions = {
223+
setExternalEntities: (entities: Record<string, string>) => void;
224+
addInputEntities: (entities: Record<string, string>) => void;
225+
reset: () => void;
226+
decode: (text: string) => string;
227+
setXmlVersion: (version: string) => void;
228+
}
229+
222230
type X2jOptions = {
223231
/**
224232
* Preserve the order of tags in resulting JS object
@@ -398,16 +406,22 @@ type X2jOptions = {
398406
* When `ProcessEntitiesOptions` - enables entity processing with custom configuration
399407
*
400408
* Defaults to `true`
409+
* @deprecated Use `entityDecoder` instead
401410
*/
402411
processEntities?: boolean | ProcessEntitiesOptions;
403412

404413
/**
405414
* Whether to process HTML entities
406415
*
407416
* Defaults to `false`
417+
* @deprecated Use `entityDecoder` instead
408418
*/
409419
htmlEntities?: boolean;
410420

421+
/**
422+
* Custom entity decoder
423+
*/
424+
entityDecoder?: EntityDecoderOptions;
411425
/**
412426
* Whether to ignore the declaration tag from output
413427
*
@@ -713,8 +727,10 @@ declare class XMLParser {
713727
declare class XMLValidator {
714728
static validate(xmlData: string, options?: validationOptions): true | ValidationError;
715729
}
716-
717-
declare class XMLBuilder {
730+
/**
731+
* @deprecated Use npm package 'fast-xml-builder' instead
732+
*/
733+
devlare class XMLBuilder {
718734
constructor(options?: XmlBuilderOptions);
719735
build(jObj: any): string;
720736
}
@@ -747,6 +763,7 @@ declare namespace fxp {
747763
MatcherView,
748764
JPathOrMatcher,
749765
JPathOrExpression,
766+
EntityDecoderOptions
750767
}
751768
}
752769

package-lock.json

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,9 @@
8787
}
8888
],
8989
"dependencies": {
90-
"@nodable/entities": "^1.1.0",
90+
"@nodable/entities": "^2.1.0",
9191
"fast-xml-builder": "^1.1.4",
9292
"path-expression-matcher": "^1.5.0",
9393
"strnum": "^2.2.3"
9494
}
95-
}
95+
}

spec/entities_security_spec.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ describe("XMLParser entity expansion security", function () {
7272

7373
expect(function () {
7474
parser.parse(xmlData);
75-
}).toThrowError("[EntityReplacer] Entity expansion count limit exceeded: 1500 > 1000");
75+
}).toThrowError("[EntityReplacer] Entity expansion count limit exceeded: 1001 > 1000");
7676
});
7777

7878
it("should allow expansions within limit", function () {
@@ -109,7 +109,7 @@ describe("XMLParser entity expansion security", function () {
109109

110110
expect(function () {
111111
parser.parse(xmlData);
112-
}).toThrowError("[EntityReplacer] Entity expansion count limit exceeded: 1200 > 1000");
112+
}).toThrowError("[EntityReplacer] Entity expansion count limit exceeded: 1001 > 1000");
113113
});
114114
});
115115

@@ -132,7 +132,7 @@ describe("XMLParser entity expansion security", function () {
132132

133133
expect(function () {
134134
parser.parse(xmlData);
135-
}).toThrowError("[EntityReplacer] Expanded content length limit exceeded: 149250 > 100000");
135+
}).toThrowError("[EntityReplacer] Expanded content length limit exceeded: 100495 > 100000");
136136
});
137137

138138
it("should allow expansions within maxExpandedLength", function () {
@@ -188,7 +188,7 @@ describe("XMLParser entity expansion security", function () {
188188

189189
expect(function () {
190190
parser.parse(xmlData);
191-
}).toThrowError("[EntityReplacer] Entity expansion count limit exceeded: 5000 > 1000");
191+
}).toThrowError("[EntityReplacer] Entity expansion count limit exceeded: 1001 > 1000");
192192
});
193193

194194
it("should prevent billion laughs with maxExpandedLength", function () {
@@ -205,7 +205,7 @@ describe("XMLParser entity expansion security", function () {
205205

206206
expect(function () {
207207
parser.parse(xmlData);
208-
}).toThrowError("[EntityReplacer] Expanded content length limit exceeded: 199000 > 100000");
208+
}).toThrowError("[EntityReplacer] Expanded content length limit exceeded: 100495 > 100000");
209209
});
210210
});
211211

@@ -407,7 +407,7 @@ describe("XMLParser entity expansion security", function () {
407407

408408
expect(function () {
409409
parser.parse(xmlData);
410-
}).toThrowError("[EntityReplacer] Expanded content length limit exceeded: 19400 > 10000");
410+
}).toThrowError("[EntityReplacer] Expanded content length limit exceeded: 10088 > 10000");
411411
});
412412
});
413413

0 commit comments

Comments
 (0)