Repository: validatorjs/validator.js
Pull request #1730 (2021-09-20 11:38:43)

fix(isMagnetURI): update validation regex
This PR updates the `isMagnetURI` validator regex:

- Fix ReDOS in old regex (thanks to @yetingli for discovering the vulnerability and @JamieSlome for reporting it)
- Validate only exact xt topics (btih,sha1,...) based on [this list](https://en.wikipedia.org/wiki/Magnet_URI_scheme#xt_exact_topic)
- Validate only 32 or 40 hashes (Old regex was validating length between 32 and 40 even if only 32 (md5 and sha1) and 40 (btih, ed2k,...) character hashes are valid )
- Make tr and dn parameters optional (Magnet URI definition doesn't specify if other parameters than `xt` are required
- Allow passing multiple `xt` urn using the standard `xt.1` and `xt.2`,... (URI is valid even if only `xt.1` is passed) 
- Allow any other parameter (protocol allow passing non standard parameters)
- Use placeholder hashes in tests 
- Add new tests

All the changes are based on the Magnet URI scheme definition [here](https://en.wikipedia.org/wiki/Magnet_URI_scheme) , there is no IETF RFC concerning magnet URI.
## Checklist

- [x] PR contains only changes related; no stray files, etc.
- [x] Tests written (where applicable)


codecov[bot]: # [Codecov](https://codecov.io/gh/validatorjs/validator.js/pull/1730?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=validatorjs) Report
> Merging [#1730](https://codecov.io/gh/validatorjs/validator.js/pull/1730?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=validatorjs) (e263b32) into [master](https://codecov.io/gh/validatorjs/validator.js/commit/8c4b3b35c3bd36dc3983aadb045422847154451b?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=validatorjs) (8c4b3b3) will **not change** coverage.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/validatorjs/validator.js/pull/1730/graphs/tree.svg?width=650&height=150&src=pr&token=YzR3kbN1m2&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=validatorjs)](https://codecov.io/gh/validatorjs/validator.js/pull/1730?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=validatorjs)

```diff
@@            Coverage Diff            @@
##            master     #1730   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          101       101           
  Lines         2005      2005           
  Branches       452       452           
=========================================
  Hits          2005      2005           
```


| [Impacted Files](https://codecov.io/gh/validatorjs/validator.js/pull/1730?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=validatorjs) | Coverage Δ | |
|---|---|---|
| [src/lib/isMagnetURI.js](https://codecov.io/gh/validatorjs/validator.js/pull/1730/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=validatorjs#diff-c3JjL2xpYi9pc01hZ25ldFVSSS5qcw==) | `100.00% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/validatorjs/validator.js/pull/1730?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=validatorjs).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=validatorjs)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/validatorjs/validator.js/pull/1730?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=validatorjs). Last update [8c4b3b3...e263b32](https://codecov.io/gh/validatorjs/validator.js/pull/1730?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=validatorjs). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=validatorjs).


Patch:
diff --git a/src/lib/isBIC.js b/src/lib/isBIC.js
index 240bfe1..b5576b2 100644
--- a/src/lib/isBIC.js
+++ b/src/lib/isBIC.js
@@ -9,7 +9,7 @@ export default function isBIC(str) {
 
   // toUpperCase() should be removed when a new major version goes out that changes
   // the regex to [A-Z] (per the spec).
-  if (CountryCodes.indexOf(str.slice(4, 6).toUpperCase()) < 0) {
+  if (!CountryCodes.has(str.slice(4, 6).toUpperCase())) {
     return false;
   }
 
diff --git a/src/lib/isISO31661Alpha2.js b/src/lib/isISO31661Alpha2.js
index e91ae87..e67bb1e 100644
--- a/src/lib/isISO31661Alpha2.js
+++ b/src/lib/isISO31661Alpha2.js
@@ -1,7 +1,7 @@
 import assertString from './util/assertString';
 
 // from https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
-const validISO31661Alpha2CountriesCodes = [
+const validISO31661Alpha2CountriesCodes = new Set([
   'AD', 'AE', 'AF', 'AG', 'AI', 'AL', 'AM', 'AO', 'AQ', 'AR', 'AS', 'AT', 'AU', 'AW', 'AX', 'AZ',
   'BA', 'BB', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ', 'BL', 'BM', 'BN', 'BO', 'BQ', 'BR', 'BS', 'BT', 'BV', 'BW', 'BY', 'BZ',
   'CA', 'CC', 'CD', 'CF', 'CG', 'CH', 'CI', 'CK', 'CL', 'CM', 'CN', 'CO', 'CR', 'CU', 'CV', 'CW', 'CX', 'CY', 'CZ',
@@ -27,11 +27,11 @@ const validISO31661Alpha2CountriesCodes = [
   'WF', 'WS',
   'YE', 'YT',
   'ZA', 'ZM', 'ZW',
-];
+]);
 
 export default function isISO31661Alpha2(str) {
   assertString(str);
-  return validISO31661Alpha2CountriesCodes.indexOf(str.toUpperCase()) >= 0;
+  return validISO31661Alpha2CountriesCodes.has(str.toUpperCase());
 }
 
 export const CountryCodes = validISO31661Alpha2CountriesCodes;
diff --git a/src/lib/isMagnetURI.js b/src/lib/isMagnetURI.js
index 54a3d66..45b5c8e 100644
--- a/src/lib/isMagnetURI.js
+++ b/src/lib/isMagnetURI.js
@@ -1,6 +1,6 @@
 import assertString from './util/assertString';
 
-const magnetURI = /^magnet:\?xt=urn:[a-z0-9]+:[a-z0-9]{32,40}&dn=.+&tr=.+$/i;
+const magnetURI = /^magnet:\?xt(?:\.1)?=urn:(?:aich|bitprint|btih|ed2k|ed2khash|kzhash|md5|sha1|tree:tiger):[a-z0-9]{32}(?:[a-z0-9]{8})?($|&)/i;
 
 export default function isMagnetURI(url) {
   assertString(url);


Test patch:
diff --git a/test/validators.js b/test/validators.js
index 6bb6072..f60391a 100644
--- a/test/validators.js
+++ b/test/validators.js
@@ -9297,27 +9297,25 @@ describe('Validators', () => {
     test({
       validator: 'isMagnetURI',
       valid: [
-        'magnet:?xt=urn:btih:06E2A9683BF4DA92C73A661AC56F0ECC9C63C5B4&dn=helloword2000&tr=udp://helloworld:1337/announce',
-        'magnet:?xt=urn:btih:3E30322D5BFC7444B7B1D8DD42404B75D0531DFB&dn=world&tr=udp://world.com:1337',
-        'magnet:?xt=urn:btih:4ODKSDJBVMSDSNJVBCBFYFBKNRU875DW8D97DWC6&dn=helloworld&tr=udp://helloworld.com:1337',
-        'magnet:?xt=urn:btih:1GSHJVBDVDVJFYEHKFHEFIO8573898434JBFEGHD&dn=foo&tr=udp://foo.com:1337',
-        'magnet:?xt=urn:btih:MCJDCYUFHEUD6E2752T7UJNEKHSUGEJFGTFHVBJS&dn=bar&tr=udp://bar.com:1337',
-        'magnet:?xt=urn:btih:LAKDHWDHEBFRFVUFJENBYYTEUY837562JH2GEFYH&dn=foobar&tr=udp://foobar.com:1337',
-        'magnet:?xt=urn:btih:MKCJBHCBJDCU725TGEB3Y6RE8EJ2U267UNJFGUID&dn=test&tr=udp://test.com:1337',
-        'magnet:?xt=urn:btih:UHWY2892JNEJ2GTEYOMDNU67E8ICGICYE92JDUGH&dn=baz&tr=udp://baz.com:1337',
-        'magnet:?xt=urn:btih:HS263FG8U3GFIDHWD7829BYFCIXB78XIHG7CWCUG&dn=foz&tr=udp://foz.com:1337',
-      ],
-      invalid: [
-        '',
-        ':?xt=urn:btih:06E2A9683BF4DA92C73A661AC56F0ECC9C63C5B4&dn=helloword2000&tr=udp://helloworld:1337/announce',
-        'magnett:?xt=urn:btih:3E30322D5BFC7444B7B1D8DD42404B75D0531DFB&dn=world&tr=udp://world.com:1337',
-        'xt=urn:btih:4ODKSDJBVMSDSNJVBCBFYFBKNRU875DW8D97DWC6&dn=helloworld&tr=udp://helloworld.com:1337',
-        'magneta:?xt=urn:btih:1GSHJVBDVDVJFYEHKFHEFIO8573898434JBFEGHD&dn=foo&tr=udp://foo.com:1337',
-        'magnet:?xt=uarn:btih:MCJDCYUFHEUD6E2752T7UJNEKHSUGEJFGTFHVBJS&dn=bar&tr=udp://bar.com:1337',
-        'magnet:?xt=urn:btihz&dn=foobar&tr=udp://foobar.com:1337',
-        'magnet:?xat=urn:btih:MKCJBHCBJDCU725TGEB3Y6RE8EJ2U267UNJFGUID&dn=test&tr=udp://test.com:1337',
-        'magnet::?xt=urn:btih:UHWY2892JNEJ2GTEYOMDNU67E8ICGICYE92JDUGH&dn=baz&tr=udp://baz.com:1337',
-        'magnet:?xt:btih:HS263FG8U3GFIDHWD7829BYFCIXB78XIHG7CWCUG&dn=foz&tr=udp://foz.com:1337',
+        'magnet:?xt.1=urn:sha1:ABCDEFGHIJKLMNOPQRSTUVWXYZ123456&xt.2=urn:sha1:ABCDEFGHIJKLMNOPQRSTUVWXYZ123456',
+        'magnet:?xt=urn:btih:ABCDEFGHIJKLMNOPQRSTUVWXYZ12345678901234&dn=helloword2000&tr=udp://helloworld:1337/announce',
+        'magnet:?xt=urn:btih:ABCDEFGHIJKLMNOPQRSTUVWXYZ12345678901234&dn=foo',
+        'magnet:?xt=urn:btih:ABCDEFGHIJKLMNOPQRSTUVWXYZ12345678901234&dn=&tr=&nonexisting=hello world',
+        'magnet:?xt=urn:md5:ABCDEFGHIJKLMNOPQRSTUVWXYZ123456',
+        'magnet:?xt=urn:tree:tiger:ABCDEFGHIJKLMNOPQRSTUVWXYZ123456',
+        'magnet:?xt=urn:ed2k:ABCDEFGHIJKLMNOPQRSTUVWXYZ12345678901234',
+      ],
+      invalid: [
+        ':?xt=urn:btih:ABCDEFGHIJKLMNOPQRSTUVWXYZ12345678901234',
+        'xt=urn:btih:ABCDEFGHIJKLMNOPQRSTUVWXYZ12345678901234',
+        'magneta:?xt=urn:btih:ABCDEFGHIJKLMNOPQRSTUVWXYZ12345678901234',
+        'magnet:?xt=uarn:btih:ABCDEFGHIJKLMNOPQRSTUVWXYZ12345678901234',
+        'magnet:?xt=urn:btihz',
+        'magnet::?xt=urn:btih:UHWY2892JNEJ2GTEYOMDNU67E8ICGICYE92JDUGH',
+        'magnet:?xt:btih:ABCDEFGHIJKLMNOPQRSTUVWXYZ',
+        'magnet:?xt:urn:nonexisting:ABCDEFGHIJKLMNOPQRSTUVWXYZ12345678901234',
+        'magnet:?xt.2=urn:btih:ABCDEFGHIJKLMNOPQRSTUVWXYZ12345678901234',
+        'magnet:?xt=urn:ed2k:ABCDEFGHIJKLMNOPQRSTUVWXYZ12345678901234567890123456789ABCD',
       ],
     });
     /* eslint-enable max-len */