From 8df346d998498b3ce899e49e88aa9bdc1659a50b Mon Sep 17 00:00:00 2001 From: Utpal Sarkar Date: Tue, 21 Feb 2023 17:30:12 +0600 Subject: [PATCH 1/8] added mailto URI validator method --- src/lib/isMailtoURI.js | 70 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 src/lib/isMailtoURI.js diff --git a/src/lib/isMailtoURI.js b/src/lib/isMailtoURI.js new file mode 100644 index 000000000..0bf9b9cfd --- /dev/null +++ b/src/lib/isMailtoURI.js @@ -0,0 +1,70 @@ +import trim from './trim'; +import isEmail from './isEmail'; +import assertString from './util/assertString'; + +function parseMailtoQueryString(queryString) { + const allowedParams = new Set(['subject', 'body', 'cc', 'bcc']), + query = { cc: '', bcc: '' }; + let isParseFailed = false; + + const queryParams = queryString.split('&'); + + if (queryParams.length > 4) { + return false; + } + + for (const q of queryParams) { + const [key, value] = q.split('='); + + if (!key) { + // eslint-disable-next-line no-continue + continue; + } + + // checked for invalid and duplicated query params + if (!allowedParams.has(key)) { + isParseFailed = true; + break; + } + + if (value && (key === 'cc' || key === 'bcc')) { + query[key] = value; + } + + allowedParams.delete(key); + } + + return isParseFailed ? false : query; +} + +export default function isMailtoURI(url, options) { + assertString(url); + + if (url.indexOf('mailto:') !== 0) { + return false; + } + + const [to = '', queryString = ''] = url.replace('mailto:', '').split('?'); + + const query = parseMailtoQueryString(queryString); + + if (!query) { + return false; + } + + return `${to},${query.cc},${query.bcc}` + .split(',') + .reduce((isValid, email) => { + if (!isValid) { + return isValid; + } + + email = trim(email, ' '); + + if (email) { + isValid = isEmail(email, options); + } + + return isValid; + }, true); +} From 057573f9488ae946018d7973b5f9ff4aa942a9db Mon Sep 17 00:00:00 2001 From: Utpal Sarkar Date: Tue, 21 Feb 2023 17:30:38 +0600 Subject: [PATCH 2/8] imported the isMailtoURI method --- src/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/index.js b/src/index.js index 07cbbefbe..fd97dc3ac 100644 --- a/src/index.js +++ b/src/index.js @@ -101,6 +101,7 @@ import isBase58 from './lib/isBase58'; import isBase64 from './lib/isBase64'; import isDataURI from './lib/isDataURI'; import isMagnetURI from './lib/isMagnetURI'; +import isMailtoURI from './lib/isMailtoURI'; import isMimeType from './lib/isMimeType'; @@ -213,6 +214,7 @@ const validator = { isBase64, isDataURI, isMagnetURI, + isMailtoURI, isMimeType, isLatLong, ltrim, From ae0cdfe5be72d4ca400bd798210d1d6105dc9908 Mon Sep 17 00:00:00 2001 From: Utpal Sarkar Date: Tue, 21 Feb 2023 17:31:03 +0600 Subject: [PATCH 3/8] added tests for the isMailtoURI method --- test/validators.test.js | 48 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/test/validators.test.js b/test/validators.test.js index 239f172ca..c45520b39 100644 --- a/test/validators.test.js +++ b/test/validators.test.js @@ -14179,4 +14179,52 @@ describe('Validators', () => { ], }); }); + it('should validate mailto URI', () => { + test({ + validator: 'isMailtoURI', + valid: [ + 'mailto:?subject=something&cc=valid@mail.com', + 'mailto:?subject=something&cc=valid@mail.com,another@mail.com,', + 'mailto:?subject=something&bcc=valid@mail.com', + 'mailto:?subject=something&bcc=valid@mail.com,another@mail.com', + 'mailto:?bcc=valid@mail.com,another@mail.com', + 'mailto:?cc=valid@mail.com,another@mail.com', + 'mailto:?cc=valid@mail.com', + 'mailto:?bcc=valid@mail.com', + 'mailto:?subject=something&body=something else', + 'mailto:?subject=something&body=something else&cc=hello@mail.com,another@mail.com', + 'mailto:?subject=something&body=something else&bcc=hello@mail.com,another@mail.com', + 'mailto:?subject=something&body=something else&cc=something@mail.com&bcc=hello@mail.com,another@mail.com', + 'mailto:hello@mail.com', + 'mailto:info@mail.com?', + 'mailto:hey@mail.com?subject=something', + 'mailto:info@mail.com?subject=something&cc=valid@mail.com', + 'mailto:info@mail.com?subject=something&cc=valid@mail.com,another@mail.com,', + 'mailto:info@mail.com?subject=something&bcc=valid@mail.com', + 'mailto:info@mail.com?subject=something&bcc=valid@mail.com,another@mail.com', + 'mailto:info@mail.com?bcc=valid@mail.com,another@mail.com', + 'mailto:info@mail.com?cc=valid@mail.com,another@mail.com', + 'mailto:info@mail.com?cc=valid@mail.com', + 'mailto:info@mail.com?bcc=valid@mail.com&', + 'mailto:info@mail.com?subject=something&body=something else', + 'mailto:info@mail.com?subject=something&body=something else&cc=hello@mail.com,another@mail.com', + 'mailto:info@mail.com?subject=something&body=something else&bcc=hello@mail.com,another@mail.com', + 'mailto:info@mail.com?subject=something&body=something else&cc=something@mail.com&bcc=hello@mail.com,another@mail.com', + ], + invalid: [ + '', + 'somthing', + 'valid@gmail.com', + 'mailto:?subject=okay&subject=444', + 'mailto:?subject=something&wrong=888', + 'mailto:somename@gmail.com', + 'mailto:hello@world.com?cc=somename@gmail.com', + 'mailto:hello@world.com?bcc=somename@gmail.com', + 'mailto:hello@world.com?bcc=somename@gmail.com&bcc', + 'mailto:valid@gmail.com?subject=anything&body=nothing&cc=&bcc=&key=', + 'mailto:hello@world.com?cc=somename', + 'mailto:somename', + ], + }); + }); }); From 49e4e9ce6b917072d06901299e0e49f91ba1636b Mon Sep 17 00:00:00 2001 From: Utpal Sarkar Date: Tue, 21 Feb 2023 17:48:00 +0600 Subject: [PATCH 4/8] added the method description to the readme file --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d75f15b27..9d857e38f 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,7 @@ Validator | Description **isLuhnNumber(str)** | check if the string passes the [Luhn algorithm check](https://en.wikipedia.org/wiki/Luhn_algorithm). **isMACAddress(str [, options])** | check if the string is a MAC address.

`options` is an object which defaults to `{ no_separators: false }`. If `no_separators` is true, the validator will allow MAC addresses without separators. Also, it allows the use of hyphens, spaces or dots e.g. '01 02 03 04 05 ab', '01-02-03-04-05-ab' or '0102.0304.05ab'. The options also allow a `eui` property to specify if it needs to be validated against EUI-48 or EUI-64. The accepted values of `eui` are: 48, 64. **isMagnetURI(str)** | check if the string is a [Magnet URI format][Magnet URI Format]. +**isMailtoURI(str, [, options])** | check if the string is a [Magnet URI format][Mailto URI Format].

`options` is an object of validating emails inside the URI (check `isEmail`s options for details). **isMD5(str)** | check if the string is a MD5 hash.

Please note that you can also use the `isHash(str, 'md5')` function. Keep in mind that MD5 has some collision weaknesses compared to other algorithms (e.g., SHA). **isMimeType(str)** | check if the string matches to a valid [MIME type][MIME Type] format. **isMobilePhone(str [, locale [, options]])** | check if the string is a mobile phone number,

`locale` is either an array of locales (e.g. `['sk-SK', 'sr-RS']`) OR one of `['am-Am', 'ar-AE', 'ar-BH', 'ar-DZ', 'ar-EG', 'ar-EH', 'ar-IQ', 'ar-JO', 'ar-KW', 'ar-PS', 'ar-SA', 'ar-SY', 'ar-TN', 'ar-YE', 'az-AZ', 'az-LB', 'az-LY', 'be-BY', 'bg-BG', 'bn-BD', 'bs-BA', 'ca-AD', 'cs-CZ', 'da-DK', 'de-AT', 'de-CH', 'de-DE', 'de-LU', 'dv-MV', 'dz-BT', 'el-CY', 'el-GR', 'en-AG', 'en-AI', 'en-AU', 'en-BM', 'en-BS', 'en-BW', 'en-CA', 'en-GB', 'en-GG', 'en-GH', 'en-GY', 'en-HK', 'en-IE', 'en-IN', 'en-JM', 'en-KE', 'en-KI', 'en-KN', 'en-LS', 'en-MO', 'en-MT', 'en-MU', 'en-NG', 'en-NZ', 'en-PG', 'en-PH', 'en-PK', 'en-RW', 'en-SG', 'en-SL', 'en-SS', 'en-TZ', 'en-UG', 'en-US', 'en-ZA', 'en-ZM', 'en-ZW', 'es-AR', 'es-BO', 'es-CL', 'es-CO', 'es-CR', 'es-CU', 'es-DO', 'es-EC', 'es-ES', 'es-HN', 'es-MX', 'es-NI', 'es-PA', 'es-PE', 'es-PY', 'es-SV', 'es-UY', 'es-VE', 'et-EE', 'fa-AF', 'fa-IR', 'fi-FI', 'fj-FJ', 'fo-FO', 'fr-BE', 'fr-BF', 'fr-BJ', 'fr-CD', 'fr-CF', 'fr-FR', 'fr-GF', 'fr-GP', 'fr-MQ', 'fr-PF', 'fr-RE', 'ga-IE', 'he-IL', 'hu-HU', 'id-ID', 'ir-IR', 'it-IT', 'it-SM', 'ja-JP', 'ka-GE', 'kk-KZ', 'kl-GL', 'ko-KR', 'ky-KG', 'lt-LT', 'mg-MG', 'mn-MN', 'ms-MY', 'my-MM', 'mz-MZ', 'nb-NO', 'ne-NP', 'nl-AW', 'nl-BE', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-AO', 'pt-BR', 'pt-PT', 'ro-Md', 'ro-RO', 'ru-RU', 'si-LK', 'sk-SK', 'sl-SI', 'so-SO', 'sq-AL', 'sr-RS', 'sv-SE', 'tg-TJ', 'th-TH', 'tk-TM', 'tr-TR', 'uk-UA', 'uz-UZ', 'vi-VN', 'zh-CN', 'zh-HK', 'zh-MO', 'zh-TW']` OR defaults to `'any'`. If 'any' or a falsey value is used, function will check if any of the locales match).

`options` is an optional object that can be supplied with the following keys: `strictMode`, if this is set to `true`, the mobile phone number must be supplied with the country code and therefore must start with `+`. Locale list is `validator.isMobilePhoneLocales`. @@ -301,6 +302,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. [ISSN]: https://en.wikipedia.org/wiki/International_Standard_Serial_Number [Luhn Check]: https://en.wikipedia.org/wiki/Luhn_algorithm [Magnet URI Format]: https://en.wikipedia.org/wiki/Magnet_URI_scheme +[Mailto URI Format]: https://en.wikipedia.org/wiki/Mailto [MIME Type]: https://en.wikipedia.org/wiki/Media_type [mongoid]: http://docs.mongodb.org/manual/reference/object-id/ [RFC 3339]: https://tools.ietf.org/html/rfc3339 From 16140b113a9bbf8934a1409e2f26f452368315f4 Mon Sep 17 00:00:00 2001 From: Utpal Sarkar Date: Tue, 21 Feb 2023 20:35:16 +0600 Subject: [PATCH 5/8] early checked the 'to' and 'queryString' --- src/lib/isMailtoURI.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib/isMailtoURI.js b/src/lib/isMailtoURI.js index 0bf9b9cfd..a979ad054 100644 --- a/src/lib/isMailtoURI.js +++ b/src/lib/isMailtoURI.js @@ -46,6 +46,10 @@ export default function isMailtoURI(url, options) { const [to = '', queryString = ''] = url.replace('mailto:', '').split('?'); + if (!to && !queryString) { + return true; + } + const query = parseMailtoQueryString(queryString); if (!query) { From 49a2e1280e3faab5ce3be6623130f608173a3bab Mon Sep 17 00:00:00 2001 From: Utpal Sarkar Date: Tue, 21 Feb 2023 20:35:25 +0600 Subject: [PATCH 6/8] added more test --- test/validators.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/validators.test.js b/test/validators.test.js index c45520b39..a778a7eeb 100644 --- a/test/validators.test.js +++ b/test/validators.test.js @@ -14210,6 +14210,7 @@ describe('Validators', () => { 'mailto:info@mail.com?subject=something&body=something else&cc=hello@mail.com,another@mail.com', 'mailto:info@mail.com?subject=something&body=something else&bcc=hello@mail.com,another@mail.com', 'mailto:info@mail.com?subject=something&body=something else&cc=something@mail.com&bcc=hello@mail.com,another@mail.com', + 'mailto:', ], invalid: [ '', @@ -14224,6 +14225,8 @@ describe('Validators', () => { 'mailto:valid@gmail.com?subject=anything&body=nothing&cc=&bcc=&key=', 'mailto:hello@world.com?cc=somename', 'mailto:somename', + 'mailto:info@mail.com?subject=something&body=something else&cc=something@mail.com&bcc=hello@mail.com,another@mail.com&', + 'mailto:?subject=something&body=something else&cc=something@mail.com&bcc=hello@mail.com,another@mail.com&', ], }); }); From 1869d54778e9489afa88a5b644786205e03069b9 Mon Sep 17 00:00:00 2001 From: Utpal Sarkar Date: Tue, 21 Feb 2023 21:28:12 +0600 Subject: [PATCH 7/8] using every instead of reduce --- src/lib/isMailtoURI.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/lib/isMailtoURI.js b/src/lib/isMailtoURI.js index a979ad054..1ab1ca03e 100644 --- a/src/lib/isMailtoURI.js +++ b/src/lib/isMailtoURI.js @@ -58,17 +58,13 @@ export default function isMailtoURI(url, options) { return `${to},${query.cc},${query.bcc}` .split(',') - .reduce((isValid, email) => { - if (!isValid) { - return isValid; - } - + .every((email) => { email = trim(email, ' '); if (email) { - isValid = isEmail(email, options); + return isEmail(email, options); } - return isValid; - }, true); + return true; + }); } From 21fc56291b7a2260b2bd5faa4c6a7a702bfe975b Mon Sep 17 00:00:00 2001 From: Utpal Sarkar Date: Tue, 21 Feb 2023 21:34:52 +0600 Subject: [PATCH 8/8] removed the 'continue' --- src/lib/isMailtoURI.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/lib/isMailtoURI.js b/src/lib/isMailtoURI.js index 1ab1ca03e..0dd95b6a9 100644 --- a/src/lib/isMailtoURI.js +++ b/src/lib/isMailtoURI.js @@ -16,13 +16,8 @@ function parseMailtoQueryString(queryString) { for (const q of queryParams) { const [key, value] = q.split('='); - if (!key) { - // eslint-disable-next-line no-continue - continue; - } - // checked for invalid and duplicated query params - if (!allowedParams.has(key)) { + if (key && !allowedParams.has(key)) { isParseFailed = true; break; } @@ -31,7 +26,9 @@ function parseMailtoQueryString(queryString) { query[key] = value; } - allowedParams.delete(key); + if (key) { + allowedParams.delete(key); + } } return isParseFailed ? false : query;