Skip to content

Commit

Permalink
added support for string.uri relativeOnly option
Browse files Browse the repository at this point in the history
  • Loading branch information
Lam Chan committed Nov 13, 2016
1 parent 2963e1b commit 98804b4
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 10 deletions.
1 change: 1 addition & 0 deletions lib/language.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ exports.errors = {
},
email: 'must be a valid email',
uri: 'must be a valid uri',
uriRelativeOnly: 'must be a relative only uri',
uriCustomScheme: 'must be a valid uri with a scheme matching the {{scheme}} pattern',
isoDate: 'must be a valid ISO 8601 date',
guid: 'must be a valid GUID',
Expand Down
13 changes: 11 additions & 2 deletions lib/string.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ internals.String = class extends Any {

let customScheme = '';
let allowRelative = false;
let relativeOnly = false;
let regex = internals.uriRegex;

if (uriOptions) {
Expand Down Expand Up @@ -260,10 +261,14 @@ internals.String = class extends Any {
if (uriOptions.allowRelative) {
allowRelative = true;
}

if (uriOptions.relativeOnly) {
relativeOnly = true;
}
}

if (customScheme || allowRelative) {
regex = Uri.createUriRegex(customScheme, allowRelative);
if (customScheme || allowRelative || relativeOnly) {
regex = Uri.createUriRegex(customScheme, allowRelative, relativeOnly);
}

return this._test('uri', uriOptions, function (value, state, options) {
Expand All @@ -272,6 +277,10 @@ internals.String = class extends Any {
return value;
}

if (relativeOnly) {
return this.createError('string.uriRelativeOnly', { value }, state, options);
}

if (customScheme) {
return this.createError('string.uriCustomScheme', { scheme: customScheme, value }, state, options);
}
Expand Down
23 changes: 15 additions & 8 deletions lib/string/uri.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,26 @@ const RFC3986 = require('./rfc3986');

const internals = {
Uri: {
createUriRegex: function (optionalScheme, allowRelative) {
createUriRegex: function (optionalScheme, allowRelative, relativeOnly) {

let scheme = RFC3986.scheme;
let prefix;

// If we were passed a scheme, use it instead of the generic one
if (optionalScheme) {

// Have to put this in a non-capturing group to handle the OR statements
scheme = '(?:' + optionalScheme + ')';
if (relativeOnly) {
prefix = '(?:' + RFC3986.relativeRef + ')';
}
else {
// If we were passed a scheme, use it instead of the generic one
if (optionalScheme) {

// Have to put this in a non-capturing group to handle the OR statements
scheme = '(?:' + optionalScheme + ')';
}

const withScheme = '(?:' + scheme + ':' + RFC3986.hierPart + ')';
const prefix = allowRelative ? '(?:' + withScheme + '|' + RFC3986.relativeRef + ')' : withScheme;
const withScheme = '(?:' + scheme + ':' + RFC3986.hierPart + ')';

prefix = allowRelative ? '(?:' + withScheme + '|' + RFC3986.relativeRef + ')' : withScheme;
}

/**
* URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
Expand Down
104 changes: 104 additions & 0 deletions test/string.js
Original file line number Diff line number Diff line change
Expand Up @@ -1847,6 +1847,110 @@ describe('string', () => {
['/absolute', true]
], done);
});

it('validates relative only uri', (done) => {

const schema = Joi.string().uri({ relativeOnly: true });
Helper.validate(schema, [
['foo://example.com:8042/over/there?name=ferret#nose', false, null, '"value" must be a relative only uri'],
['urn:example:animal:ferret:nose', false, null, '"value" must be a relative only uri'],
['ftp://ftp.is.co.za/rfc/rfc1808.txt', false, null, '"value" must be a relative only uri'],
['http://www.ietf.org/rfc/rfc2396.txt', false, null, '"value" must be a relative only uri'],
['ldap://[2001:db8::7]/c=GB?objectClass?one', false, null, '"value" must be a relative only uri'],
['mailto:[email protected]', false, null, '"value" must be a relative only uri'],
['news:comp.infosystems.www.servers.unix', false, null, '"value" must be a relative only uri'],
['tel:+1-816-555-1212', false, null, '"value" must be a relative only uri'],
['telnet://192.0.2.16:80/', false, null, '"value" must be a relative only uri'],
['urn:oasis:names:specification:docbook:dtd:xml:4.1.2', false, null, '"value" must be a relative only uri'],
['file:///example.txt', false, null, '"value" must be a relative only uri'],
['http://asdf:qw%20er@localhost:8000?asdf=12345&asda=fc%2F#bacon', false, null, '"value" must be a relative only uri'],
['http://asdf@localhost:8000', false, null, '"value" must be a relative only uri'],
['http://[v1.09azAZ-._~!$&\'()*+,;=:]', false, null, '"value" must be a relative only uri'],
['http://[a:b:c:d:e::1.2.3.4]', false, null, '"value" must be a relative only uri'],
['coap://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]', false, null, '"value" must be a relative only uri'],
['http://[1080:0:0:0:8:800:200C:417A]', false, null, '"value" must be a relative only uri'],
['http://127.0.0.1:8000/foo?bar', false, null, '"value" must be a relative only uri'],
['http://asdf:qwer@localhost:8000', false, null, '"value" must be a relative only uri'],
['http://user:pass%3A@localhost:80', false, null, '"value" must be a relative only uri'],
['http://localhost:123', false, null, '"value" must be a relative only uri'],
['https://localhost:123', false, null, '"value" must be a relative only uri'],
['file:///whatever', false, null, '"value" must be a relative only uri'],
['mailto:[email protected]', false, null, '"value" must be a relative only uri'],
['ftp://www.example.com', false, null, '"value" must be a relative only uri'],
['javascript:alert(\'hello\');', false, null, '"value" must be a relative only uri'], // eslint-disable-line no-script-url
['xmpp:[email protected]', false, null, '"value" must be a relative only uri'],
['f://some.host/path', false, null, '"value" must be a relative only uri'],
['http://localhost:18/asdf', false, null, '"value" must be a relative only uri'],
['http://localhost:42/asdf?qwer=zxcv', false, null, '"value" must be a relative only uri'],
['HTTP://www.example.com/', false, null, '"value" must be a relative only uri'],
['HTTP://www.example.com', false, null, '"value" must be a relative only uri'],
['http://www.ExAmPlE.com/', false, null, '"value" must be a relative only uri'],
['http://user:[email protected]/', false, null, '"value" must be a relative only uri'],
['http://USER:[email protected]/', false, null, '"value" must be a relative only uri'],
['http://[email protected]/', false, null, '"value" must be a relative only uri'],
['http://user%[email protected]/', false, null, '"value" must be a relative only uri'],
['http://x.com/path?that%27s#all,%20folks', false, null, '"value" must be a relative only uri'],
['HTTP://X.COM/Y', false, null, '"value" must be a relative only uri'],
['http://www.narwhaljs.org/blog/categories?id=news', false, null, '"value" must be a relative only uri'],
['http://mt0.google.com/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s=', false, null, '"value" must be a relative only uri'],
['http://mt0.google.com/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=', false, null, '"value" must be a relative only uri'],
['http://user:[email protected]/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=', false, null, '"value" must be a relative only uri'],
['http://_jabber._tcp.google.com:80/test', false, null, '"value" must be a relative only uri'],
['http://user:pass@_jabber._tcp.google.com:80/test', false, null, '"value" must be a relative only uri'],
['http://[fe80::1]/a/b?a=b#abc', false, null, '"value" must be a relative only uri'],
['http://user:password@[3ffe:2a00:100:7031::1]:8080', false, null, '"value" must be a relative only uri'],
['coap://[1080:0:0:0:8:800:200C:417A]:61616/', false, null, '"value" must be a relative only uri'],
['git+http://github.com/joyent/node.git', false, null, '"value" must be a relative only uri'],
['http://bucket_name.s3.amazonaws.com/image.jpg', false, null, '"value" must be a relative only uri'],
['dot.test://foo/bar', false, null, '"value" must be a relative only uri'],
['svn+ssh://foo/bar', false, null, '"value" must be a relative only uri'],
['dash-test://foo/bar', false, null, '"value" must be a relative only uri'],
['xmpp:[email protected]', false, null, '"value" must be a relative only uri'],
['http://atpass:foo%[email protected]:8080/path?search=foo#bar', false, null, '"value" must be a relative only uri'],
['javascript:alert(\'hello\');', false, null, '"value" must be a relative only uri'], // eslint-disable-line no-script-url
['file://localhost/etc/node/', false, null, '"value" must be a relative only uri'],
['file:///etc/node/', false, null, '"value" must be a relative only uri'],
['http://USER:[email protected]/', false, null, '"value" must be a relative only uri'],
['mailto:local1@domain1?query1', false, null, '"value" must be a relative only uri'],
['http://example/a/b?c/../d', false, null, '"value" must be a relative only uri'],
['http://example/x%2Fabc', false, null, '"value" must be a relative only uri'],
['http://a/b/c/d;p=1/g;x=1/y', false, null, '"value" must be a relative only uri'],
['http://a/b/c/g#s/../x', false, null, '"value" must be a relative only uri'],
['http://a/b/c/.foo', false, null, '"value" must be a relative only uri'],
['http://example.com/b//c//d;p?q#blarg', false, null, '"value" must be a relative only uri'],
['g:h', false, null, '"value" must be a relative only uri'],
['http://a/b/c/g', false, null, '"value" must be a relative only uri'],
['http://a/b/c/g/', false, null, '"value" must be a relative only uri'],
['http://a/g', false, null, '"value" must be a relative only uri'],
['http://g', false, null, '"value" must be a relative only uri'],
['http://a/b/c/d;p?y', false, null, '"value" must be a relative only uri'],
['http://a/b/c/g?y', false, null, '"value" must be a relative only uri'],
['http://a/b/c/d;p?q#s', false, null, '"value" must be a relative only uri'],
['http://a/b/c/g#s', false, null, '"value" must be a relative only uri'],
['http://a/b/c/g?y#s', false, null, '"value" must be a relative only uri'],
['http://a/b/c/;x', false, null, '"value" must be a relative only uri'],
['http://a/b/c/g;x', false, null, '"value" must be a relative only uri'],
['http://a/b/c/g;x?y#s', false, null, '"value" must be a relative only uri'],
['http://a/b/c/d;p?q', false, null, '"value" must be a relative only uri'],
['http://a/b/c/', false, null, '"value" must be a relative only uri'],
['http://a/b/', false, null, '"value" must be a relative only uri'],
['http://a/b/g', false, null, '"value" must be a relative only uri'],
['http://a/', false, null, '"value" must be a relative only uri'],
['http://a/g', false, null, '"value" must be a relative only uri'],
['http://a/g', false, null, '"value" must be a relative only uri'],
['file:/asda', false, null, '"value" must be a relative only uri'],
['qwerty', true],
['invalid uri', false, null, '"value" must be a relative only uri'],
['1http://google.com', false, null, '"value" must be a relative only uri'],
['http://testdomain`,.<>/?\'";{}][++\\|~!@#$%^&*().org', false, null, '"value" must be a relative only uri'],
['', false, null, '"value" is not allowed to be empty'],
['(╯°□°)╯︵ ┻━┻', false, null, '"value" must be a relative only uri'],
['one/two/three?value=abc&value2=123#david-rules', true],
['//username:[email protected]/one/two/three?value=abc&value2=123#david-rules', true],
['http://a\r" \t\n<\'b:b@c\r\nd/e?f', false, null, '"value" must be a relative only uri'],
['/absolute', true]
], done);
});
});

describe('truncate()', () => {
Expand Down

0 comments on commit 98804b4

Please sign in to comment.