@pdfme/common 6.2.4-dev.9 → 6.2.5-dev.1

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/helper.d.ts CHANGED
@@ -21,6 +21,10 @@ export declare const migrateTemplate: (template: Template) => void;
21
21
  export declare const getInputFromTemplate: (template: Template) => {
22
22
  [key: string]: string;
23
23
  }[];
24
+ /**
25
+ * Checks the URL's literal host only. DNS names that resolve to internal addresses and
26
+ * redirects are not covered; validate untrusted templates server-side if that matters.
27
+ */
24
28
  export declare const isUrlSafeToFetch: (urlString: string) => boolean;
25
29
  export type PdfLinkAnnotationRect = {
26
30
  x: number;
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import { Buffer } from "buffer";
3
3
  import { PDFName } from "@pdfme/pdf-lib";
4
4
  import * as acorn from "acorn";
5
5
  //#region src/version.ts
6
- var PDFME_VERSION = "6.2.4";
6
+ var PDFME_VERSION = "6.2.5";
7
7
  //#endregion
8
8
  //#region src/pageSize.ts
9
9
  var PAGE_SIZE_PRESETS = {
@@ -432,6 +432,123 @@ var getInputFromTemplate = (template) => {
432
432
  });
433
433
  return [input];
434
434
  };
435
+ var parseIpv4 = (host) => {
436
+ const match = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(host);
437
+ if (!match) return null;
438
+ const octets = match.slice(1).map(Number);
439
+ return octets.every((octet) => octet <= 255) ? octets : null;
440
+ };
441
+ var parseIpv6 = (host) => {
442
+ let address = host.toLowerCase();
443
+ const lastColon = address.lastIndexOf(":");
444
+ const tail = address.slice(lastColon + 1);
445
+ if (tail.includes(".")) {
446
+ const octets = parseIpv4(tail);
447
+ if (!octets) return null;
448
+ const high = (octets[0] << 8 | octets[1]).toString(16);
449
+ const low = (octets[2] << 8 | octets[3]).toString(16);
450
+ address = `${address.slice(0, lastColon + 1)}${high}:${low}`;
451
+ }
452
+ const halves = address.split("::");
453
+ if (halves.length > 2) return null;
454
+ const toGroups = (part) => part === "" ? [] : part.split(":");
455
+ const head = toGroups(halves[0]);
456
+ let groups = head;
457
+ if (halves.length === 2) {
458
+ const rest = toGroups(halves[1]);
459
+ const missing = 8 - head.length - rest.length;
460
+ if (missing < 1) return null;
461
+ groups = [
462
+ ...head,
463
+ ...Array(missing).fill("0"),
464
+ ...rest
465
+ ];
466
+ }
467
+ if (groups.length !== 8 || !groups.every((group) => /^[0-9a-f]{1,4}$/.test(group))) return null;
468
+ return groups.map((group) => parseInt(group, 16));
469
+ };
470
+ var ipv4ToInt = (octets) => (octets[0] << 24 | octets[1] << 16 | octets[2] << 8 | octets[3]) >>> 0;
471
+ var toIpv4Range = (cidr) => {
472
+ const [address, prefix] = cidr.split("/");
473
+ const prefixLength = Number(prefix);
474
+ const mask = prefixLength === 0 ? 0 : -1 << 32 - prefixLength >>> 0;
475
+ return {
476
+ base: (ipv4ToInt(parseIpv4(address)) & mask) >>> 0,
477
+ mask
478
+ };
479
+ };
480
+ var toIpv6Range = (cidr) => {
481
+ const [address, prefix] = cidr.split("/");
482
+ return {
483
+ base: parseIpv6(address),
484
+ prefixLength: Number(prefix)
485
+ };
486
+ };
487
+ var NON_PUBLIC_IPV4_RANGES = [
488
+ "0.0.0.0/8",
489
+ "10.0.0.0/8",
490
+ "100.64.0.0/10",
491
+ "127.0.0.0/8",
492
+ "169.254.0.0/16",
493
+ "172.16.0.0/12",
494
+ "192.0.0.0/24",
495
+ "192.0.2.0/24",
496
+ "192.88.99.0/24",
497
+ "192.168.0.0/16",
498
+ "198.18.0.0/15",
499
+ "198.51.100.0/24",
500
+ "203.0.113.0/24",
501
+ "224.0.0.0/4",
502
+ "240.0.0.0/4"
503
+ ].map(toIpv4Range);
504
+ var NON_PUBLIC_IPV6_RANGES = [
505
+ "::/96",
506
+ "100::/64",
507
+ "2001::/32",
508
+ "2001:db8::/32",
509
+ "64:ff9b:1::/48",
510
+ "fc00::/7",
511
+ "fe80::/10",
512
+ "fec0::/10",
513
+ "ff00::/8"
514
+ ].map(toIpv6Range);
515
+ var LOOPBACK_HOSTNAMES = /* @__PURE__ */ new Set([
516
+ "localhost",
517
+ "localhost.localdomain",
518
+ "ip6-localhost",
519
+ "ip6-loopback"
520
+ ]);
521
+ var IPV4_MAPPED_RANGE = toIpv6Range("::ffff:0:0/96");
522
+ var NAT64_WELL_KNOWN_RANGE = toIpv6Range("64:ff9b::/96");
523
+ var SIX_TO_FOUR_RANGE = toIpv6Range("2002::/16");
524
+ var isPublicIpv4 = (octets) => {
525
+ const value = ipv4ToInt(octets);
526
+ return NON_PUBLIC_IPV4_RANGES.every(({ base, mask }) => (value & mask) >>> 0 !== base);
527
+ };
528
+ var isInIpv6Range = (groups, { base, prefixLength }) => {
529
+ for (let i = 0; i < 8; i++) {
530
+ const bits = Math.min(16, Math.max(0, prefixLength - i * 16));
531
+ if (bits === 0) return true;
532
+ const mask = 65535 << 16 - bits & 65535;
533
+ if ((groups[i] & mask) !== (base[i] & mask)) return false;
534
+ }
535
+ return true;
536
+ };
537
+ var ipv4FromGroups = (high, low) => [
538
+ high >> 8,
539
+ high & 255,
540
+ low >> 8,
541
+ low & 255
542
+ ];
543
+ var isPublicIpv6 = (groups) => {
544
+ if (isInIpv6Range(groups, IPV4_MAPPED_RANGE) || isInIpv6Range(groups, NAT64_WELL_KNOWN_RANGE)) return isPublicIpv4(ipv4FromGroups(groups[6], groups[7]));
545
+ if (isInIpv6Range(groups, SIX_TO_FOUR_RANGE)) return isPublicIpv4(ipv4FromGroups(groups[1], groups[2]));
546
+ return NON_PUBLIC_IPV6_RANGES.every((range) => !isInIpv6Range(groups, range));
547
+ };
548
+ /**
549
+ * Checks the URL's literal host only. DNS names that resolve to internal addresses and
550
+ * redirects are not covered; validate untrusted templates server-side if that matters.
551
+ */
435
552
  var isUrlSafeToFetch = (urlString) => {
436
553
  let parsed;
437
554
  try {
@@ -441,31 +558,15 @@ var isUrlSafeToFetch = (urlString) => {
441
558
  }
442
559
  if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return false;
443
560
  const hostname = parsed.hostname.toLowerCase();
444
- if (hostname === "localhost" || hostname === "0.0.0.0" || hostname === "[::1]" || hostname === "::1") return false;
445
- const bare = hostname.replace(/^\[|\]$/g, "");
446
- if (/^fe80:/i.test(bare)) return false;
447
- if (/^f[cd]/i.test(bare)) return false;
448
- const ipv4MappedMatch = bare.match(/^::ffff:(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/i);
449
- if (ipv4MappedMatch) {
450
- const a = Number(ipv4MappedMatch[1]);
451
- const b = Number(ipv4MappedMatch[2]);
452
- if (a === 0 || a === 10 || a === 127) return false;
453
- if (a === 169 && b === 254) return false;
454
- if (a === 172 && b >= 16 && b <= 31) return false;
455
- if (a === 192 && b === 168) return false;
561
+ if (hostname.startsWith("[") && hostname.endsWith("]")) {
562
+ const groups = parseIpv6(hostname.slice(1, -1));
563
+ return groups !== null && isPublicIpv6(groups);
456
564
  }
457
- const ipv4Match = hostname.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
458
- if (ipv4Match) {
459
- const a = Number(ipv4Match[1]);
460
- const b = Number(ipv4Match[2]);
461
- if (a === 0) return false;
462
- if (a === 10) return false;
463
- if (a === 127) return false;
464
- if (a === 169 && b === 254) return false;
465
- if (a === 172 && b >= 16 && b <= 31) return false;
466
- if (a === 192 && b === 168) return false;
467
- }
468
- return true;
565
+ const host = hostname.replace(/\.+$/, "");
566
+ if (!host) return false;
567
+ const ipv4 = parseIpv4(host);
568
+ if (ipv4) return isPublicIpv4(ipv4);
569
+ return !LOOPBACK_HOSTNAMES.has(host) && !host.endsWith(".localhost");
469
570
  };
470
571
  var SAFE_LINK_URI_PROTOCOLS = /* @__PURE__ */ new Set([
471
572
  "http:",