tldts-tests 7.0.31 → 7.1.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.
@@ -147,6 +147,11 @@ export default function test(
147
147
  'while',
148
148
  'with',
149
149
  'yield',
150
+ // Object.prototype-member labels (lowercase, so they survive hostname
151
+ // lowercasing): must be treated as ordinary labels, never resolve
152
+ // against the prototype chain during trie traversal.
153
+ 'constructor',
154
+ '__proto__',
150
155
  ].forEach((keyword) => {
151
156
  it(keyword, () => {
152
157
  expect(tldts.getDomain(`https://${keyword}.com`)).to.equal(
@@ -305,6 +310,16 @@ export default function test(
305
310
  });
306
311
  });
307
312
 
313
+ // Labels ending with '_' (e.g. SPF / DNS-TXT records). Allowed by DNS (RFC 2181 §11)
314
+ // and WHATWG URL ('_' is not a forbidden host code point); only the RFC 1035 LDH
315
+ // "preferred syntax" forbids it, which tldts intentionally does not enforce.
316
+ it('should accept labels ending with an underscore', () => {
317
+ expect(tldts.getDomain('spf_.google.com')).to.equal('google.com'); // reported bug
318
+ expect(tldts.getHostname('spf_.google.com')).to.equal('spf_.google.com'); // full hostname preserved
319
+ expect(tldts.getDomain('_spf.google.com')).to.equal('google.com'); // leading '_' (reference case)
320
+ expect(tldts.getDomain('s_pf.google.com')).to.equal('google.com'); // middle '_' (reference case)
321
+ });
322
+
308
323
  // @see https://github.com/oncletom/tld.js/issues/53
309
324
  it('should correctly extract domain from paths including "@" in the path', () => {
310
325
  const domain = tldts.getDomain(
@@ -653,9 +668,10 @@ export default function test(
653
668
  it('should be consistent with parse method', () => {
654
669
  const url = '___id___.c.mystat-in.net';
655
670
 
656
- // With validation ('_' is forbidden at the start of a label)
657
- expect(tldts.parse(url).hostname).to.equal(null);
658
- expect(tldts.getHostname(url)).to.equal(null);
671
+ // Underscores (incl. trailing) are accepted — DNS allows any octet (RFC 2181 §11),
672
+ // WHATWG URL does not forbid '_'. parse() and getHostname() must agree.
673
+ expect(tldts.parse(url).hostname).to.equal(url);
674
+ expect(tldts.getHostname(url)).to.equal(url);
659
675
 
660
676
  // Without validation
661
677
  expect(tldts.parse(url, { validateHostname: false }).hostname).to.equal(
@@ -1032,4 +1048,114 @@ export default function test(
1032
1048
  }
1033
1049
  });
1034
1050
  });
1051
+
1052
+ describe('options handling (regression for shared default-options reuse)', () => {
1053
+ // Calling a method with no options must behave identically to passing `{}`.
1054
+ // The no-options path now returns a shared cached defaults object instead of
1055
+ // allocating one per call; this guards that the shared object stays read-only.
1056
+ it('omitting options equals passing {} for every public method', () => {
1057
+ const url = 'https://sub.example.co.uk/path?q=1';
1058
+ expect(tldts.parse(url)).to.deep.equal(tldts.parse(url, {}));
1059
+ expect(tldts.getHostname(url)).to.equal(tldts.getHostname(url, {}));
1060
+ expect(tldts.getDomain(url)).to.equal(tldts.getDomain(url, {}));
1061
+ expect(tldts.getPublicSuffix(url)).to.equal(
1062
+ tldts.getPublicSuffix(url, {}),
1063
+ );
1064
+ expect(tldts.getSubdomain(url)).to.equal(tldts.getSubdomain(url, {}));
1065
+ expect(tldts.getDomainWithoutSuffix(url)).to.equal(
1066
+ tldts.getDomainWithoutSuffix(url, {}),
1067
+ );
1068
+ });
1069
+
1070
+ // A prior call with custom options must not corrupt the shared defaults that
1071
+ // a subsequent no-options call relies on (co.uk is ICANN in all packages).
1072
+ it('a custom-options call does not corrupt later default-options results', () => {
1073
+ const url = 'https://sub.example.co.uk/';
1074
+ const before = tldts.getDomain(url); // default options
1075
+ // interleave calls with assorted non-default options
1076
+ tldts.getDomain(url, {
1077
+ allowPrivateDomains: true,
1078
+ validateHostname: false,
1079
+ detectIp: false,
1080
+ });
1081
+ tldts.getDomain('https://other.example.com/', { mixedInputs: false });
1082
+ const after = tldts.getDomain(url); // default options again
1083
+ expect(after).to.equal(before);
1084
+ expect(after).to.equal('example.co.uk');
1085
+ });
1086
+ });
1087
+
1088
+ describe('public-suffix reconstruction (single-slice offset)', () => {
1089
+ // Rules match across multiple labels: the suffix is rebuilt via a single
1090
+ // hostname.slice at the computed offset (was parts.slice(i).join('.')).
1091
+ it('returns a multi-label rules suffix unchanged', () => {
1092
+ expect(tldts.getPublicSuffix('not.evil.co.uk')).to.equal('co.uk');
1093
+ expect(tldts.getDomain('a.b.c.example.co.uk')).to.equal('example.co.uk');
1094
+ });
1095
+
1096
+ // Exception match: suffix offset uses index+1 (the exception removes its
1097
+ // own left-most label, e.g. !www.ck -> suffix 'ck').
1098
+ it('returns an exception suffix unchanged', () => {
1099
+ expect(tldts.getPublicSuffix('www.ck')).to.equal('ck');
1100
+ });
1101
+ });
1102
+
1103
+ describe('hostname validation dedupe', () => {
1104
+ // Already-valid lowercase hostname: extractHostname returns the SAME string
1105
+ // reference, so the post-extraction validation is skipped — result must
1106
+ // still be that hostname.
1107
+ it('keeps an already-valid hostname', () => {
1108
+ expect(tldts.getHostname('example.co.uk')).to.equal('example.co.uk');
1109
+ expect(tldts.getHostname('sub.example.com')).to.equal('sub.example.com');
1110
+ });
1111
+
1112
+ // Trailing dot is trimmed by extractHostname -> returned string differs from
1113
+ // the input -> the skip guard must NOT fire -> trimmed hostname is validated.
1114
+ it('still validates a trailing-dot hostname (guard does not fire)', () => {
1115
+ expect(tldts.getHostname('miam.miam.google.com.')).to.equal(
1116
+ 'miam.miam.google.com',
1117
+ );
1118
+ });
1119
+
1120
+ // Uppercase input is not a "valid hostname" to the validator, so the full
1121
+ // extraction + lowercasing path runs and the guard does not fire.
1122
+ it('lowercases an uppercase hostname', () => {
1123
+ expect(tldts.getHostname('EXAMPLE.COM')).to.equal('example.com');
1124
+ });
1125
+
1126
+ // An invalid hostname must still be rejected: the guard only skips the
1127
+ // re-scan when the input was ALREADY valid, so it can never keep an invalid one.
1128
+ it('still rejects an invalid hostname', () => {
1129
+ expect(tldts.getHostname('foo-.com')).to.equal(null);
1130
+ });
1131
+ });
1132
+
1133
+ describe('wildcard suffix reconstruction', () => {
1134
+ // *.sch.uk where the matched suffix spans every label of the hostname:
1135
+ // in the packed-hash impl this takes the backward-scan fallback branch
1136
+ // (matchLabels === number of hashed labels). Must return the full suffix.
1137
+ it('returns a wildcard suffix that spans the whole hostname', () => {
1138
+ expect(tldts.getPublicSuffix('foo.sch.uk')).to.equal('foo.sch.uk');
1139
+ });
1140
+
1141
+ // *.sch.uk with an extra leading label (non-fallback wildcard branch).
1142
+ it('returns a wildcard suffix with a leading subdomain present', () => {
1143
+ expect(tldts.getPublicSuffix('pupils.school.sch.uk')).to.equal(
1144
+ 'school.sch.uk',
1145
+ );
1146
+ });
1147
+ });
1148
+
1149
+ describe('prototype-pollution-safe trie traversal', () => {
1150
+ // A label equal to an Object.prototype member, sitting where the trie has a
1151
+ // '*' wildcard child (*.ck), must match the wildcard — NOT resolve to
1152
+ // Object.prototype.constructor / the __proto__ accessor. Guards the
1153
+ // hasOwnProperty check (or, post-Stage-2, the substring-keyed lookup).
1154
+ it('treats constructor/__proto__ labels as ordinary labels under a wildcard', () => {
1155
+ expect(tldts.getPublicSuffix('b.constructor.ck')).to.equal(
1156
+ 'constructor.ck',
1157
+ );
1158
+ expect(tldts.getPublicSuffix('b.__proto__.ck')).to.equal('__proto__.ck');
1159
+ });
1160
+ });
1035
1161
  }