@json-to-office/jto 0.26.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +134 -77
- package/dist/cli.js.map +1 -1
- package/dist/client/assets/{HomePage-CcmtpSuV.js → HomePage-BX2wX21e.js} +3 -3
- package/dist/client/assets/HomePage-BX2wX21e.js.map +1 -0
- package/dist/client/assets/{JsonEditorPage-RDa8GWDd.js → JsonEditorPage-DseCjMok.js} +3 -3
- package/dist/client/assets/{JsonEditorPage-RDa8GWDd.js.map → JsonEditorPage-DseCjMok.js.map} +1 -1
- package/dist/client/assets/{MonacoPluginProvider-DM63WAJx.js → MonacoPluginProvider-DvO7h20V.js} +3 -3
- package/dist/client/assets/{MonacoPluginProvider-DM63WAJx.js.map → MonacoPluginProvider-DvO7h20V.js.map} +1 -1
- package/dist/client/assets/{button-CyTe9rTl.js → button-DzgfrDEj.js} +2 -2
- package/dist/client/assets/{button-CyTe9rTl.js.map → button-DzgfrDEj.js.map} +1 -1
- package/dist/client/assets/{editor-DCtGYNz2.js → editor-BDi6QWgh.js} +2 -2
- package/dist/client/assets/{editor-DCtGYNz2.js.map → editor-BDi6QWgh.js.map} +1 -1
- package/dist/client/assets/{editor-monaco-json-CU9ciwPv.js → editor-monaco-json-CsQqBG2A.js} +2 -2
- package/dist/client/assets/{editor-monaco-json-CU9ciwPv.js.map → editor-monaco-json-CsQqBG2A.js.map} +1 -1
- package/dist/client/assets/{index-CHAIoQtG.js → index-Cxjik2Rg.js} +3 -3
- package/dist/client/assets/{index-CHAIoQtG.js.map → index-Cxjik2Rg.js.map} +1 -1
- package/dist/client/assets/preview-BOF6SWhK.js +3 -0
- package/dist/client/assets/preview-BOF6SWhK.js.map +1 -0
- package/dist/client/index.html +1 -1
- package/dist/client/templates/management-plan.pptx.json +18 -18
- package/dist/client/templates/minimalist-pitch-deck.pptx.json +19 -19
- package/dist/client/templates/modern-annual-report-2.docx.json +12 -12
- package/dist/client/templates/modern-annual-report-3.docx.json +14 -14
- package/dist/client/templates/standard-annual-report.docx.json +2 -2
- package/dist/render-server.js +62 -48
- package/dist/render-server.js.map +1 -1
- package/package.json +7 -8
- package/dist/client/assets/HomePage-CcmtpSuV.js.map +0 -1
- package/dist/client/assets/preview-oxnxMi4x.js +0 -3
- package/dist/client/assets/preview-oxnxMi4x.js.map +0 -1
|
@@ -360,7 +360,7 @@
|
|
|
360
360
|
{
|
|
361
361
|
"name": "image",
|
|
362
362
|
"props": {
|
|
363
|
-
"path": "
|
|
363
|
+
"path": "media/modern-annual-report-2/hatch-1.88x2.13.png",
|
|
364
364
|
"x": 0.63,
|
|
365
365
|
"y": 8.43,
|
|
366
366
|
"w": 1.88,
|
|
@@ -1559,7 +1559,7 @@
|
|
|
1559
1559
|
{
|
|
1560
1560
|
"name": "image",
|
|
1561
1561
|
"props": {
|
|
1562
|
-
"path": "
|
|
1562
|
+
"path": "media/modern-annual-report-2/hatch-3.53x4.22.png",
|
|
1563
1563
|
"x": 0.5,
|
|
1564
1564
|
"y": 1.49,
|
|
1565
1565
|
"w": 3.53,
|
|
@@ -2511,7 +2511,7 @@
|
|
|
2511
2511
|
{
|
|
2512
2512
|
"name": "image",
|
|
2513
2513
|
"props": {
|
|
2514
|
-
"path": "
|
|
2514
|
+
"path": "media/modern-annual-report-2/hatch-2.19x2.61.png",
|
|
2515
2515
|
"x": 0.53,
|
|
2516
2516
|
"y": 8.62,
|
|
2517
2517
|
"w": 2.19,
|
|
@@ -3985,7 +3985,7 @@
|
|
|
3985
3985
|
{
|
|
3986
3986
|
"name": "image",
|
|
3987
3987
|
"props": {
|
|
3988
|
-
"path": "
|
|
3988
|
+
"path": "media/modern-annual-report-2/image2.png",
|
|
3989
3989
|
"x": 0.53,
|
|
3990
3990
|
"y": 1.91,
|
|
3991
3991
|
"w": 7.28,
|
|
@@ -4624,7 +4624,7 @@
|
|
|
4624
4624
|
{
|
|
4625
4625
|
"name": "image",
|
|
4626
4626
|
"props": {
|
|
4627
|
-
"path": "
|
|
4627
|
+
"path": "media/modern-annual-report-2/hatch-2.57x2.91.png",
|
|
4628
4628
|
"x": 5.17,
|
|
4629
4629
|
"y": 0.55,
|
|
4630
4630
|
"w": 2.57,
|
|
@@ -10651,7 +10651,7 @@
|
|
|
10651
10651
|
{
|
|
10652
10652
|
"name": "image",
|
|
10653
10653
|
"props": {
|
|
10654
|
-
"path": "
|
|
10654
|
+
"path": "media/modern-annual-report-2/hatch-2.78x3.03.png",
|
|
10655
10655
|
"x": 4.97,
|
|
10656
10656
|
"y": 0.44,
|
|
10657
10657
|
"w": 2.78,
|
|
@@ -12075,7 +12075,7 @@
|
|
|
12075
12075
|
{
|
|
12076
12076
|
"name": "image",
|
|
12077
12077
|
"props": {
|
|
12078
|
-
"path": "
|
|
12078
|
+
"path": "media/modern-annual-report-2/hatch-3.8x5.41.png",
|
|
12079
12079
|
"x": 0.45,
|
|
12080
12080
|
"y": 0.41,
|
|
12081
12081
|
"w": 3.8,
|
|
@@ -12535,7 +12535,7 @@
|
|
|
12535
12535
|
{
|
|
12536
12536
|
"name": "image",
|
|
12537
12537
|
"props": {
|
|
12538
|
-
"path": "
|
|
12538
|
+
"path": "media/modern-annual-report-2/image4.png",
|
|
12539
12539
|
"x": 0.48,
|
|
12540
12540
|
"y": 7.24,
|
|
12541
12541
|
"w": 7.27,
|
|
@@ -13049,7 +13049,7 @@
|
|
|
13049
13049
|
{
|
|
13050
13050
|
"name": "image",
|
|
13051
13051
|
"props": {
|
|
13052
|
-
"path": "
|
|
13052
|
+
"path": "media/modern-annual-report-2/hatch-2.22x2.88.png",
|
|
13053
13053
|
"x": 2.99,
|
|
13054
13054
|
"y": 6.26,
|
|
13055
13055
|
"w": 2.22,
|
|
@@ -14376,7 +14376,7 @@
|
|
|
14376
14376
|
{
|
|
14377
14377
|
"name": "image",
|
|
14378
14378
|
"props": {
|
|
14379
|
-
"path": "
|
|
14379
|
+
"path": "media/modern-annual-report-2/image6.png",
|
|
14380
14380
|
"x": 0.44,
|
|
14381
14381
|
"y": 0.49,
|
|
14382
14382
|
"w": 7.27,
|
|
@@ -14386,7 +14386,7 @@
|
|
|
14386
14386
|
{
|
|
14387
14387
|
"name": "image",
|
|
14388
14388
|
"props": {
|
|
14389
|
-
"path": "
|
|
14389
|
+
"path": "media/modern-annual-report-2/hatch-1.86x2.03.png",
|
|
14390
14390
|
"x": 0.45,
|
|
14391
14391
|
"y": 9.18,
|
|
14392
14392
|
"w": 1.86,
|
|
@@ -14940,7 +14940,7 @@
|
|
|
14940
14940
|
{
|
|
14941
14941
|
"name": "image",
|
|
14942
14942
|
"props": {
|
|
14943
|
-
"path": "
|
|
14943
|
+
"path": "media/modern-annual-report-2/hatch-4.46x6.42.png",
|
|
14944
14944
|
"x": 3.34,
|
|
14945
14945
|
"y": 0.52,
|
|
14946
14946
|
"w": 4.46,
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
{
|
|
87
87
|
"name": "image",
|
|
88
88
|
"props": {
|
|
89
|
-
"path": "
|
|
89
|
+
"path": "media/modern-annual-report-3/pct30-7054x10363-v2.png",
|
|
90
90
|
"x": 0.61,
|
|
91
91
|
"y": 0.67,
|
|
92
92
|
"w": 7.054,
|
|
@@ -432,7 +432,7 @@
|
|
|
432
432
|
{
|
|
433
433
|
"name": "image",
|
|
434
434
|
"props": {
|
|
435
|
-
"path": "
|
|
435
|
+
"path": "media/modern-annual-report-3/pct30-1817x2117-v2.png",
|
|
436
436
|
"x": 5.98,
|
|
437
437
|
"y": 1.57,
|
|
438
438
|
"w": 1.817,
|
|
@@ -840,7 +840,7 @@
|
|
|
840
840
|
{
|
|
841
841
|
"name": "image",
|
|
842
842
|
"props": {
|
|
843
|
-
"path": "
|
|
843
|
+
"path": "media/modern-annual-report-3/pct30-2544x3221-v2.png",
|
|
844
844
|
"x": 0.51,
|
|
845
845
|
"y": 7.22,
|
|
846
846
|
"w": 2.544,
|
|
@@ -1621,7 +1621,7 @@
|
|
|
1621
1621
|
{
|
|
1622
1622
|
"name": "image",
|
|
1623
1623
|
"props": {
|
|
1624
|
-
"path": "
|
|
1624
|
+
"path": "media/modern-annual-report-3/pct30-2084x2506-v2.png",
|
|
1625
1625
|
"x": 3.1,
|
|
1626
1626
|
"y": 3.06,
|
|
1627
1627
|
"w": 2.084,
|
|
@@ -1896,7 +1896,7 @@
|
|
|
1896
1896
|
{
|
|
1897
1897
|
"name": "image",
|
|
1898
1898
|
"props": {
|
|
1899
|
-
"path": "
|
|
1899
|
+
"path": "media/modern-annual-report-3/pct30-1312x1574-v2.png",
|
|
1900
1900
|
"x": 6.43,
|
|
1901
1901
|
"y": 2.1,
|
|
1902
1902
|
"w": 1.312,
|
|
@@ -3132,7 +3132,7 @@
|
|
|
3132
3132
|
{
|
|
3133
3133
|
"name": "image",
|
|
3134
3134
|
"props": {
|
|
3135
|
-
"path": "
|
|
3135
|
+
"path": "media/modern-annual-report-3/pct30-1618x1597-v2.png",
|
|
3136
3136
|
"x": 0.52,
|
|
3137
3137
|
"y": 5.62,
|
|
3138
3138
|
"w": 1.618,
|
|
@@ -7603,7 +7603,7 @@
|
|
|
7603
7603
|
{
|
|
7604
7604
|
"name": "image",
|
|
7605
7605
|
"props": {
|
|
7606
|
-
"path": "
|
|
7606
|
+
"path": "media/modern-annual-report-3/pct30-1822x2099-v2.png",
|
|
7607
7607
|
"x": 5.92,
|
|
7608
7608
|
"y": 4.96,
|
|
7609
7609
|
"w": 1.822,
|
|
@@ -9110,7 +9110,7 @@
|
|
|
9110
9110
|
{
|
|
9111
9111
|
"name": "image",
|
|
9112
9112
|
"props": {
|
|
9113
|
-
"path": "
|
|
9113
|
+
"path": "media/modern-annual-report-3/pct30-7253x2778-v2.png",
|
|
9114
9114
|
"x": 0.52,
|
|
9115
9115
|
"y": 5.26,
|
|
9116
9116
|
"w": 7.253,
|
|
@@ -9403,7 +9403,7 @@
|
|
|
9403
9403
|
{
|
|
9404
9404
|
"name": "image",
|
|
9405
9405
|
"props": {
|
|
9406
|
-
"path": "
|
|
9406
|
+
"path": "media/modern-annual-report-3/pct30-1874x2077-v2.png",
|
|
9407
9407
|
"x": 4.22,
|
|
9408
9408
|
"y": 0.5,
|
|
9409
9409
|
"w": 1.874,
|
|
@@ -10199,7 +10199,7 @@
|
|
|
10199
10199
|
{
|
|
10200
10200
|
"name": "image",
|
|
10201
10201
|
"props": {
|
|
10202
|
-
"path": "
|
|
10202
|
+
"path": "media/modern-annual-report-3/pct30-7256x6807-v2.png",
|
|
10203
10203
|
"x": 0.48,
|
|
10204
10204
|
"y": 0.45,
|
|
10205
10205
|
"w": 7.256,
|
|
@@ -10752,7 +10752,7 @@
|
|
|
10752
10752
|
{
|
|
10753
10753
|
"name": "image",
|
|
10754
10754
|
"props": {
|
|
10755
|
-
"path": "
|
|
10755
|
+
"path": "media/modern-annual-report-3/pct30-1308x1454-v2.png",
|
|
10756
10756
|
"x": 5.52,
|
|
10757
10757
|
"y": 4.2,
|
|
10758
10758
|
"w": 1.308,
|
|
@@ -11382,7 +11382,7 @@
|
|
|
11382
11382
|
{
|
|
11383
11383
|
"name": "image",
|
|
11384
11384
|
"props": {
|
|
11385
|
-
"path": "
|
|
11385
|
+
"path": "media/modern-annual-report-3/pct30-1660x1818-v2.png",
|
|
11386
11386
|
"x": 0.61,
|
|
11387
11387
|
"y": 9.24,
|
|
11388
11388
|
"w": 1.66,
|
|
@@ -12381,7 +12381,7 @@
|
|
|
12381
12381
|
{
|
|
12382
12382
|
"name": "image",
|
|
12383
12383
|
"props": {
|
|
12384
|
-
"path": "
|
|
12384
|
+
"path": "media/modern-annual-report-3/pct30-2622x3017-v2.png",
|
|
12385
12385
|
"x": 0.5,
|
|
12386
12386
|
"y": 5.08,
|
|
12387
12387
|
"w": 2.622,
|
|
@@ -12763,7 +12763,7 @@
|
|
|
12763
12763
|
{
|
|
12764
12764
|
"name": "image",
|
|
12765
12765
|
"props": {
|
|
12766
|
-
"path": "
|
|
12766
|
+
"path": "media/modern-annual-report-3/pct30-7054x10363-v2.png",
|
|
12767
12767
|
"x": 0.6,
|
|
12768
12768
|
"y": 0.61,
|
|
12769
12769
|
"w": 7.054,
|
|
@@ -6719,7 +6719,7 @@
|
|
|
6719
6719
|
{
|
|
6720
6720
|
"name": "image",
|
|
6721
6721
|
"props": {
|
|
6722
|
-
"path": "
|
|
6722
|
+
"path": "media/standard-annual-report/image23.png",
|
|
6723
6723
|
"width": 755,
|
|
6724
6724
|
"height": 504,
|
|
6725
6725
|
"floating": {
|
|
@@ -7005,7 +7005,7 @@
|
|
|
7005
7005
|
{
|
|
7006
7006
|
"name": "image",
|
|
7007
7007
|
"props": {
|
|
7008
|
-
"path": "
|
|
7008
|
+
"path": "media/standard-annual-report/image25.png",
|
|
7009
7009
|
"width": 301,
|
|
7010
7010
|
"height": 453,
|
|
7011
7011
|
"floating": {
|
package/dist/render-server.js
CHANGED
|
@@ -7,6 +7,7 @@ import { HTTPException as HTTPException4 } from "hono/http-exception";
|
|
|
7
7
|
import { secureHeaders } from "hono/secure-headers";
|
|
8
8
|
|
|
9
9
|
// src/server/rasterize-route.ts
|
|
10
|
+
import path from "path";
|
|
10
11
|
import { Type } from "@sinclair/typebox";
|
|
11
12
|
import { bodyLimit } from "hono/body-limit";
|
|
12
13
|
import { HTTPException as HTTPException2 } from "hono/http-exception";
|
|
@@ -69,9 +70,9 @@ function getValidated(c, target) {
|
|
|
69
70
|
|
|
70
71
|
// src/server/security/outbound-source-policy.ts
|
|
71
72
|
var UnsafeOutboundSourceError = class extends Error {
|
|
72
|
-
constructor(
|
|
73
|
-
super(`Unsafe outbound source at ${
|
|
74
|
-
this.path =
|
|
73
|
+
constructor(path2, reason) {
|
|
74
|
+
super(`Unsafe outbound source at ${path2}: ${reason}`);
|
|
75
|
+
this.path = path2;
|
|
75
76
|
this.name = "UnsafeOutboundSourceError";
|
|
76
77
|
}
|
|
77
78
|
};
|
|
@@ -125,36 +126,36 @@ function isPrivateHost(host) {
|
|
|
125
126
|
const firstIpv6Group = Number.parseInt(normalized.split(":")[0] || "0", 16);
|
|
126
127
|
return firstIpv6Group >= 64512 && firstIpv6Group <= 65023 || firstIpv6Group >= 65152 && firstIpv6Group <= 65215;
|
|
127
128
|
}
|
|
128
|
-
function assertAllowedUrl(source,
|
|
129
|
+
function assertAllowedUrl(source, path2, allowedHosts) {
|
|
129
130
|
if (source.startsWith("data:")) return;
|
|
130
131
|
let url;
|
|
131
132
|
try {
|
|
132
133
|
url = new URL(source);
|
|
133
134
|
} catch {
|
|
134
135
|
throw new UnsafeOutboundSourceError(
|
|
135
|
-
|
|
136
|
+
path2,
|
|
136
137
|
"local and relative file paths are disabled for HTTP requests"
|
|
137
138
|
);
|
|
138
139
|
}
|
|
139
140
|
if (url.protocol !== "https:") {
|
|
140
|
-
throw new UnsafeOutboundSourceError(
|
|
141
|
+
throw new UnsafeOutboundSourceError(path2, "only HTTPS URLs are allowed");
|
|
141
142
|
}
|
|
142
143
|
if (url.username || url.password) {
|
|
143
144
|
throw new UnsafeOutboundSourceError(
|
|
144
|
-
|
|
145
|
+
path2,
|
|
145
146
|
"URLs containing credentials are not allowed"
|
|
146
147
|
);
|
|
147
148
|
}
|
|
148
149
|
const host = url.hostname.toLowerCase().replace(/\.$/, "");
|
|
149
150
|
if (isPrivateHost(host)) {
|
|
150
151
|
throw new UnsafeOutboundSourceError(
|
|
151
|
-
|
|
152
|
+
path2,
|
|
152
153
|
`private or local host "${host}" is not allowed`
|
|
153
154
|
);
|
|
154
155
|
}
|
|
155
156
|
if (!allowedHosts.some((pattern) => hostMatches(host, pattern))) {
|
|
156
157
|
throw new UnsafeOutboundSourceError(
|
|
157
|
-
|
|
158
|
+
path2,
|
|
158
159
|
`host "${host}" is not in OUTBOUND_HOST_ALLOWLIST`
|
|
159
160
|
);
|
|
160
161
|
}
|
|
@@ -172,13 +173,13 @@ function extractCssReferences(input) {
|
|
|
172
173
|
function extractAbsoluteUrls(input) {
|
|
173
174
|
return input.match(/(?:https?|file):\/\/[^\s'"<>)}\]]+/gi) ?? [];
|
|
174
175
|
}
|
|
175
|
-
function assertSafeSvg(svg,
|
|
176
|
+
function assertSafeSvg(svg, path2, allowedHosts) {
|
|
176
177
|
if (/<\s*script\b/i.test(svg) || /<\s*(?:foreignObject|iframe|object|embed)\b/i.test(svg) || /\bon[a-z]+\s*=/i.test(svg)) {
|
|
177
|
-
throw new UnsafeOutboundSourceError(
|
|
178
|
+
throw new UnsafeOutboundSourceError(path2, "active SVG content is disabled");
|
|
178
179
|
}
|
|
179
180
|
if (/<!\s*(?:DOCTYPE|ENTITY)\b/i.test(svg)) {
|
|
180
181
|
throw new UnsafeOutboundSourceError(
|
|
181
|
-
|
|
182
|
+
path2,
|
|
182
183
|
"SVG document types and entities are disabled"
|
|
183
184
|
);
|
|
184
185
|
}
|
|
@@ -187,20 +188,20 @@ function assertSafeSvg(svg, path, allowedHosts) {
|
|
|
187
188
|
while (match = refPattern.exec(svg)) {
|
|
188
189
|
const ref = match[2].trim();
|
|
189
190
|
if (!ref || ref.startsWith("#") || ref.startsWith("data:")) continue;
|
|
190
|
-
assertAllowedUrl(ref,
|
|
191
|
+
assertAllowedUrl(ref, path2, allowedHosts);
|
|
191
192
|
}
|
|
192
193
|
for (const ref of extractCssReferences(svg)) {
|
|
193
194
|
if (ref.startsWith("#") || ref.startsWith("data:")) continue;
|
|
194
|
-
assertAllowedUrl(ref,
|
|
195
|
+
assertAllowedUrl(ref, path2, allowedHosts);
|
|
195
196
|
}
|
|
196
197
|
}
|
|
197
|
-
function assertSafeEncodedImage(source,
|
|
198
|
+
function assertSafeEncodedImage(source, path2, allowedHosts) {
|
|
198
199
|
let candidate = source.trim();
|
|
199
200
|
let declaredSvg = false;
|
|
200
201
|
if (candidate.startsWith("data:")) {
|
|
201
202
|
const comma = candidate.indexOf(",");
|
|
202
203
|
if (comma < 0) {
|
|
203
|
-
throw new UnsafeOutboundSourceError(
|
|
204
|
+
throw new UnsafeOutboundSourceError(path2, "malformed image data URL");
|
|
204
205
|
}
|
|
205
206
|
const metadata = candidate.slice(5, comma);
|
|
206
207
|
declaredSvg = metadata.split(";")[0].toLowerCase() === "image/svg+xml";
|
|
@@ -209,7 +210,7 @@ function assertSafeEncodedImage(source, path, allowedHosts) {
|
|
|
209
210
|
try {
|
|
210
211
|
candidate = /(?:^|;)base64(?:;|$)/i.test(metadata) ? Buffer.from(payload, "base64").toString("utf8") : decodeURIComponent(payload);
|
|
211
212
|
} catch {
|
|
212
|
-
throw new UnsafeOutboundSourceError(
|
|
213
|
+
throw new UnsafeOutboundSourceError(path2, "malformed SVG data URL");
|
|
213
214
|
}
|
|
214
215
|
} else if (!/<\s*svg\b/i.test(candidate)) {
|
|
215
216
|
candidate = Buffer.from(candidate, "base64").toString("utf8");
|
|
@@ -217,37 +218,37 @@ function assertSafeEncodedImage(source, path, allowedHosts) {
|
|
|
217
218
|
const svgStart = candidate.search(/<\s*svg\b/i);
|
|
218
219
|
if (svgStart < 0) {
|
|
219
220
|
if (declaredSvg) {
|
|
220
|
-
throw new UnsafeOutboundSourceError(
|
|
221
|
+
throw new UnsafeOutboundSourceError(path2, "malformed SVG image data");
|
|
221
222
|
}
|
|
222
223
|
return;
|
|
223
224
|
}
|
|
224
|
-
assertSafeSvg(candidate,
|
|
225
|
+
assertSafeSvg(candidate, path2, allowedHosts);
|
|
225
226
|
}
|
|
226
|
-
function assertSafeResources(resources,
|
|
227
|
+
function assertSafeResources(resources, path2, allowedHosts) {
|
|
227
228
|
if (typeof resources.js === "string" && resources.js.trim()) {
|
|
228
229
|
throw new UnsafeOutboundSourceError(
|
|
229
|
-
`${
|
|
230
|
+
`${path2}.js`,
|
|
230
231
|
"remote renderer JavaScript resources are disabled"
|
|
231
232
|
);
|
|
232
233
|
}
|
|
233
234
|
if (typeof resources.css === "string") {
|
|
234
235
|
for (const ref of extractCssReferences(resources.css)) {
|
|
235
236
|
if (ref.startsWith("data:")) continue;
|
|
236
|
-
assertAllowedUrl(ref, `${
|
|
237
|
+
assertAllowedUrl(ref, `${path2}.css`, allowedHosts);
|
|
237
238
|
}
|
|
238
239
|
}
|
|
239
240
|
if (Array.isArray(resources.files) && resources.files.length > 0) {
|
|
240
241
|
throw new UnsafeOutboundSourceError(
|
|
241
|
-
`${
|
|
242
|
+
`${path2}.files`,
|
|
242
243
|
"remote renderer JavaScript resources are disabled"
|
|
243
244
|
);
|
|
244
245
|
}
|
|
245
246
|
}
|
|
246
|
-
function assertNoRemoteReferences(value,
|
|
247
|
+
function assertNoRemoteReferences(value, path2, allowedHosts, seen) {
|
|
247
248
|
if (typeof value === "string") {
|
|
248
249
|
if (/\b(?:fetch|XMLHttpRequest|WebSocket|EventSource)\s*\(/i.test(value) || /\b(?:javascript|file):/i.test(value)) {
|
|
249
250
|
throw new UnsafeOutboundSourceError(
|
|
250
|
-
|
|
251
|
+
path2,
|
|
251
252
|
"network-capable JavaScript and file URLs are disabled"
|
|
252
253
|
);
|
|
253
254
|
}
|
|
@@ -256,11 +257,11 @@ function assertNoRemoteReferences(value, path, allowedHosts, seen) {
|
|
|
256
257
|
...extractCssReferences(value)
|
|
257
258
|
]) {
|
|
258
259
|
if (url.startsWith("data:")) continue;
|
|
259
|
-
assertAllowedUrl(url,
|
|
260
|
+
assertAllowedUrl(url, path2, allowedHosts);
|
|
260
261
|
}
|
|
261
262
|
if (/^\/\//.test(value.trim())) {
|
|
262
263
|
throw new UnsafeOutboundSourceError(
|
|
263
|
-
|
|
264
|
+
path2,
|
|
264
265
|
"protocol-relative URLs are disabled"
|
|
265
266
|
);
|
|
266
267
|
}
|
|
@@ -270,20 +271,20 @@ function assertNoRemoteReferences(value, path, allowedHosts, seen) {
|
|
|
270
271
|
seen.add(value);
|
|
271
272
|
if (Array.isArray(value)) {
|
|
272
273
|
value.forEach(
|
|
273
|
-
(entry, index) => assertNoRemoteReferences(entry, `${
|
|
274
|
+
(entry, index) => assertNoRemoteReferences(entry, `${path2}[${index}]`, allowedHosts, seen)
|
|
274
275
|
);
|
|
275
276
|
return;
|
|
276
277
|
}
|
|
277
278
|
for (const [key, child] of Object.entries(value)) {
|
|
278
|
-
assertNoRemoteReferences(child, `${
|
|
279
|
+
assertNoRemoteReferences(child, `${path2}.${key}`, allowedHosts, seen);
|
|
279
280
|
}
|
|
280
281
|
}
|
|
281
|
-
function visit(value,
|
|
282
|
+
function visit(value, path2, containerKey, allowedHosts, seen) {
|
|
282
283
|
if (!value || typeof value !== "object" || seen.has(value)) return;
|
|
283
284
|
seen.add(value);
|
|
284
285
|
if (Array.isArray(value)) {
|
|
285
286
|
value.forEach(
|
|
286
|
-
(entry, index) => visit(entry, `${
|
|
287
|
+
(entry, index) => visit(entry, `${path2}[${index}]`, containerKey, allowedHosts, seen)
|
|
287
288
|
);
|
|
288
289
|
return;
|
|
289
290
|
}
|
|
@@ -291,7 +292,7 @@ function visit(value, path, containerKey, allowedHosts, seen) {
|
|
|
291
292
|
for (const key of Object.keys(record)) {
|
|
292
293
|
if (DANGEROUS_KEYS.has(key)) {
|
|
293
294
|
throw new UnsafeOutboundSourceError(
|
|
294
|
-
`${
|
|
295
|
+
`${path2}.${key}`,
|
|
295
296
|
"prototype mutation keys are disabled"
|
|
296
297
|
);
|
|
297
298
|
}
|
|
@@ -299,31 +300,31 @@ function visit(value, path, containerKey, allowedHosts, seen) {
|
|
|
299
300
|
const kind = typeof record.kind === "string" ? record.kind : void 0;
|
|
300
301
|
if (kind === "file" && typeof record.path === "string") {
|
|
301
302
|
throw new UnsafeOutboundSourceError(
|
|
302
|
-
`${
|
|
303
|
+
`${path2}.path`,
|
|
303
304
|
"local file sources are disabled for HTTP requests"
|
|
304
305
|
);
|
|
305
306
|
}
|
|
306
307
|
if ((kind === "url" || kind === "variable") && typeof record.url === "string") {
|
|
307
|
-
assertAllowedUrl(record.url, `${
|
|
308
|
+
assertAllowedUrl(record.url, `${path2}.url`, allowedHosts);
|
|
308
309
|
}
|
|
309
310
|
const componentName = typeof record.name === "string" ? record.name.toLowerCase() : void 0;
|
|
310
311
|
const props = isRecord(record.props) ? record.props : void 0;
|
|
311
312
|
if (componentName && props) {
|
|
312
313
|
if (COMPONENT_SOURCE_NAMES.has(componentName) && typeof props.path === "string") {
|
|
313
|
-
assertAllowedUrl(props.path, `${
|
|
314
|
-
assertSafeEncodedImage(props.path, `${
|
|
314
|
+
assertAllowedUrl(props.path, `${path2}.props.path`, allowedHosts);
|
|
315
|
+
assertSafeEncodedImage(props.path, `${path2}.props.path`, allowedHosts);
|
|
315
316
|
}
|
|
316
317
|
if (COMPONENT_SOURCE_NAMES.has(componentName) && typeof props.base64 === "string") {
|
|
317
318
|
assertSafeEncodedImage(
|
|
318
319
|
props.base64,
|
|
319
|
-
`${
|
|
320
|
+
`${path2}.props.base64`,
|
|
320
321
|
allowedHosts
|
|
321
322
|
);
|
|
322
323
|
}
|
|
323
324
|
if ((componentName === "highcharts" || componentName === "visual") && typeof props.serverUrl === "string") {
|
|
324
325
|
assertAllowedUrl(
|
|
325
326
|
props.serverUrl,
|
|
326
|
-
`${
|
|
327
|
+
`${path2}.props.serverUrl`,
|
|
327
328
|
allowedHosts
|
|
328
329
|
);
|
|
329
330
|
}
|
|
@@ -331,30 +332,30 @@ function visit(value, path, containerKey, allowedHosts, seen) {
|
|
|
331
332
|
if (isRecord(props.resources)) {
|
|
332
333
|
assertSafeResources(
|
|
333
334
|
props.resources,
|
|
334
|
-
`${
|
|
335
|
+
`${path2}.props.resources`,
|
|
335
336
|
allowedHosts
|
|
336
337
|
);
|
|
337
338
|
}
|
|
338
339
|
assertNoRemoteReferences(
|
|
339
340
|
props.options,
|
|
340
|
-
`${
|
|
341
|
+
`${path2}.props.options`,
|
|
341
342
|
allowedHosts,
|
|
342
343
|
/* @__PURE__ */ new WeakSet()
|
|
343
344
|
);
|
|
344
345
|
}
|
|
345
346
|
}
|
|
346
347
|
if (containerKey === "image" && typeof record.path === "string") {
|
|
347
|
-
assertAllowedUrl(record.path, `${
|
|
348
|
-
assertSafeEncodedImage(record.path, `${
|
|
348
|
+
assertAllowedUrl(record.path, `${path2}.path`, allowedHosts);
|
|
349
|
+
assertSafeEncodedImage(record.path, `${path2}.path`, allowedHosts);
|
|
349
350
|
}
|
|
350
351
|
if (typeof record.svg === "string") {
|
|
351
|
-
assertSafeSvg(record.svg, `${
|
|
352
|
+
assertSafeSvg(record.svg, `${path2}.svg`, allowedHosts);
|
|
352
353
|
}
|
|
353
354
|
if (containerKey === "resources") {
|
|
354
|
-
assertSafeResources(record,
|
|
355
|
+
assertSafeResources(record, path2, allowedHosts);
|
|
355
356
|
}
|
|
356
357
|
for (const [key, child] of Object.entries(record)) {
|
|
357
|
-
visit(child, `${
|
|
358
|
+
visit(child, `${path2}.${key}`, key, allowedHosts, seen);
|
|
358
359
|
}
|
|
359
360
|
}
|
|
360
361
|
function assertSafeOutboundSources(value, policy, rootPath = "request") {
|
|
@@ -386,7 +387,8 @@ var RasterizeRequestSchema = Type.Object(
|
|
|
386
387
|
presentation: Type.Object({}, { additionalProperties: true }),
|
|
387
388
|
dpi: Type.Optional(
|
|
388
389
|
Type.Number({ minimum: MIN_VISUAL_DPI, maximum: MAX_VISUAL_DPI })
|
|
389
|
-
)
|
|
390
|
+
),
|
|
391
|
+
baseDir: Type.Optional(Type.String())
|
|
390
392
|
},
|
|
391
393
|
{ additionalProperties: false }
|
|
392
394
|
);
|
|
@@ -420,7 +422,18 @@ function registerRasterizeRoute(router, options = {}) {
|
|
|
420
422
|
jsonOnly,
|
|
421
423
|
tbValidator(RasterizeRequestSchema),
|
|
422
424
|
async (c) => {
|
|
423
|
-
const { presentation, dpi } = getValidated(c, "json");
|
|
425
|
+
const { presentation, dpi, baseDir } = getValidated(c, "json");
|
|
426
|
+
let safeBaseDir;
|
|
427
|
+
if (baseDir !== void 0) {
|
|
428
|
+
const resolved = path.resolve(baseDir);
|
|
429
|
+
const cwd = process.cwd();
|
|
430
|
+
if (resolved !== cwd && !resolved.startsWith(cwd + path.sep)) {
|
|
431
|
+
throw new HTTPException2(400, {
|
|
432
|
+
message: "baseDir must be inside the server working directory"
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
safeBaseDir = resolved;
|
|
436
|
+
}
|
|
424
437
|
try {
|
|
425
438
|
if (options.sourcePolicy) {
|
|
426
439
|
assertSafeOutboundSources(
|
|
@@ -431,7 +444,8 @@ function registerRasterizeRoute(router, options = {}) {
|
|
|
431
444
|
}
|
|
432
445
|
const result = await getRasterizer()({
|
|
433
446
|
presentation,
|
|
434
|
-
dpi: clampVisualDpi(dpi ?? DEFAULT_VISUAL_DPI)
|
|
447
|
+
dpi: clampVisualDpi(dpi ?? DEFAULT_VISUAL_DPI),
|
|
448
|
+
baseDir: safeBaseDir
|
|
435
449
|
});
|
|
436
450
|
return c.json(result);
|
|
437
451
|
} catch (error) {
|