Skip to content

Commit 98804b4

Browse files
author
Lam Chan
committed
added support for string.uri relativeOnly option
1 parent 2963e1b commit 98804b4

File tree

4 files changed

+131
-10
lines changed

4 files changed

+131
-10
lines changed

lib/language.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ exports.errors = {
126126
},
127127
email: 'must be a valid email',
128128
uri: 'must be a valid uri',
129+
uriRelativeOnly: 'must be a relative only uri',
129130
uriCustomScheme: 'must be a valid uri with a scheme matching the {{scheme}} pattern',
130131
isoDate: 'must be a valid ISO 8601 date',
131132
guid: 'must be a valid GUID',

lib/string.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ internals.String = class extends Any {
224224

225225
let customScheme = '';
226226
let allowRelative = false;
227+
let relativeOnly = false;
227228
let regex = internals.uriRegex;
228229

229230
if (uriOptions) {
@@ -260,10 +261,14 @@ internals.String = class extends Any {
260261
if (uriOptions.allowRelative) {
261262
allowRelative = true;
262263
}
264+
265+
if (uriOptions.relativeOnly) {
266+
relativeOnly = true;
267+
}
263268
}
264269

265-
if (customScheme || allowRelative) {
266-
regex = Uri.createUriRegex(customScheme, allowRelative);
270+
if (customScheme || allowRelative || relativeOnly) {
271+
regex = Uri.createUriRegex(customScheme, allowRelative, relativeOnly);
267272
}
268273

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

280+
if (relativeOnly) {
281+
return this.createError('string.uriRelativeOnly', { value }, state, options);
282+
}
283+
275284
if (customScheme) {
276285
return this.createError('string.uriCustomScheme', { scheme: customScheme, value }, state, options);
277286
}

lib/string/uri.js

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,26 @@ const RFC3986 = require('./rfc3986');
99

1010
const internals = {
1111
Uri: {
12-
createUriRegex: function (optionalScheme, allowRelative) {
12+
createUriRegex: function (optionalScheme, allowRelative, relativeOnly) {
1313

1414
let scheme = RFC3986.scheme;
15+
let prefix;
1516

16-
// If we were passed a scheme, use it instead of the generic one
17-
if (optionalScheme) {
18-
19-
// Have to put this in a non-capturing group to handle the OR statements
20-
scheme = '(?:' + optionalScheme + ')';
17+
if (relativeOnly) {
18+
prefix = '(?:' + RFC3986.relativeRef + ')';
2119
}
20+
else {
21+
// If we were passed a scheme, use it instead of the generic one
22+
if (optionalScheme) {
23+
24+
// Have to put this in a non-capturing group to handle the OR statements
25+
scheme = '(?:' + optionalScheme + ')';
26+
}
2227

23-
const withScheme = '(?:' + scheme + ':' + RFC3986.hierPart + ')';
24-
const prefix = allowRelative ? '(?:' + withScheme + '|' + RFC3986.relativeRef + ')' : withScheme;
28+
const withScheme = '(?:' + scheme + ':' + RFC3986.hierPart + ')';
29+
30+
prefix = allowRelative ? '(?:' + withScheme + '|' + RFC3986.relativeRef + ')' : withScheme;
31+
}
2532

2633
/**
2734
* URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]

test/string.js

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1847,6 +1847,110 @@ describe('string', () => {
18471847
['/absolute', true]
18481848
], done);
18491849
});
1850+
1851+
it('validates relative only uri', (done) => {
1852+
1853+
const schema = Joi.string().uri({ relativeOnly: true });
1854+
Helper.validate(schema, [
1855+
['foo://example.com:8042/over/there?name=ferret#nose', false, null, '"value" must be a relative only uri'],
1856+
['urn:example:animal:ferret:nose', false, null, '"value" must be a relative only uri'],
1857+
['ftp://ftp.is.co.za/rfc/rfc1808.txt', false, null, '"value" must be a relative only uri'],
1858+
['http://www.ietf.org/rfc/rfc2396.txt', false, null, '"value" must be a relative only uri'],
1859+
['ldap://[2001:db8::7]/c=GB?objectClass?one', false, null, '"value" must be a relative only uri'],
1860+
['mailto:[email protected]', false, null, '"value" must be a relative only uri'],
1861+
['news:comp.infosystems.www.servers.unix', false, null, '"value" must be a relative only uri'],
1862+
['tel:+1-816-555-1212', false, null, '"value" must be a relative only uri'],
1863+
['telnet://192.0.2.16:80/', false, null, '"value" must be a relative only uri'],
1864+
['urn:oasis:names:specification:docbook:dtd:xml:4.1.2', false, null, '"value" must be a relative only uri'],
1865+
['file:///example.txt', false, null, '"value" must be a relative only uri'],
1866+
['http://asdf:qw%20er@localhost:8000?asdf=12345&asda=fc%2F#bacon', false, null, '"value" must be a relative only uri'],
1867+
['http://asdf@localhost:8000', false, null, '"value" must be a relative only uri'],
1868+
['http://[v1.09azAZ-._~!$&\'()*+,;=:]', false, null, '"value" must be a relative only uri'],
1869+
['http://[a:b:c:d:e::1.2.3.4]', false, null, '"value" must be a relative only uri'],
1870+
['coap://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]', false, null, '"value" must be a relative only uri'],
1871+
['http://[1080:0:0:0:8:800:200C:417A]', false, null, '"value" must be a relative only uri'],
1872+
['http://127.0.0.1:8000/foo?bar', false, null, '"value" must be a relative only uri'],
1873+
['http://asdf:qwer@localhost:8000', false, null, '"value" must be a relative only uri'],
1874+
['http://user:pass%3A@localhost:80', false, null, '"value" must be a relative only uri'],
1875+
['http://localhost:123', false, null, '"value" must be a relative only uri'],
1876+
['https://localhost:123', false, null, '"value" must be a relative only uri'],
1877+
['file:///whatever', false, null, '"value" must be a relative only uri'],
1878+
['mailto:[email protected]', false, null, '"value" must be a relative only uri'],
1879+
['ftp://www.example.com', false, null, '"value" must be a relative only uri'],
1880+
['javascript:alert(\'hello\');', false, null, '"value" must be a relative only uri'], // eslint-disable-line no-script-url
1881+
['xmpp:[email protected]', false, null, '"value" must be a relative only uri'],
1882+
['f://some.host/path', false, null, '"value" must be a relative only uri'],
1883+
['http://localhost:18/asdf', false, null, '"value" must be a relative only uri'],
1884+
['http://localhost:42/asdf?qwer=zxcv', false, null, '"value" must be a relative only uri'],
1885+
['HTTP://www.example.com/', false, null, '"value" must be a relative only uri'],
1886+
['HTTP://www.example.com', false, null, '"value" must be a relative only uri'],
1887+
['http://www.ExAmPlE.com/', false, null, '"value" must be a relative only uri'],
1888+
['http://user:[email protected]/', false, null, '"value" must be a relative only uri'],
1889+
['http://USER:[email protected]/', false, null, '"value" must be a relative only uri'],
1890+
['http://[email protected]/', false, null, '"value" must be a relative only uri'],
1891+
['http://user%[email protected]/', false, null, '"value" must be a relative only uri'],
1892+
['http://x.com/path?that%27s#all,%20folks', false, null, '"value" must be a relative only uri'],
1893+
['HTTP://X.COM/Y', false, null, '"value" must be a relative only uri'],
1894+
['http://www.narwhaljs.org/blog/categories?id=news', false, null, '"value" must be a relative only uri'],
1895+
['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'],
1896+
['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'],
1897+
['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'],
1898+
['http://_jabber._tcp.google.com:80/test', false, null, '"value" must be a relative only uri'],
1899+
['http://user:pass@_jabber._tcp.google.com:80/test', false, null, '"value" must be a relative only uri'],
1900+
['http://[fe80::1]/a/b?a=b#abc', false, null, '"value" must be a relative only uri'],
1901+
['http://user:password@[3ffe:2a00:100:7031::1]:8080', false, null, '"value" must be a relative only uri'],
1902+
['coap://[1080:0:0:0:8:800:200C:417A]:61616/', false, null, '"value" must be a relative only uri'],
1903+
['git+http://github.com/joyent/node.git', false, null, '"value" must be a relative only uri'],
1904+
['http://bucket_name.s3.amazonaws.com/image.jpg', false, null, '"value" must be a relative only uri'],
1905+
['dot.test://foo/bar', false, null, '"value" must be a relative only uri'],
1906+
['svn+ssh://foo/bar', false, null, '"value" must be a relative only uri'],
1907+
['dash-test://foo/bar', false, null, '"value" must be a relative only uri'],
1908+
['xmpp:[email protected]', false, null, '"value" must be a relative only uri'],
1909+
['http://atpass:foo%[email protected]:8080/path?search=foo#bar', false, null, '"value" must be a relative only uri'],
1910+
['javascript:alert(\'hello\');', false, null, '"value" must be a relative only uri'], // eslint-disable-line no-script-url
1911+
['file://localhost/etc/node/', false, null, '"value" must be a relative only uri'],
1912+
['file:///etc/node/', false, null, '"value" must be a relative only uri'],
1913+
['http://USER:[email protected]/', false, null, '"value" must be a relative only uri'],
1914+
['mailto:local1@domain1?query1', false, null, '"value" must be a relative only uri'],
1915+
['http://example/a/b?c/../d', false, null, '"value" must be a relative only uri'],
1916+
['http://example/x%2Fabc', false, null, '"value" must be a relative only uri'],
1917+
['http://a/b/c/d;p=1/g;x=1/y', false, null, '"value" must be a relative only uri'],
1918+
['http://a/b/c/g#s/../x', false, null, '"value" must be a relative only uri'],
1919+
['http://a/b/c/.foo', false, null, '"value" must be a relative only uri'],
1920+
['http://example.com/b//c//d;p?q#blarg', false, null, '"value" must be a relative only uri'],
1921+
['g:h', false, null, '"value" must be a relative only uri'],
1922+
['http://a/b/c/g', false, null, '"value" must be a relative only uri'],
1923+
['http://a/b/c/g/', false, null, '"value" must be a relative only uri'],
1924+
['http://a/g', false, null, '"value" must be a relative only uri'],
1925+
['http://g', false, null, '"value" must be a relative only uri'],
1926+
['http://a/b/c/d;p?y', false, null, '"value" must be a relative only uri'],
1927+
['http://a/b/c/g?y', false, null, '"value" must be a relative only uri'],
1928+
['http://a/b/c/d;p?q#s', false, null, '"value" must be a relative only uri'],
1929+
['http://a/b/c/g#s', false, null, '"value" must be a relative only uri'],
1930+
['http://a/b/c/g?y#s', false, null, '"value" must be a relative only uri'],
1931+
['http://a/b/c/;x', false, null, '"value" must be a relative only uri'],
1932+
['http://a/b/c/g;x', false, null, '"value" must be a relative only uri'],
1933+
['http://a/b/c/g;x?y#s', false, null, '"value" must be a relative only uri'],
1934+
['http://a/b/c/d;p?q', false, null, '"value" must be a relative only uri'],
1935+
['http://a/b/c/', false, null, '"value" must be a relative only uri'],
1936+
['http://a/b/', false, null, '"value" must be a relative only uri'],
1937+
['http://a/b/g', false, null, '"value" must be a relative only uri'],
1938+
['http://a/', false, null, '"value" must be a relative only uri'],
1939+
['http://a/g', false, null, '"value" must be a relative only uri'],
1940+
['http://a/g', false, null, '"value" must be a relative only uri'],
1941+
['file:/asda', false, null, '"value" must be a relative only uri'],
1942+
['qwerty', true],
1943+
['invalid uri', false, null, '"value" must be a relative only uri'],
1944+
['1http://google.com', false, null, '"value" must be a relative only uri'],
1945+
['http://testdomain`,.<>/?\'";{}][++\\|~!@#$%^&*().org', false, null, '"value" must be a relative only uri'],
1946+
['', false, null, '"value" is not allowed to be empty'],
1947+
['(╯°□°)╯︵ ┻━┻', false, null, '"value" must be a relative only uri'],
1948+
['one/two/three?value=abc&value2=123#david-rules', true],
1949+
['//username:[email protected]/one/two/three?value=abc&value2=123#david-rules', true],
1950+
['http://a\r" \t\n<\'b:b@c\r\nd/e?f', false, null, '"value" must be a relative only uri'],
1951+
['/absolute', true]
1952+
], done);
1953+
});
18501954
});
18511955

18521956
describe('truncate()', () => {

0 commit comments

Comments
 (0)