Skip to content

Commit

Permalink
validate hostname, ipv4 and ipv6 formats (microsoft#100)
Browse files Browse the repository at this point in the history
  • Loading branch information
gjsjohnmurray committed Nov 25, 2021
1 parent 386122c commit 583380e
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 1 deletion.
8 changes: 7 additions & 1 deletion src/parser/jsonParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ const formats = {
'date-time': { errorMessage: localize('dateTimeFormatWarning', 'String is not a RFC3339 date-time.'), pattern: /^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|60)(\.[0-9]+)?(Z|(\+|-)([01][0-9]|2[0-3]):([0-5][0-9]))$/i },
'date': { errorMessage: localize('dateFormatWarning', 'String is not a RFC3339 date.'), pattern: /^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/i },
'time': { errorMessage: localize('timeFormatWarning', 'String is not a RFC3339 time.'), pattern: /^([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|60)(\.[0-9]+)?(Z|(\+|-)([01][0-9]|2[0-3]):([0-5][0-9]))$/i },
'email': { errorMessage: localize('emailFormatWarning', 'String is not an e-mail address.'), pattern: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ }
'email': { errorMessage: localize('emailFormatWarning', 'String is not an e-mail address.'), pattern: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ },
'hostname': { errorMessage: localize('hostnameFormatWarning', 'String is not a hostname.'), pattern: /^(?=.{1,253}\.?$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[-0-9a-z]{0,61}[0-9a-z])?)*\.?$/i },
'ipv4': { errorMessage: localize('ipv4FormatWarning', 'String is not an IPv4 address.'), pattern: /^(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$/ },
'ipv6': { errorMessage: localize('ipv6FormatWarning', 'String is not an IPv6 address.'), pattern: /^((([0-9a-f]{1,4}:){7}([0-9a-f]{1,4}|:))|(([0-9a-f]{1,4}:){6}(:[0-9a-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){5}(((:[0-9a-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){4}(((:[0-9a-f]{1,4}){1,3})|((:[0-9a-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){3}(((:[0-9a-f]{1,4}){1,4})|((:[0-9a-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){2}(((:[0-9a-f]{1,4}){1,5})|((:[0-9a-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){1}(((:[0-9a-f]{1,4}){1,6})|((:[0-9a-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9a-f]{1,4}){1,7})|((:[0-9a-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))$/i },
};

export interface IProblem {
Expand Down Expand Up @@ -683,6 +686,9 @@ function validate(n: ASTNode | undefined, schema: JSONSchema, validationResult:
case 'date':
case 'time':
case 'email':
case 'hostname':
case 'ipv4':
case 'ipv6':
const format = formats[schema.format];
if (!node.value || !format.pattern.exec(node.value)) {
validationResult.problems.push({
Expand Down
51 changes: 51 additions & 0 deletions src/test/parser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,57 @@ suite('JSON Parser', () => {
semanticErrors = validate('{"one":"//foo/bar"}', schemaWithURIReference);
assert.strictEqual(semanticErrors!.length, 0, 'uri-reference');

const schemaWithHostname = {
type: 'object',
properties: {
"hostname": {
type: 'string',
format: 'hostname'
}
}
};

semanticErrors = validate('{"hostname":"code.visualstudio.com"}', schemaWithHostname);
assert.strictEqual(semanticErrors!.length, 0, "hostname");

semanticErrors = validate('{"hostname":"foo/bar"}', schemaWithHostname);
assert.strictEqual(semanticErrors!.length, 1, "hostname");
assert.strictEqual(semanticErrors![0].message, 'String is not a hostname.');

const schemaWithIPv4 = {
type: 'object',
properties: {
"hostaddr4": {
type: 'string',
format: 'ipv4'
}
}
};

semanticErrors = validate('{"hostaddr4":"127.0.0.1"}', schemaWithIPv4);
assert.strictEqual(semanticErrors!.length, 0, "hostaddr4");

semanticErrors = validate('{"hostaddr4":"1916:0:0:0:0:F00:1:81AE"}', schemaWithIPv4);
assert.strictEqual(semanticErrors!.length, 1, "hostaddr4");
assert.strictEqual(semanticErrors![0].message, 'String is not an IPv4 address.');

const schemaWithIPv6 = {
type: 'object',
properties: {
"hostaddr6": {
type: 'string',
format: 'ipv6'
}
}
};

semanticErrors = validate('{"hostaddr6":"1916:0:0:0:0:F00:1:81AE"}', schemaWithIPv6);
assert.strictEqual(semanticErrors!.length, 0, "hostaddr6");

semanticErrors = validate('{"hostaddr6":"127.0.0.1"}', schemaWithIPv6);
assert.strictEqual(semanticErrors!.length, 1, "hostaddr6");
assert.strictEqual(semanticErrors![0].message, 'String is not an IPv6 address.');

const schemaWithEMail = {
type: 'object',
properties: {
Expand Down

0 comments on commit 583380e

Please sign in to comment.