From 156161dd669102e1a7963e9f37a00a514c1596d5 Mon Sep 17 00:00:00 2001 From: srilumpa Date: Mon, 29 Mar 2021 19:11:11 +0200 Subject: [PATCH] Allow longer FQDN and IPv4/v6 in host field (#128) * Allow longer FQDN and IPv4/v6 in hot field * Allow short names as hostnames and add HTTP basic auth in URL --- .../CustomWebhook/validate.js | 37 +++++++++-------- .../CustomWebhook/validate.test.js | 41 +++++++++++++++++++ 2 files changed, 60 insertions(+), 18 deletions(-) diff --git a/public/pages/Destinations/components/createDestinations/CustomWebhook/validate.js b/public/pages/Destinations/components/createDestinations/CustomWebhook/validate.js index ed16d2b7..a840f7eb 100644 --- a/public/pages/Destinations/components/createDestinations/CustomWebhook/validate.js +++ b/public/pages/Destinations/components/createDestinations/CustomWebhook/validate.js @@ -15,25 +15,27 @@ import { URL_TYPE } from '../../../containers/CreateDestination/utils/constants'; +const fqdn = '(?:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(?:\\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})*)' +const regname = `(?:[a-zA-Z0-9._-]+(?::[^@]*)?@)?${fqdn}`; +const ipv4 = '(((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))'; +const h16 = '([0-9a-fA-F]{1,4})'; +const ls32 = `((${h16}:${h16})|${ipv4})`; +const ipv6 = `\\[(`+ + `((${h16}:){6}${ls32})|`+ + `(::(${h16}:){5}${ls32})|`+ + `(${h16}?::(${h16}:){4}${ls32})|`+ + `(((${h16}:){0,1}${h16})?::(${h16}:){3}${ls32})|`+ + `(((${h16}:){0,2}${h16})?::(${h16}:){2}${ls32})|`+ + `(((${h16}:){0,3}${h16})?::${h16}:${ls32})|`+ + `(((${h16}:){0,4}${h16})?::${ls32})|`+ + `(((${h16}:){0,5}${h16})?::${h16})|`+ + `((${h16}:){0,6}${h16})?::`+ + `)\\]`; + export const validateUrl = (value, allValues) => { const type = allValues.type; if (allValues[type].urlType !== URL_TYPE.FULL_URL) return; if (!value) return 'Required'; - const regname = '((www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-z]{2,63})'; - const ipv4 = '(((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))'; - const h16 = '([0-9a-fA-F]{1,4})'; - const ls32 = `((${h16}:${h16})|${ipv4})`; - const ipv6 = `\\[(`+ - `((${h16}:){6}${ls32})|`+ - `(::(${h16}:){5}${ls32})|`+ - `(${h16}?::(${h16}:){4}${ls32})|`+ - `(((${h16}:){0,1}${h16})?::(${h16}:){3}${ls32})|`+ - `(((${h16}:){0,2}${h16})?::(${h16}:){2}${ls32})|`+ - `(((${h16}:){0,3}${h16})?::${h16}:${ls32})|`+ - `(((${h16}:){0,4}${h16})?::${ls32})|`+ - `(((${h16}:){0,5}${h16})?::${h16})|`+ - `((${h16}:){0,6}${h16})?::`+ - `)\\]`; const regexUrl = `^https?:\\/\\/(${regname}|${ipv4}|${ipv6})(:[0-9]{1,5})?([/?#][-a-zA-Z0-9@:%_\\+.~#?&//=]*)?$`; const isValidUrl = new RegExp(regexUrl).test(value); if (!isValidUrl) return 'Invalid URL'; @@ -43,8 +45,7 @@ export const validateHost = (value, allValues) => { const type = allValues.type; if (allValues[type].urlType !== URL_TYPE.ATTRIBUTE_URL) return; if (!value) return 'Required'; - const isValidUrl = /^(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/.test( - value - ); + const regexHost = `^${fqdn}|${ipv4}|${ipv6}$` + const isValidUrl = new RegExp(regexHost).test(value); if (!isValidUrl) return 'Invalid Host'; }; diff --git a/public/pages/Destinations/components/createDestinations/CustomWebhook/validate.test.js b/public/pages/Destinations/components/createDestinations/CustomWebhook/validate.test.js index 47445375..aaaf8a5b 100644 --- a/public/pages/Destinations/components/createDestinations/CustomWebhook/validate.test.js +++ b/public/pages/Destinations/components/createDestinations/CustomWebhook/validate.test.js @@ -32,6 +32,12 @@ describe('validateUrl', () => { expect( validateUrl('https://opendistro.github.io/for-elasticsearch/news.html', typeFullUrl) ).toBeUndefined(); + expect( + validateUrl('https://username:password@opendistro.github.io/for-elasticsearch/news.html', typeFullUrl) + ).toBeUndefined(); + expect( + validateUrl('http://alerts-smtp-forwarder:8080/email', typeFullUrl) + ).toBeUndefined(); expect(validateUrl('http://127.0.0.1:8080/', typeFullUrl)).toBeUndefined(); expect( validateUrl('http://192.168.0.1/test.php?foo=bar&action=test', typeFullUrl) @@ -71,3 +77,38 @@ describe('validateUrl', () => { ).toBe(invalidText); }); }); + +describe('validateHost', () => { + const typeAttributeUrl = { type: 'custom_webhook', custom_webhook: { urlType: URL_TYPE.ATTRIBUTE_URL } }; + + test('returns Required if is empty', () => { + expect(validateHost('', typeAttributeUrl)).toBe('Required'); + }); + + test('returns undefined if valid', () => { + expect( + validateHost('opendistro.github.io', typeAttributeUrl) + ).toBeUndefined(); + expect( + validateHost('alerts-smtp-forwarder', typeAttributeUrl) + ).toBeUndefined(); + expect(validateHost('127.0.0.1', typeAttributeUrl)).toBeUndefined(); + expect( + validateHost('2001:0db8:85a3:0000:0000:0000:0000:7344', typeAttributeUrl) + ).toBeUndefined(); + expect(validateHost('2001:0db8:85a3:0:0:0:0:7344', typeAttributeUrl)).toBeUndefined(); + expect(validateHost('2001:0db8:85a3::7344', typeAttributeUrl)).toBeUndefined(); + expect(validateHost('::ff', typeAttributeUrl)).toBeUndefined(); + expect(validateHost('org.example', typeAttributeUrl)).toBeUndefined(); + }); + + test('returns error string if invalid', () => { + const invalidText = 'Invalid Host'; + expect( + validateHost( + 'org.exampleexampleexampleexampleexampleexampleexampleexampleexampleexampleexampleexample', + typeAttributeUrl + ) + ).toBe(invalidText); + }); +});