Skip to content

Commit

Permalink
Merge branch 'v17'
Browse files Browse the repository at this point in the history
  • Loading branch information
Marsup committed Jan 17, 2024
2 parents d2a9082 + e7687b1 commit 9d67652
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 12 deletions.
3 changes: 2 additions & 1 deletion API.md
Original file line number Diff line number Diff line change
Expand Up @@ -2825,8 +2825,9 @@ Requires the string value to be a valid hexadecimal string.

- `options` - optional settings:
- `byteAligned` - Boolean specifying whether you want to check that the hexadecimal string is byte aligned. If `convert` is `true`, a `0` will be added in front of the string in case it needs to be aligned. Defaults to `false`.
- `prefix` - Boolean or `optional`. When `true`, the string will be considered valid if prefixed with `0x` or `0X`. When `false`, the prefix is forbidden. When `optional`, the string will be considered valid if prefixed or not prefixed at all. Defaults to `false`.
```js
const schema = Joi.string().hex();
const schema = Joi.string().hex({ prefix: 'optional' });
```

Possible validation errors: [`string.hex`](#stringhex), [`string.hexAlign`](#stringhexalign)
Expand Down
9 changes: 9 additions & 0 deletions lib/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,15 @@ declare namespace Joi {
* @default false
*/
byteAligned?: boolean;
/**
* controls whether the prefix `0x` or `0X` is allowed (or required) on hex strings.
* When `true`, the prefix must be provided.
* When `false`, the prefix is forbidden.
* When `optional`, the prefix is allowed but not required.
*
* @default false
*/
prefix?: boolean | 'optional';
}

interface IpOptions {
Expand Down
17 changes: 11 additions & 6 deletions lib/types/string.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ const internals = {
},
dataUriRegex: /^data:[\w+.-]+\/[\w+.-]+;((charset=[\w-]+|base64),)?(.*)$/,
hexRegex: {
withPrefix: /^(0x)?[0-9a-f]+$/i,
withoutPrefix: /^[0-9a-f]+$/i
withPrefix: /^0x[0-9a-f]+$/i,
withOptionalPrefix: /^(?:0x)?[0-9a-f]+$/i,
withoutPrefix: /^[0-9a-f]+$/i
},
ipRegex: ipRegex({ cidr: 'forbidden' }).regex,
isoDurationRegex: /^P(?!$)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?$/,
Expand Down Expand Up @@ -367,17 +368,21 @@ module.exports = Any.extend({
hex: {
method(options = {}) {

Common.assertOptions(options, ['byteAligned', 'withPrefix']);
Common.assertOptions(options, ['byteAligned', 'prefix']);

options = { byteAligned: false, withPrefix: false, ...options };
options = { byteAligned: false, prefix: false, ...options };
assert(typeof options.byteAligned === 'boolean', 'byteAligned must be boolean');
assert(typeof options.withPrefix === 'boolean', 'withPrefix must be boolean');
assert(typeof options.prefix === 'boolean' || options.prefix === 'optional', 'prefix must be boolean or "optional"');

return this.$_addRule({ name: 'hex', args: { options } });
},
validate(value, helpers, { options }) {

const re = options.withPrefix ? internals.hexRegex.withPrefix : internals.hexRegex.withoutPrefix;
const re = options.prefix === 'optional' ?
internals.hexRegex.withOptionalPrefix :
options.prefix === true ?
internals.hexRegex.withPrefix :
internals.hexRegex.withoutPrefix;
if (!re.test(value)) {
return helpers.error('string.hex');
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "joi",
"description": "Object schema validation",
"version": "17.11.1",
"version": "17.12.0",
"repository": "git://github.com/hapijs/joi",
"main": "lib/index.js",
"types": "lib/index.d.ts",
Expand Down
88 changes: 84 additions & 4 deletions test/types/string.js
Original file line number Diff line number Diff line change
Expand Up @@ -1215,6 +1215,58 @@ describe('string', () => {
]
});
});

it('describes a hex string', () => {

expect(Joi.string().hex().describe()).to.equal({
type: 'string',
rules: [{
name: 'hex',
args: {
options: {
byteAligned: false,
prefix: false
}
}
}]
});
expect(Joi.string().hex({ byteAligned: true }).describe()).to.equal({
type: 'string',
rules: [{
name: 'hex',
args: {
options: {
byteAligned: true,
prefix: false
}
}
}]
});
expect(Joi.string().hex({ prefix: true }).describe()).to.equal({
type: 'string',
rules: [{
name: 'hex',
args: {
options: {
byteAligned: false,
prefix: true
}
}
}]
});
expect(Joi.string().hex({ prefix: 'optional' }).describe()).to.equal({
type: 'string',
rules: [{
name: 'hex',
args: {
options: {
byteAligned: false,
prefix: 'optional'
}
}
}]
});
});
});

describe('domain()', () => {
Expand Down Expand Up @@ -4521,15 +4573,43 @@ describe('string', () => {

it('validates an hexadecimal string with prefix explicitly required', () => {

const rule = Joi.string().hex({ withPrefix: true }).strict();
const rule = Joi.string().hex({ prefix: true }).strict();
Helper.validate(rule, [
['0123456789abcdef', false, {
message: '"value" must only contain hexadecimal characters',
path: [],
type: 'string.hex',
context: { value: '0123456789abcdef', label: 'value' }
}],
['0x0123456789abcdef', true],
['123456789abcdef', true],
['0123afg', false, {
['0X0123456789abcdef', true]
]);
});

it('validates an hexadecimal string with optional prefix', () => {

const rule = Joi.string().hex({ prefix: 'optional' }).strict();
Helper.validate(rule, [
['0123456789abcdef', true],
['0x0123456789abcdef', true],
['0X0123456789abcdef', true],
['0123456789abcdefg', false, {
message: '"value" must only contain hexadecimal characters',
path: [],
type: 'string.hex',
context: { value: '0123afg', label: 'value' }
context: { value: '0123456789abcdefg', label: 'value' }
}],
['0x0123456789abcdefg', false, {
message: '"value" must only contain hexadecimal characters',
path: [],
type: 'string.hex',
context: { value: '0x0123456789abcdefg', label: 'value' }
}],
['0X0123456789abcdefg', false, {
message: '"value" must only contain hexadecimal characters',
path: [],
type: 'string.hex',
context: { value: '0X0123456789abcdefg', label: 'value' }
}]
]);
});
Expand Down

0 comments on commit 9d67652

Please sign in to comment.