Skip to content

Commit 1ed2d4e

Browse files
authored
feat: support encoding uri (follow-up to #3027) (#3032)
1 parent 9af6f1f commit 1ed2d4e

File tree

3 files changed

+48
-12
lines changed

3 files changed

+48
-12
lines changed

API.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3085,7 +3085,7 @@ Requires the string value to be a valid [RFC 3986](http://tools.ietf.org/html/rf
30853085
- `relativeOnly` - Restrict only relative URIs. Defaults to `false`.
30863086
- `allowQuerySquareBrackets` - Allows unencoded square brackets inside the query string. This is **NOT** RFC 3986 compliant but query strings like `abc[]=123&abc[]=456` are very common these days. Defaults to `false`.
30873087
- `domain` - Validate the domain component using the options specified in [`string.domain()`](#stringdomainoptions).
3088-
- `encodeUri` - Encodes the uri with non-alphabetical characters. Defaults to `false`.
3088+
- `encodeUri` - When `convert` is true, if the validation fails, attempts to encode the URI using [`encodeURI`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI) before validating it again. This allows to provide, for example, unicode URIs, and have it encoded for you. Defaults to `false`.
30893089

30903090
```js
30913091
// Accept git or git http/https

lib/types/string.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -665,11 +665,16 @@ module.exports = Any.extend({
665665
return helpers.error('string.uri');
666666
}
667667

668-
if (helpers.prefs.convert && options.encodeUri) {
669-
value = encodeURI(value);
668+
let match = regex.exec(value);
669+
670+
if (!match && helpers.prefs.convert && options.encodeUri) {
671+
const encoded = encodeURI(value);
672+
match = regex.exec(encoded);
673+
if (match) {
674+
value = encoded;
675+
}
670676
}
671677

672-
const match = regex.exec(value);
673678
if (match) {
674679
const matched = match[1] || match[2];
675680
if (domain &&
@@ -690,10 +695,6 @@ module.exports = Any.extend({
690695
return helpers.error('string.uriCustomScheme', { scheme, value });
691696
}
692697

693-
if (options.encodeUri) {
694-
return helpers.error('string.uriEncoding');
695-
}
696-
697698
return helpers.error('string.uri');
698699
}
699700
}
@@ -744,7 +745,6 @@ module.exports = Any.extend({
744745
'string.uri': '{{#label}} must be a valid uri',
745746
'string.uriCustomScheme': '{{#label}} must be a valid uri with a scheme matching the {{#scheme}} pattern',
746747
'string.uriRelativeOnly': '{{#label}} must be a valid relative uri',
747-
'string.uriEncoding': '{{#label}} must contain only valid characters or "convert" must be allowed',
748748
'string.uppercase': '{{#label}} must only contain uppercase characters'
749749
}
750750
});

test/types/string.js

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9017,7 +9017,43 @@ describe('string', () => {
90179017
const schema = Joi.string().uri({ encodeUri: true });
90189018

90199019
Helper.validate(schema, { convert: true }, [
9020-
['https://linkedin.com/in/aïssa/', true, 'https://linkedin.com/in/a%C3%AFssa/']
9020+
['https://linkedin.com/in/aïssa/', true, 'https://linkedin.com/in/a%C3%AFssa/'],
9021+
['https://linkedin.com/in/a%C3%AFssa/', true, 'https://linkedin.com/in/a%C3%AFssa/'],
9022+
['/#.domain.com/', false, {
9023+
message: '"value" must be a valid uri',
9024+
path: [],
9025+
type: 'string.uri',
9026+
context: { label: 'value', value: '/#.domain.com/' }
9027+
}]
9028+
]);
9029+
});
9030+
9031+
it('validates relative uri with accented characters with encoding', () => {
9032+
9033+
const schema = Joi.string().uri({ encodeUri: true, allowRelative: true });
9034+
9035+
Helper.validate(schema, { convert: true }, [
9036+
['/in/aïssa/', true, '/in/a%C3%AFssa/'],
9037+
['/in/a%C3%AFssa/', true, '/in/a%C3%AFssa/']
9038+
]);
9039+
});
9040+
9041+
it('validates uri with encodeUri and scheme', () => {
9042+
9043+
const schema = Joi.string().uri({ encodeUri: true, scheme: 'https' });
9044+
9045+
Helper.validate(schema, { convert: true }, [
9046+
['https://linkedin.com/in/aïssa/', true, 'https://linkedin.com/in/a%C3%AFssa/'],
9047+
['http://linkedin.com/in/aïssa/', false, {
9048+
message: '"value" must be a valid uri with a scheme matching the https pattern',
9049+
path: [],
9050+
type: 'string.uriCustomScheme',
9051+
context: {
9052+
scheme: 'https',
9053+
value: 'http://linkedin.com/in/aïssa/',
9054+
label: 'value'
9055+
}
9056+
}]
90219057
]);
90229058
});
90239059

@@ -9027,9 +9063,9 @@ describe('string', () => {
90279063

90289064
Helper.validate(schema, { convert: false }, [
90299065
['https://linkedin.com/in/aïssa/', false, {
9030-
message: '"value" must contain only valid characters or "convert" must be allowed',
9066+
message: '"value" must be a valid uri',
90319067
path: [],
9032-
type: 'string.uriEncoding',
9068+
type: 'string.uri',
90339069
context: { value: 'https://linkedin.com/in/aïssa/', label: 'value' }
90349070
}]
90359071
]);

0 commit comments

Comments
 (0)