diff --git a/src/util/validators.js b/src/util/validators.js index d8240dcc..56e51d00 100644 --- a/src/util/validators.js +++ b/src/util/validators.js @@ -136,6 +136,24 @@ export const ageAtLeast = (message, minYears) => value => { return message; }; +export const validBusinessURL = message => value => { + if (typeof value === 'undefined' || value === null) { + return message; + } + + const disallowedChars = /[^-A-Za-z0-9+&@#/%?=~_|!:,.;()]/; + const protocolTokens = value.split(':'); + const includesProtocol = protocolTokens.length > 1; + const usesHttpProtocol = includesProtocol && !!protocolTokens[0].match(/^(https?)/); + + const invalidCharacters = !!value.match(disallowedChars); + const invalidProtocol = !(usesHttpProtocol || !includesProtocol); + // Stripe checks against example.com + const isExampleDotCom = !!value.match(/^(https?:\/\/example\.com|example\.com)/); + const isLocalhost = !!value.match(/^(https?:\/\/localhost($|:|\/)|localhost($|:|\/))/); + return invalidCharacters || invalidProtocol || isExampleDotCom || isLocalhost ? message : VALID; +}; + export const validSsnLast4 = message => value => { return value.length === 4 ? VALID : message; }; diff --git a/src/util/validators.test.js b/src/util/validators.test.js index 08e8d23a..83f2f883 100644 --- a/src/util/validators.test.js +++ b/src/util/validators.test.js @@ -6,6 +6,7 @@ import { maxLength, moneySubUnitAmountAtLeast, composeValidators, + validBusinessURL, validHKID, } from './validators'; @@ -150,6 +151,35 @@ describe('validators', () => { expect(moneySubUnitAmountAtLeast('fail', 50)(new Money(100, 'USD'))).toBeUndefined(); }); }); + describe('validBusinessURL()', () => { + it('should fail on example.com', () => { + expect(validBusinessURL('fail')('example.com')).toEqual('fail'); + }); + it('should fail on http://example.com', () => { + expect(validBusinessURL('fail')('http://example.com')).toEqual('fail'); + }); + it('should fail on localhost', () => { + expect(validBusinessURL('fail')('localhost/')).toEqual('fail'); + }); + it('should fail on http://localhost', () => { + expect(validBusinessURL('fail')('http://localhost/')).toEqual('fail'); + }); + it('should fail on localhost:3000', () => { + expect(validBusinessURL('fail')('localhost:3000')).toEqual('fail'); + }); + it('should fail on ', () => { + expect(validBusinessURL('fail')('')).toEqual('fail'); + }); + it('should allow on localhosttunnel.com', () => { + expect(validBusinessURL('fail')('localhosttunnel.com')).toBeUndefined(); + }); + it('should allow on http://localhosttunnel.com', () => { + expect(validBusinessURL('fail')('http://localhosttunnel.com')).toBeUndefined(); + }); + it('should allow on https://localhosttunnel.com', () => { + expect(validBusinessURL('fail')('https://localhosttunnel.com')).toBeUndefined(); + }); + }); describe('composeValidators()', () => { const validateLength = composeValidators(minLength('minLength', 4), maxLength('maxLength', 6));