tldts-tests 7.1.2 → 7.2.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.
@@ -55,6 +55,7 @@ interface Options {
55
55
  validateHostname?: boolean;
56
56
  mixedInputs?: boolean;
57
57
  detectIp?: boolean;
58
+ detectSpecialUse?: boolean;
58
59
  validHosts?: string[];
59
60
  }
60
61
 
@@ -72,6 +73,7 @@ export default function test(
72
73
  domain: string | null;
73
74
  hostname: string | null;
74
75
  publicSuffix: string | null;
76
+ isSpecialUse?: boolean | null;
75
77
  };
76
78
  },
77
79
  { includePrivate }: { includePrivate: boolean },
@@ -328,6 +330,7 @@ export default function test(
328
330
  isIcann: true,
329
331
  isIp: false,
330
332
  isPrivate: false,
333
+ isSpecialUse: null,
331
334
  publicSuffix: 'com',
332
335
  subdomain: '_0f6879f07aa61fc09d9645cce98b30e3.bsg-1418',
333
336
  });
@@ -339,6 +342,7 @@ export default function test(
339
342
  isIcann: true,
340
343
  isIp: false,
341
344
  isPrivate: false,
345
+ isSpecialUse: null,
342
346
  publicSuffix: 'com',
343
347
  subdomain: '_bsg-1418',
344
348
  });
@@ -350,6 +354,7 @@ export default function test(
350
354
  isIcann: true,
351
355
  isIp: false,
352
356
  isPrivate: false,
357
+ isSpecialUse: null,
353
358
  publicSuffix: 'com',
354
359
  subdomain: '',
355
360
  });
@@ -834,6 +839,7 @@ export default function test(
834
839
  isIcann: null,
835
840
  isIp: true,
836
841
  isPrivate: null,
842
+ isSpecialUse: null,
837
843
  publicSuffix: null,
838
844
  subdomain: null,
839
845
  };
@@ -849,6 +855,7 @@ export default function test(
849
855
  isIcann: false,
850
856
  isIp: false,
851
857
  isPrivate: false,
858
+ isSpecialUse: null,
852
859
  publicSuffix: 'badasdasdada',
853
860
  subdomain: 'foo',
854
861
  }
@@ -859,6 +866,7 @@ export default function test(
859
866
  isIcann: null,
860
867
  isIp: false,
861
868
  isPrivate: null,
869
+ isSpecialUse: null,
862
870
  publicSuffix: 'badasdasdada',
863
871
  subdomain: 'foo',
864
872
  },
@@ -888,6 +896,27 @@ export default function test(
888
896
  ).to.deep.equal(mockResponse('1080::8:800:200c:417a'));
889
897
  });
890
898
 
899
+ it('handles bare, unbracketed ipv6 addresses (issue #2288)', () => {
900
+ // Bare and scheme-prefixed unbracketed IPv6 are kept whole and detected,
901
+ // instead of being dropped or truncated to "2a01:e35:2f22:e3d0:". A
902
+ // documented deviation from `new URL`, which rejects unbracketed IPv6.
903
+ expect(tldts.parse('2a01:e35:2f22:e3d0::1')).to.deep.equal(
904
+ mockResponse('2a01:e35:2f22:e3d0::1'),
905
+ );
906
+ expect(tldts.parse('http://2a01:e35:2f22:e3d0::1')).to.deep.equal(
907
+ mockResponse('2a01:e35:2f22:e3d0::1'),
908
+ );
909
+ expect(tldts.parse('fe80::1')).to.deep.equal(mockResponse('fe80::1'));
910
+ expect(tldts.getHostname('http://2a01:e35:2f22:e3d0::1')).to.equal(
911
+ '2a01:e35:2f22:e3d0::1',
912
+ );
913
+ // A trailing group that looks like a port is part of the address (an
914
+ // unbracketed IPv6 cannot carry a port), so it is kept and still an IP.
915
+ expect(tldts.parse('2a01::1:8080')).to.deep.equal(
916
+ mockResponse('2a01::1:8080'),
917
+ );
918
+ });
919
+
891
920
  it('handles ipv6 address when extractHostname is false', () => {
892
921
  const hostname = '1080::8:800:200C:417A';
893
922
  expect(tldts.parse(hostname, { extractHostname: false })).to.deep.equal({
@@ -897,6 +926,7 @@ export default function test(
897
926
  isIcann: null,
898
927
  isIp: true,
899
928
  isPrivate: null,
929
+ isSpecialUse: null,
900
930
  publicSuffix: null,
901
931
  subdomain: null,
902
932
  });
@@ -911,6 +941,7 @@ export default function test(
911
941
  isIcann: null,
912
942
  isIp: true,
913
943
  isPrivate: null,
944
+ isSpecialUse: null,
914
945
  publicSuffix: null,
915
946
  subdomain: null,
916
947
  });
@@ -934,6 +965,7 @@ export default function test(
934
965
  isIcann: false,
935
966
  isIp: null,
936
967
  isPrivate: false,
968
+ isSpecialUse: null,
937
969
  publicSuffix: '1',
938
970
  subdomain: '192.168',
939
971
  }
@@ -944,6 +976,7 @@ export default function test(
944
976
  isIcann: null,
945
977
  isIp: null,
946
978
  isPrivate: null,
979
+ isSpecialUse: null,
947
980
  publicSuffix: '1',
948
981
  subdomain: '192.168',
949
982
  },
@@ -951,6 +984,73 @@ export default function test(
951
984
  });
952
985
  });
953
986
 
987
+ describe('special-use domains (IANA registry)', () => {
988
+ const special = (url: string) =>
989
+ tldts.parse(url, { detectSpecialUse: true }).isSpecialUse;
990
+
991
+ it('flags special-use names and their sub-domains', () => {
992
+ for (const hostname of [
993
+ // RFC 6761
994
+ 'test',
995
+ 'a.b.test',
996
+ 'localhost',
997
+ 'foo.localhost',
998
+ 'invalid',
999
+ 'something.invalid',
1000
+ 'example',
1001
+ 'sub.example',
1002
+ 'example.com',
1003
+ 'example.net',
1004
+ 'www.example.org',
1005
+ // RFC 6762 / 7686 / 9476
1006
+ 'local',
1007
+ 'printer.local',
1008
+ 'onion',
1009
+ 'facebookcorewwwwi.onion',
1010
+ 'alt',
1011
+ 'x.alt',
1012
+ // named .arpa entries (RFC 8375 / 8880 / 9462 / 9665 / 9031 / 9965)
1013
+ 'home.arpa',
1014
+ 'router.home.arpa',
1015
+ 'ipv4only.arpa',
1016
+ 'resolver.arpa',
1017
+ 'service.arpa',
1018
+ '6tisch.arpa',
1019
+ 'eap.arpa',
1020
+ // normalization contract: extractHostname lower-cases the host and
1021
+ // strips a trailing dot before isSpecialUse sees it (is-special-use.ts).
1022
+ 'LocalHost',
1023
+ 'a.b.test.',
1024
+ ]) {
1025
+ expect(special(hostname), hostname).to.equal(true);
1026
+ }
1027
+ });
1028
+
1029
+ it('does not flag ordinary domains, partial matches, or excluded entries', () => {
1030
+ for (const hostname of [
1031
+ 'google.com',
1032
+ 'foo.bar.com',
1033
+ 'example.fr', // not a reserved name
1034
+ 'latest', // label boundary vs `test`
1035
+ 'notlocalhost', // label boundary vs `localhost`
1036
+ 'badexample.com', // label boundary vs `example.com`
1037
+ 'arpa', // only specific .arpa names are reserved
1038
+ 'foo.arpa',
1039
+ 'eap-noob.arpa', // deprecated registry entry, intentionally excluded
1040
+ ]) {
1041
+ expect(special(hostname), hostname).to.equal(false);
1042
+ }
1043
+ });
1044
+
1045
+ it('is null unless detectSpecialUse is enabled', () => {
1046
+ expect(tldts.parse('localhost').isSpecialUse).to.equal(null);
1047
+ expect(
1048
+ tldts.parse('localhost', { detectSpecialUse: false }).isSpecialUse,
1049
+ ).to.equal(null);
1050
+ expect(tldts.parse('google.com').isSpecialUse).to.equal(null);
1051
+ });
1052
+ });
1053
+
954
1054
  describe('validHosts', () => {
955
1055
  describe('non-empty array', () => {
956
1056
  const options: Options = {
@@ -1244,6 +1344,15 @@ export default function test(
1244
1344
  );
1245
1345
  });
1246
1346
 
1347
+ it('accepts unbracketed IPv6 (WHATWG/`new URL` rejects)', () => {
1348
+ expect(tldts.getHostname('2a01:e35:2f22:e3d0::1')).to.equal(
1349
+ '2a01:e35:2f22:e3d0::1',
1350
+ );
1351
+ expect(tldts.getHostname('http://2a01:e35:2f22:e3d0::1')).to.equal(
1352
+ '2a01:e35:2f22:e3d0::1',
1353
+ );
1354
+ });
1355
+
1247
1356
  it('strips trailing dots', () => {
1248
1357
  expect(tldts.getHostname('http://example.com./')).to.equal(
1249
1358
  'example.com',