Skip to content

Commit

Permalink
Support ipv6 urls, this closes #564
Browse files Browse the repository at this point in the history
  • Loading branch information
chriso committed Sep 11, 2016
1 parent 7d0bee5 commit b7c749b
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 19 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#### HEAD

- Added support for IPv6 in `isURL()`
([#564](https://github.com/chriso/validator.js/issues/564))
- Added support for MasterCard 2-Series BIN
([#576](https://github.com/chriso/validator.js/pull/576))
- New locales
Expand Down
28 changes: 22 additions & 6 deletions lib/isURL.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ var default_url_options = {
allow_protocol_relative_urls: false
};

var wrapped_ipv6 = /^\[([^\]]+)\](?::([0-9]+))?$/;

function isURL(url, options) {
(0, _assertString2.default)(url);
if (!url || url.length >= 2083 || /\s/.test(url)) {
Expand All @@ -48,7 +50,8 @@ function isURL(url, options) {
hostname = void 0,
port = void 0,
port_str = void 0,
split = void 0;
split = void 0,
ipv6 = void 0;

split = url.split('#');
url = split.shift();
Expand Down Expand Up @@ -79,16 +82,29 @@ function isURL(url, options) {
}
}
hostname = split.join('@');
split = hostname.split(':');
host = split.shift();
if (split.length) {
port_str = split.join(':');

port_str = ipv6 = null;
var ipv6_match = hostname.match(wrapped_ipv6);
if (ipv6_match) {
host = '';
ipv6 = ipv6_match[1];
port_str = ipv6_match[2] || null;
} else {
split = hostname.split(':');
host = split.shift();
if (split.length) {
port_str = split.join(':');
}
}

if (port_str !== null) {
port = parseInt(port_str, 10);
if (!/^[0-9]+$/.test(port_str) || port <= 0 || port > 65535) {
return false;
}
}
if (!(0, _isIP2.default)(host) && !(0, _isFQDN2.default)(host, options) && host !== 'localhost') {

if (!(0, _isIP2.default)(host) && !(0, _isFQDN2.default)(host, options) && (!ipv6 || !(0, _isIP2.default)(ipv6, 6)) && host !== 'localhost') {
return false;
}
if (options.host_whitelist && options.host_whitelist.indexOf(host) === -1) {
Expand Down
27 changes: 21 additions & 6 deletions src/lib/isURL.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ const default_url_options = {
allow_protocol_relative_urls: false,
};

const wrapped_ipv6 = /^\[([^\]]+)\](?::([0-9]+))?$/;

export default function isURL(url, options) {
assertString(url);
if (!url || url.length >= 2083 || /\s/.test(url)) {
Expand All @@ -23,7 +25,7 @@ export default function isURL(url, options) {
return false;
}
options = merge(options, default_url_options);
let protocol, auth, host, hostname, port, port_str, split;
let protocol, auth, host, hostname, port, port_str, split, ipv6;

split = url.split('#');
url = split.shift();
Expand Down Expand Up @@ -54,16 +56,29 @@ export default function isURL(url, options) {
}
}
hostname = split.join('@');
split = hostname.split(':');
host = split.shift();
if (split.length) {
port_str = split.join(':');

port_str = ipv6 = null;
const ipv6_match = hostname.match(wrapped_ipv6);
if (ipv6_match) {
host = '';
ipv6 = ipv6_match[1];
port_str = ipv6_match[2] || null;
} else {
split = hostname.split(':');
host = split.shift();
if (split.length) {
port_str = split.join(':');
}
}

if (port_str !== null) {
port = parseInt(port_str, 10);
if (!/^[0-9]+$/.test(port_str) || port <= 0 || port > 65535) {
return false;
}
}
if (!isIP(host) && !isFQDN(host, options) &&

if (!isIP(host) && !isFQDN(host, options) && (!ipv6 || !isIP(ipv6, 6)) &&
host !== 'localhost') {
return false;
}
Expand Down
7 changes: 7 additions & 0 deletions test/validators.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,13 @@ describe('Validators', function () {
'http://xn------eddceddeftq7bvv7c4ke4c.xn--p1ai',
'http://кулік.укр',
'test.com?ref=http://test2.com',
'http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html',
'http://[1080:0:0:0:8:800:200C:417A]/index.html',
'http://[3ffe:2a00:100:7031::1]',
'http://[1080::8:800:200C:417A]/foo',
'http://[::192.9.5.5]/ipng',
'http://[::FFFF:129.144.52.38]:80/index.html',
'http://[2010:836B:4179::836B:4179]',
],
invalid: [
'xyz://foobar.com',
Expand Down
28 changes: 22 additions & 6 deletions validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,8 @@
allow_protocol_relative_urls: false
};

var wrapped_ipv6 = /^\[([^\]]+)\](?::([0-9]+))?$/;

function isURL(url, options) {
assertString(url);
if (!url || url.length >= 2083 || /\s/.test(url)) {
Expand All @@ -316,7 +318,8 @@
hostname = void 0,
port = void 0,
port_str = void 0,
split = void 0;
split = void 0,
ipv6 = void 0;

split = url.split('#');
url = split.shift();
Expand Down Expand Up @@ -347,16 +350,29 @@
}
}
hostname = split.join('@');
split = hostname.split(':');
host = split.shift();
if (split.length) {
port_str = split.join(':');

port_str = ipv6 = null;
var ipv6_match = hostname.match(wrapped_ipv6);
if (ipv6_match) {
host = '';
ipv6 = ipv6_match[1];
port_str = ipv6_match[2] || null;
} else {
split = hostname.split(':');
host = split.shift();
if (split.length) {
port_str = split.join(':');
}
}

if (port_str !== null) {
port = parseInt(port_str, 10);
if (!/^[0-9]+$/.test(port_str) || port <= 0 || port > 65535) {
return false;
}
}
if (!isIP(host) && !isFDQN(host, options) && host !== 'localhost') {

if (!isIP(host) && !isFDQN(host, options) && (!ipv6 || !isIP(ipv6, 6)) && host !== 'localhost') {
return false;
}
if (options.host_whitelist && options.host_whitelist.indexOf(host) === -1) {
Expand Down
Loading

0 comments on commit b7c749b

Please sign in to comment.