close
Skip to content

Commit f653dac

Browse files
authored
feat(validators): host, ipv4 and domain name validators (#1212)
* feat(validators): host, ipv4 and domain name validators Changes share modal email validation to use new email validator. @hapi/address is used by @hapi/Joi JSON schema validator BREAKING CHANGE: Adds peer dependency of @hapi/address used for email and domain validation * fix: added uncommon tlds for email checking * fix: adding some bad tlds
1 parent 67fe62f commit f653dac

6 files changed

Lines changed: 152 additions & 3 deletions

File tree

‎package.json‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@
148148
"@commitlint/cli": "^7.2.1",
149149
"@commitlint/config-conventional": "^7.1.2",
150150
"@commitlint/travis-cli": "^7.2.1",
151+
"@hapi/address": "^2.0.0",
151152
"autoprefixer": "^9.4.8",
152153
"axios": "^0.18.0",
153154
"babel-core": "^7.0.0-bridge.0",
@@ -260,6 +261,7 @@
260261
"worker-farm": "^1.6.0"
261262
},
262263
"peerDependencies": {
264+
"@hapi/address": "^2.0.0",
263265
"axios": "^0.18.0",
264266
"classnames": "^2.2.5",
265267
"draft-js": "^0.10.1",

‎src/features/unified-share-modal/EmailForm.js‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import Tooltip from '../../components/tooltip';
1616
import InlineNotice from '../../components/inline-notice';
1717
import PillSelectorDropdown from '../../components/pill-selector-dropdown';
1818
import commonMessages from '../../common/messages';
19+
import { emailValidator } from '../../utils/validators';
1920
import type { inlineNoticeType } from '../../common/box-types';
2021

2122
import ContactsField from './ContactsField';
@@ -195,9 +196,7 @@ class EmailForm extends React.Component<Props, State> {
195196
};
196197

197198
isValidEmail = (text: string): boolean => {
198-
// TODO-AH: make this a constant somewhere
199-
const emailValidation = /^[^\s<>@,]+@[^\s<>@,/\\]+\.[^\s<>@,]+$/i;
200-
return emailValidation.test(text);
199+
return emailValidator(text);
201200
};
202201

203202
render() {

‎src/features/unified-share-modal/__tests__/EmailForm-test.js‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,18 @@ describe('features/unified-share-modal/EmailForm', () => {
283283
email: 'test.box.com',
284284
expectedValue: false,
285285
},
286+
{
287+
email: 'foo@bar.dog',
288+
expectedValue: true,
289+
},
290+
{
291+
email: 'foo@bar.design',
292+
expectedValue: true,
293+
},
294+
{
295+
email: 'foo@bar.dev',
296+
expectedValue: true,
297+
},
286298
{
287299
email: 'test@@example.com',
288300
expectedValue: false,
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// @flow
2+
3+
import { domainNameValidator, emailValidator, hostnameValidator, ipv4AddressValidator } from '../validators';
4+
5+
describe('util/validators', () => {
6+
describe('domainNameValidator()', () => {
7+
test.each([
8+
['a.com', true],
9+
['www.a.com', true],
10+
['a-1.com', true],
11+
['www.a-1.com', true],
12+
['-a.com', false],
13+
['www.a.com-', false],
14+
['a@b.com', false],
15+
['a.', false],
16+
['1.1.1.1', false],
17+
['1.1.1', false],
18+
['1.1', false],
19+
['a', false],
20+
])('domainNameValidator(%s) should return %s', (domain, expected) => {
21+
expect(domainNameValidator(domain)).toBe(expected);
22+
});
23+
});
24+
25+
describe('hostnameValidator()', () => {
26+
test.each([
27+
['a.com', true],
28+
['www.a.com', true],
29+
['a-1.com', true],
30+
['www.a-1.com', true],
31+
['-a.com', false],
32+
['www.a.com-', false],
33+
['a@b.com', false],
34+
['a.', false],
35+
['1.1.1.1', true],
36+
['1.1.1', true],
37+
['1.1', true],
38+
['a', true],
39+
])('hostnameValidator(%s) should return %s', (hostname, expected) => {
40+
expect(hostnameValidator(hostname)).toBe(expected);
41+
});
42+
});
43+
44+
describe('ipv4AddressValidator()', () => {
45+
test.each([
46+
['a.com', false],
47+
['www.a.com', false],
48+
['a-1.com', false],
49+
['www.a-1.com', false],
50+
['-a.com', false],
51+
['www.a.com-', false],
52+
['a@b.com', false],
53+
['a.', false],
54+
['1.1.1.1', true],
55+
['256.1.1.1', false],
56+
['1.256.1.1', false],
57+
['1.1.256.1', false],
58+
['1.1.1.256', false],
59+
['1.1.1', false],
60+
['1.1', false],
61+
['1.1.', false],
62+
['1.', false],
63+
['a', false],
64+
])('ipv4AddressValidator(%s) should return %s', (address, expected) => {
65+
expect(ipv4AddressValidator(address)).toBe(expected);
66+
});
67+
});
68+
69+
describe('emailValidator()', () => {
70+
test.each([
71+
['a.com', false],
72+
['www.a.com', false],
73+
['a-1.com', false],
74+
['www.a-1.com', false],
75+
['-a.com', false],
76+
['www.a.com-', false],
77+
['a@b.com', true],
78+
['a@b.dfdsfsdffs', false],
79+
['a@b.whatever', false],
80+
['a@b.junk', false],
81+
['a@b.design', true],
82+
['a@b.dog', true],
83+
['a@b.business', true],
84+
['a@b.club', true],
85+
['a@b.life', true],
86+
['a@b.co.com', true],
87+
['a@.com', false],
88+
['a.x@b.com', true],
89+
['a:x@b.com', false],
90+
['a..x@b.com', false],
91+
['@b.com', false],
92+
['a.', false],
93+
['1.1.1.1', false],
94+
['256.1.1.1', false],
95+
['1.256.1.1', false],
96+
['1.1.256.1', false],
97+
['1.1.1.256', false],
98+
['1.1.1', false],
99+
['1.1', false],
100+
['1.1.', false],
101+
['1.', false],
102+
['a', false],
103+
])('emailValidator(%s) should return %s', (email, expected) => {
104+
expect(emailValidator(email)).toBe(expected);
105+
});
106+
});
107+
});

‎src/utils/validators.js‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// @flow
2+
import Address from '@hapi/address';
3+
4+
function hostnameValidator(value: string): boolean {
5+
// @see https://github.com/hapijs/joi/blame/3516cf0b995c9fe415634c4612c0ac2f8792f0b4/lib/types/string/index.js#L530
6+
const regex = /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])$/;
7+
return regex.test(value);
8+
}
9+
10+
function ipv4AddressValidator(value: string): boolean {
11+
// @see https://www.oreilly.com/library/view/regular-expressions-cookbook/9780596802837/ch07s16.html
12+
const regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
13+
return regex.test(value);
14+
}
15+
16+
function domainNameValidator(value: string): boolean {
17+
return Address.domain.isValid(value);
18+
}
19+
20+
function emailValidator(value: string): boolean {
21+
return Address.email.isValid(value);
22+
}
23+
24+
export { domainNameValidator, emailValidator, hostnameValidator, ipv4AddressValidator };

‎yarn.lock‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,6 +1277,11 @@
12771277
debug "^3.1.0"
12781278
lodash.once "^4.1.1"
12791279

1280+
"@hapi/address@^2.0.0":
1281+
version "2.0.0"
1282+
resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.0.0.tgz#9f05469c88cb2fd3dcd624776b54ee95c312126a"
1283+
integrity sha512-mV6T0IYqb0xL1UALPFplXYQmR0twnXG0M6jUswpquqT2sD12BOiCiLy3EvMp/Fy7s3DZElC4/aPjEjo2jeZpvw==
1284+
12801285
"@jest/console@^24.3.0":
12811286
version "24.3.0"
12821287
resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.3.0.tgz#7bd920d250988ba0bf1352c4493a48e1cb97671e"

0 commit comments

Comments
 (0)