@bedrock/validation 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.cjs +12 -0
- package/.github/workflows/main.yml +67 -0
- package/CHANGELOG.md +244 -0
- package/LICENSE.md +115 -0
- package/README.md +92 -0
- package/lib/Cache.js +24 -0
- package/lib/config.js +18 -0
- package/lib/index.js +250 -0
- package/lib/logger.js +5 -0
- package/package.json +41 -0
- package/schemas/comment.js +24 -0
- package/schemas/credential.js +37 -0
- package/schemas/description.js +24 -0
- package/schemas/email.js +34 -0
- package/schemas/identifier.js +22 -0
- package/schemas/jsonPatch.js +38 -0
- package/schemas/jsonldContext.js +54 -0
- package/schemas/jsonldType.js +72 -0
- package/schemas/label.js +25 -0
- package/schemas/linkedDataSignature.js +46 -0
- package/schemas/linkedDataSignature2018.js +58 -0
- package/schemas/linkedDataSignature2020.js +42 -0
- package/schemas/nonce.js +25 -0
- package/schemas/personName.js +25 -0
- package/schemas/privateKeyPem.js +23 -0
- package/schemas/publicKeyPem.js +23 -0
- package/schemas/sequencedPatch.js +31 -0
- package/schemas/slug.js +27 -0
- package/schemas/title.js +25 -0
- package/schemas/url.js +22 -0
- package/schemas/w3cDateTime.js +24 -0
- package/test/mocha/.eslintrc +9 -0
- package/test/mocha/001-schemas.js +1157 -0
- package/test/mocha/mock.data.js +45 -0
- package/test/package.json +28 -0
- package/test/test.config.js +10 -0
- package/test/test.js +8 -0
package/lib/index.js
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2012-2022 Digital Bazaar, Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
import * as bedrock from '@bedrock/core';
|
|
5
|
+
import Ajv from 'ajv';
|
|
6
|
+
import {Cache} from './Cache.js';
|
|
7
|
+
import {promises as fs} from 'fs';
|
|
8
|
+
import {logger} from './logger.js';
|
|
9
|
+
import PATH from 'path';
|
|
10
|
+
|
|
11
|
+
const ajv = new Ajv({cache: new Cache(), serialize: false, verbose: true});
|
|
12
|
+
const {util: {BedrockError}} = bedrock;
|
|
13
|
+
|
|
14
|
+
// load config defaults
|
|
15
|
+
import './config.js';
|
|
16
|
+
|
|
17
|
+
// available schemas
|
|
18
|
+
export const schemas = {};
|
|
19
|
+
|
|
20
|
+
bedrock.events.on('bedrock.init', init);
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Initializes the validation system: loads all schemas, etc.
|
|
24
|
+
*/
|
|
25
|
+
async function init() {
|
|
26
|
+
// schemas to skip loading
|
|
27
|
+
const skip = bedrock.config.validation.schema.skip.slice();
|
|
28
|
+
|
|
29
|
+
// load all schemas in directory order
|
|
30
|
+
const schemaDirs = bedrock.config.validation.schema.paths;
|
|
31
|
+
const jsExt = '.js';
|
|
32
|
+
for(let schemaDir of schemaDirs) {
|
|
33
|
+
schemaDir = PATH.resolve(schemaDir);
|
|
34
|
+
logger.debug('loading schemas from: ' + schemaDir);
|
|
35
|
+
const files = (await fs.readdir(schemaDir)).filter(file => {
|
|
36
|
+
const js = PATH.extname(file) === jsExt;
|
|
37
|
+
const use = skip.indexOf(file) === -1;
|
|
38
|
+
return js && use;
|
|
39
|
+
});
|
|
40
|
+
// load files in parallel
|
|
41
|
+
await Promise.all(files.map(async file => {
|
|
42
|
+
const name = PATH.basename(file, PATH.extname(file));
|
|
43
|
+
const module = await import(PATH.join(schemaDir, file));
|
|
44
|
+
const api = module.default || module;
|
|
45
|
+
if(typeof api === 'function') {
|
|
46
|
+
if(name in schemas) {
|
|
47
|
+
logger.debug(
|
|
48
|
+
'overwriting schema "' + name + '" with ' +
|
|
49
|
+
PATH.resolve(schemaDir, file));
|
|
50
|
+
}
|
|
51
|
+
schemas[name] = api;
|
|
52
|
+
schemas[name].instance = api();
|
|
53
|
+
logger.debug('loaded schema: ' + name);
|
|
54
|
+
} else {
|
|
55
|
+
for(const key in api) {
|
|
56
|
+
const tmp = name + '.' + key;
|
|
57
|
+
if(tmp in schemas) {
|
|
58
|
+
logger.debug('overwriting schema "' + tmp + '" with ' + file);
|
|
59
|
+
}
|
|
60
|
+
schemas[tmp] = api[key];
|
|
61
|
+
schemas[tmp].instance = schemas[tmp]();
|
|
62
|
+
logger.debug('loaded schema: ' + tmp);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Compiles the given schema, returning a validation function that takes one
|
|
71
|
+
* parameter: the data to be validated. It returns the same value that
|
|
72
|
+
* `validateInstance` returns.
|
|
73
|
+
*
|
|
74
|
+
* @param {object} options - The options to use.
|
|
75
|
+
* @param {object} options.schema - The JSON schema to compile.
|
|
76
|
+
*
|
|
77
|
+
* @returns {Function} The a validate function to call on instance data.
|
|
78
|
+
*/
|
|
79
|
+
export function compile({schema} = {}) {
|
|
80
|
+
const fn = ajv.compile(schema);
|
|
81
|
+
fn.title = schema.title;
|
|
82
|
+
return function validate(instance) {
|
|
83
|
+
if(fn(instance)) {
|
|
84
|
+
return {valid: true};
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
valid: false,
|
|
88
|
+
error: _createError({schema: fn, instance})
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Retrieves a validation schema given a name for the schema.
|
|
95
|
+
*
|
|
96
|
+
* @param {object} options - The options to use.
|
|
97
|
+
* @param {string} options.name - The name of the schema to retrieve.
|
|
98
|
+
*
|
|
99
|
+
* @returns {object|null} The object for the schema, or `null` if the schema
|
|
100
|
+
* doesn't exist.
|
|
101
|
+
*/
|
|
102
|
+
export function getSchema({name} = {}) {
|
|
103
|
+
let schema = null;
|
|
104
|
+
if(name in schemas) {
|
|
105
|
+
schema = schemas[name].instance;
|
|
106
|
+
}
|
|
107
|
+
return schema;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Validates an instance against a schema.
|
|
112
|
+
*
|
|
113
|
+
* @param {object} options - The options to use.
|
|
114
|
+
* @param {*} options.instance - The instance to validate.
|
|
115
|
+
* @param {object|Array|Function|string} [options.schema] - The JSON schema,
|
|
116
|
+
* compiled schema function, or name of schema to use.
|
|
117
|
+
*
|
|
118
|
+
* @returns {object} The validation result.
|
|
119
|
+
*/
|
|
120
|
+
export function validateInstance({instance, schema} = {}) {
|
|
121
|
+
const schemaIsFunction = typeof schema === 'function';
|
|
122
|
+
|
|
123
|
+
// do validation
|
|
124
|
+
let valid;
|
|
125
|
+
if(schemaIsFunction) {
|
|
126
|
+
valid = schema(instance);
|
|
127
|
+
} else {
|
|
128
|
+
if(typeof schema === 'string') {
|
|
129
|
+
const name = schema;
|
|
130
|
+
schema = getSchema({name});
|
|
131
|
+
if(!schema) {
|
|
132
|
+
throw new BedrockError(
|
|
133
|
+
`Could not validate data; unknown schema name (${name}).`,
|
|
134
|
+
'NotFoundError', {schemaName: name});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
valid = ajv.validate(schema, instance);
|
|
138
|
+
}
|
|
139
|
+
if(valid) {
|
|
140
|
+
return {valid};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const result = {
|
|
144
|
+
valid: false,
|
|
145
|
+
error: _createError({schema, instance})
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
return result;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Creates middleware that will validate request body and URL query parameters.
|
|
153
|
+
*
|
|
154
|
+
* Use this method over the deprecated `validate` to create a middleware.
|
|
155
|
+
*
|
|
156
|
+
* @param {object} options - The options to use.
|
|
157
|
+
* @param {object} [options.bodySchema] - The JSON schema to use to validate
|
|
158
|
+
* the request body.
|
|
159
|
+
* @param {object} [options.querySchema] - The JSON schema to use to validate
|
|
160
|
+
* the request URL query parameters.
|
|
161
|
+
*
|
|
162
|
+
* @returns {Function} An express-style middleware.
|
|
163
|
+
*/
|
|
164
|
+
export function createValidateMiddleware({bodySchema, querySchema} = {}) {
|
|
165
|
+
if(!(bodySchema || querySchema)) {
|
|
166
|
+
throw new TypeError(
|
|
167
|
+
'One of the following parameters is required: ' +
|
|
168
|
+
'"bodySchema", "querySchema".');
|
|
169
|
+
}
|
|
170
|
+
// pre-compile schemas
|
|
171
|
+
let validateBodySchema;
|
|
172
|
+
if(bodySchema) {
|
|
173
|
+
validateBodySchema = compile({schema: bodySchema});
|
|
174
|
+
}
|
|
175
|
+
let validateQuerySchema;
|
|
176
|
+
if(querySchema) {
|
|
177
|
+
validateQuerySchema = compile({schema: querySchema});
|
|
178
|
+
}
|
|
179
|
+
return function validate(req, res, next) {
|
|
180
|
+
if(validateBodySchema) {
|
|
181
|
+
const result = validateBodySchema(req.body);
|
|
182
|
+
if(!result.valid) {
|
|
183
|
+
return next(result.error);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if(validateQuerySchema) {
|
|
187
|
+
const result = validateQuerySchema(req.query);
|
|
188
|
+
if(!result.valid) {
|
|
189
|
+
return next(result.error);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
next();
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function _createError({schema, instance}) {
|
|
197
|
+
// create public error messages
|
|
198
|
+
const schemaIsFunction = typeof schema === 'function';
|
|
199
|
+
const validationErrors = schemaIsFunction ? schema.errors : ajv.errors;
|
|
200
|
+
const errors = [];
|
|
201
|
+
for(const error of validationErrors) {
|
|
202
|
+
// create custom error details
|
|
203
|
+
const details = {
|
|
204
|
+
instance,
|
|
205
|
+
params: error.params,
|
|
206
|
+
path: error.dataPath,
|
|
207
|
+
public: true,
|
|
208
|
+
schemaPath: error.schemaPath,
|
|
209
|
+
};
|
|
210
|
+
let title;
|
|
211
|
+
if(Array.isArray(error.schema)) {
|
|
212
|
+
[title] = error.schema;
|
|
213
|
+
}
|
|
214
|
+
title = title || error.parentSchema.title || '',
|
|
215
|
+
details.schema = {
|
|
216
|
+
description: error.parentSchema.description || '',
|
|
217
|
+
title,
|
|
218
|
+
};
|
|
219
|
+
// include custom errors or use default
|
|
220
|
+
// FIXME: enable if ajv supports this parentSchema.errors property
|
|
221
|
+
// it appears that this is not the case
|
|
222
|
+
// details.errors = error.parentSchema.errors || {
|
|
223
|
+
// invalid: 'Invalid input.',
|
|
224
|
+
// missing: 'Missing input.'
|
|
225
|
+
// };
|
|
226
|
+
if(error.data) {
|
|
227
|
+
if(error.parentSchema.errors && 'mask' in error.parentSchema.errors) {
|
|
228
|
+
const mask = error.parentSchema.errors.mask;
|
|
229
|
+
if(mask === true) {
|
|
230
|
+
details.value = '***MASKED***';
|
|
231
|
+
} else {
|
|
232
|
+
details.value = mask;
|
|
233
|
+
}
|
|
234
|
+
} else {
|
|
235
|
+
details.value = error.data;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// add bedrock validation error
|
|
240
|
+
errors.push(new BedrockError(error.message, 'ValidationError', details));
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const msg = schema.title ?
|
|
244
|
+
'A validation error occured in the \'' + schema.title + '\' validator.' :
|
|
245
|
+
'A validation error occured in an unnamed validator.';
|
|
246
|
+
const error = new BedrockError(
|
|
247
|
+
msg, 'ValidationError', {public: true, errors, httpStatusCode: 400});
|
|
248
|
+
|
|
249
|
+
return error;
|
|
250
|
+
}
|
package/lib/logger.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bedrock/validation",
|
|
3
|
+
"version": "6.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Bedrock validation",
|
|
6
|
+
"main": "./lib/index.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"lint": "eslint ."
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/digitalbazaar/bedrock-validation"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"bedrock"
|
|
16
|
+
],
|
|
17
|
+
"author": {
|
|
18
|
+
"name": "Digital Bazaar, Inc.",
|
|
19
|
+
"email": "support@digitalbazaar.com",
|
|
20
|
+
"url": "http://digitalbazaar.com"
|
|
21
|
+
},
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/digitalbazaar/bedrock-validation/issues"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://github.com/digitalbazaar/bedrock-validation",
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"ajv": "^6.12.0"
|
|
28
|
+
},
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"@bedrock/core": "^5.0.0"
|
|
31
|
+
},
|
|
32
|
+
"directories": {
|
|
33
|
+
"lib": "./lib"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"eslint": "^7.32.0",
|
|
37
|
+
"eslint-config-digitalbazaar": "^2.8.0",
|
|
38
|
+
"eslint-plugin-jsdoc": "^37.9.7",
|
|
39
|
+
"jsdoc-to-markdown": "^6.0.1"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2012-2022 Digital Bazaar, Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
import * as bedrock from '@bedrock/core';
|
|
5
|
+
|
|
6
|
+
const schema = {
|
|
7
|
+
title: 'Comment',
|
|
8
|
+
description: 'A short comment.',
|
|
9
|
+
type: 'string',
|
|
10
|
+
minLength: 1,
|
|
11
|
+
maxLength: 5000,
|
|
12
|
+
errors: {
|
|
13
|
+
invalid: 'The comment contains invalid characters or is more than ' +
|
|
14
|
+
'5000 characters in length.',
|
|
15
|
+
missing: 'Please enter a comment.'
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default function(extend) {
|
|
20
|
+
if(extend) {
|
|
21
|
+
return bedrock.util.extend(true, bedrock.util.clone(schema), extend);
|
|
22
|
+
}
|
|
23
|
+
return schema;
|
|
24
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2012-2022 Digital Bazaar, Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
import * as bedrock from '@bedrock/core';
|
|
5
|
+
import identifier from './identifier.js';
|
|
6
|
+
import jsonldContext from './jsonldContext.js';
|
|
7
|
+
import w3cDateTime from './w3cDateTime.js';
|
|
8
|
+
|
|
9
|
+
// TODO: Improve this schema
|
|
10
|
+
const schema = {
|
|
11
|
+
type: 'object',
|
|
12
|
+
title: 'Credential',
|
|
13
|
+
properties: {
|
|
14
|
+
'@context': jsonldContext(),
|
|
15
|
+
// FIXME: improve credential context check
|
|
16
|
+
//'@context': schemas.jsonldContext([
|
|
17
|
+
// constants.IDENTITY_CONTEXT_V1_URL,
|
|
18
|
+
// constants.CREDENTIALS_CONTEXT_V1_URL
|
|
19
|
+
//]),
|
|
20
|
+
issuer: identifier(),
|
|
21
|
+
issued: w3cDateTime(),
|
|
22
|
+
claim: {
|
|
23
|
+
required: ['id'],
|
|
24
|
+
properties: {
|
|
25
|
+
id: identifier()
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
required: ['issuer', 'issued', 'claim']
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export default function(extend) {
|
|
33
|
+
if(extend) {
|
|
34
|
+
return bedrock.util.extend(true, bedrock.util.clone(schema), extend);
|
|
35
|
+
}
|
|
36
|
+
return schema;
|
|
37
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2012-2022 Digital Bazaar, Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
import * as bedrock from '@bedrock/core';
|
|
5
|
+
|
|
6
|
+
const schema = {
|
|
7
|
+
title: 'Description',
|
|
8
|
+
description: 'A description.',
|
|
9
|
+
type: 'string',
|
|
10
|
+
minLength: 0,
|
|
11
|
+
maxLength: 5000,
|
|
12
|
+
errors: {
|
|
13
|
+
invalid: 'The description contains invalid characters or is more than ' +
|
|
14
|
+
'5000 characters in length.',
|
|
15
|
+
missing: 'Please enter a description.'
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default function(extend) {
|
|
20
|
+
if(extend) {
|
|
21
|
+
return bedrock.util.extend(true, bedrock.util.clone(schema), extend);
|
|
22
|
+
}
|
|
23
|
+
return schema;
|
|
24
|
+
}
|
package/schemas/email.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2012-2022 Digital Bazaar, Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
import * as bedrock from '@bedrock/core';
|
|
5
|
+
|
|
6
|
+
// RFC 1034 - All labels have a max length of 63 octets.
|
|
7
|
+
// https://tools.ietf.org/html/rfc1034#section-3.1
|
|
8
|
+
const schema = {
|
|
9
|
+
title: 'Email',
|
|
10
|
+
description: 'An email address.',
|
|
11
|
+
type: 'string',
|
|
12
|
+
// eslint-disable-next-line max-len
|
|
13
|
+
pattern: '^[-a-z0-9~!$%^&*_=+}{\\\'?]+(\\.[-a-z0-9~!$%^&*_=+}{\\\'?]+)*@(((([a-z0-9]{1}[a-z0-9\\-]{0,63}[a-z0-9]{1})|[a-z])\\.)+[a-z]{2,63})$',
|
|
14
|
+
minLength: 1,
|
|
15
|
+
maxLength: 100,
|
|
16
|
+
errors: {
|
|
17
|
+
invalid: 'The email address is invalid.',
|
|
18
|
+
missing: 'Please enter an email address.'
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default function(extend, options) {
|
|
23
|
+
if(options && options.lowerCaseOnly) {
|
|
24
|
+
extend = extend || {};
|
|
25
|
+
if(!('pattern' in extend)) {
|
|
26
|
+
// eslint-disable-next-line max-len
|
|
27
|
+
extend.pattern = '^[-a-z0-9~!$%^&*_=+}{\\\'?]+(\\.[-a-z0-9~!$%^&*_=+}{\\\'?]+)*@(((([a-z0-9]{1}[a-z0-9\\-]{0,63}[a-z0-9]{1})|[a-z])\\.)+[a-z]{2,63})$';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if(extend) {
|
|
31
|
+
return bedrock.util.extend(true, bedrock.util.clone(schema), extend);
|
|
32
|
+
}
|
|
33
|
+
return schema;
|
|
34
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2012-2022 Digital Bazaar, Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
import * as bedrock from '@bedrock/core';
|
|
5
|
+
|
|
6
|
+
const schema = {
|
|
7
|
+
title: 'ID',
|
|
8
|
+
description: 'A unique identifier.',
|
|
9
|
+
type: 'string',
|
|
10
|
+
minLength: 1,
|
|
11
|
+
disallow: {
|
|
12
|
+
type: 'string',
|
|
13
|
+
enum: ['0']
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default function(extend) {
|
|
18
|
+
if(extend) {
|
|
19
|
+
return bedrock.util.extend(true, bedrock.util.clone(schema), extend);
|
|
20
|
+
}
|
|
21
|
+
return schema;
|
|
22
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2019-2022 Digital Bazaar, Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
import * as bedrock from '@bedrock/core';
|
|
5
|
+
|
|
6
|
+
const schema = {
|
|
7
|
+
title: 'JSON Patch',
|
|
8
|
+
type: 'array',
|
|
9
|
+
minItems: 1,
|
|
10
|
+
items: {
|
|
11
|
+
type: 'object',
|
|
12
|
+
required: ['op', 'path'],
|
|
13
|
+
// FIXME: more strictly validate properties based on value of `op`
|
|
14
|
+
properties: {
|
|
15
|
+
op: {
|
|
16
|
+
type: 'string',
|
|
17
|
+
enum: ['add', 'copy', 'move', 'remove', 'replace', 'test']
|
|
18
|
+
},
|
|
19
|
+
from: {
|
|
20
|
+
type: 'string',
|
|
21
|
+
},
|
|
22
|
+
path: {
|
|
23
|
+
type: 'string',
|
|
24
|
+
},
|
|
25
|
+
value: {
|
|
26
|
+
//type: ['number', 'string', 'boolean', 'object', 'array'],
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
additionalProperties: false
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export default function(extend) {
|
|
34
|
+
if(extend) {
|
|
35
|
+
return bedrock.util.extend(true, bedrock.util.clone(schema), extend);
|
|
36
|
+
}
|
|
37
|
+
return schema;
|
|
38
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2012-2022 Digital Bazaar, Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
import * as bedrock from '@bedrock/core';
|
|
5
|
+
|
|
6
|
+
export default function(context, extend) {
|
|
7
|
+
const schema = {
|
|
8
|
+
title: 'JSON-LD context',
|
|
9
|
+
description: 'A JSON-LD Context'
|
|
10
|
+
};
|
|
11
|
+
if(!Array.isArray(context)) {
|
|
12
|
+
schema.anyOf = [{
|
|
13
|
+
type: 'string'
|
|
14
|
+
// enum added below if context param truthy
|
|
15
|
+
}, {
|
|
16
|
+
type: 'object'
|
|
17
|
+
// FIXME: improve context object validator
|
|
18
|
+
}, {
|
|
19
|
+
type: 'array',
|
|
20
|
+
// items added below if context param truthy
|
|
21
|
+
}];
|
|
22
|
+
if(context) {
|
|
23
|
+
schema.anyOf[0].enum = [context];
|
|
24
|
+
schema.anyOf[2].items = [{const: context}];
|
|
25
|
+
schema.anyOf[2].additionalItems = false;
|
|
26
|
+
}
|
|
27
|
+
} else {
|
|
28
|
+
Object.assign(schema, {
|
|
29
|
+
type: 'array',
|
|
30
|
+
minItems: context.length,
|
|
31
|
+
uniqueItems: true,
|
|
32
|
+
items: [],
|
|
33
|
+
errors: {
|
|
34
|
+
invalid: 'The JSON-LD context information is invalid.',
|
|
35
|
+
missing: 'The JSON-LD context information is missing.'
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
for(let i = 0; i < context.length; ++i) {
|
|
39
|
+
if(typeof context[i] === 'string') {
|
|
40
|
+
schema.items.push({
|
|
41
|
+
type: 'string',
|
|
42
|
+
enum: [context[i]]
|
|
43
|
+
});
|
|
44
|
+
} else {
|
|
45
|
+
// FIXME: improve context object validator
|
|
46
|
+
schema.items.push({type: 'object'});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if(extend) {
|
|
51
|
+
return bedrock.util.extend(true, bedrock.util.clone(schema), extend);
|
|
52
|
+
}
|
|
53
|
+
return schema;
|
|
54
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2012-2022 Digital Bazaar, Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
export default function(types, alternates) {
|
|
5
|
+
const schema = {
|
|
6
|
+
title: 'Object Type',
|
|
7
|
+
description: 'A set of terms, CURIEs, or URLs specifying the type of ' +
|
|
8
|
+
'the object.',
|
|
9
|
+
anyOf: []
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
types = Array.isArray(types) ? types : [types];
|
|
13
|
+
|
|
14
|
+
// allow single object
|
|
15
|
+
if(types.length === 1) {
|
|
16
|
+
schema.anyOf.push({
|
|
17
|
+
type: 'string',
|
|
18
|
+
enum: types,
|
|
19
|
+
errors: {
|
|
20
|
+
invalid: 'The JSON-LD type information is invalid.',
|
|
21
|
+
missing: 'The JSON-LD type information is missing.'
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// allow array combination of all types
|
|
27
|
+
schema.anyOf.push({
|
|
28
|
+
type: 'array',
|
|
29
|
+
// minItems: types.length,
|
|
30
|
+
uniqueItems: true,
|
|
31
|
+
items: {
|
|
32
|
+
type: 'string',
|
|
33
|
+
enum: types
|
|
34
|
+
},
|
|
35
|
+
errors: {
|
|
36
|
+
invalid: 'The JSON-LD type information is invalid.',
|
|
37
|
+
missing: 'The JSON-LD type information is missing.'
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// HACK: madness to support given types *must* exist, while allowing
|
|
42
|
+
// up to <alternates> other custom types
|
|
43
|
+
if(alternates !== undefined) {
|
|
44
|
+
for(let before = 0; before <= alternates; ++before) {
|
|
45
|
+
const s = {
|
|
46
|
+
type: 'array',
|
|
47
|
+
minItems: types.length,
|
|
48
|
+
uniqueItems: true,
|
|
49
|
+
items: [],
|
|
50
|
+
additionalItems: {
|
|
51
|
+
type: 'string'
|
|
52
|
+
},
|
|
53
|
+
errors: {
|
|
54
|
+
invalid: 'The JSON-LD type information is invalid.',
|
|
55
|
+
missing: 'The JSON-LD type information is missing.'
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
for(let i = 0; i < before; ++i) {
|
|
59
|
+
s.items.push({type: 'string'});
|
|
60
|
+
}
|
|
61
|
+
for(let i = 0; i < types.length; ++i) {
|
|
62
|
+
s.items.push({
|
|
63
|
+
type: 'string',
|
|
64
|
+
enum: types
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
schema.anyOf.push(s);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return schema;
|
|
72
|
+
}
|
package/schemas/label.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2012-2022 Digital Bazaar, Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
import * as bedrock from '@bedrock/core';
|
|
5
|
+
|
|
6
|
+
const schema = {
|
|
7
|
+
title: 'Label',
|
|
8
|
+
description: 'A short, descriptive label.',
|
|
9
|
+
type: 'string',
|
|
10
|
+
pattern: '^[-a-zA-Z0-9~`!@#$%^&*\\(\\)\\[\\]{}<>_=+\\\\|:;\'"\\.,/? ]*$',
|
|
11
|
+
minLength: 1,
|
|
12
|
+
maxLength: 200,
|
|
13
|
+
errors: {
|
|
14
|
+
invalid: 'The label contains invalid characters or is not between ' +
|
|
15
|
+
'1 and 200 characters in length.',
|
|
16
|
+
missing: 'Please enter a label.'
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default function(extend) {
|
|
21
|
+
if(extend) {
|
|
22
|
+
return bedrock.util.extend(true, bedrock.util.clone(schema), extend);
|
|
23
|
+
}
|
|
24
|
+
return schema;
|
|
25
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2012-2022 Digital Bazaar, Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
import * as bedrock from '@bedrock/core';
|
|
5
|
+
import identifier from './identifier.js';
|
|
6
|
+
import w3cDateTime from './w3cDateTime.js';
|
|
7
|
+
|
|
8
|
+
const signature = {
|
|
9
|
+
title: 'Linked Data Signature',
|
|
10
|
+
description: 'A Linked Data digital signature.',
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
id: identifier(),
|
|
14
|
+
type: {
|
|
15
|
+
title: 'Linked Data Signature Type',
|
|
16
|
+
type: 'string',
|
|
17
|
+
enum: ['LinkedDataSignature2015', 'LinkedDataSignature2016']
|
|
18
|
+
},
|
|
19
|
+
creator: identifier(),
|
|
20
|
+
created: w3cDateTime(),
|
|
21
|
+
signatureValue: {
|
|
22
|
+
title: 'Digital Signature Value',
|
|
23
|
+
description: 'The Base64 encoding of the result of the signature ' +
|
|
24
|
+
'algorithm.',
|
|
25
|
+
type: 'string'
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
// NOTE: id is not required
|
|
29
|
+
required: ['type', 'creator', 'created', 'signatureValue']
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const schema = {
|
|
33
|
+
title: 'Linked Data Signatures',
|
|
34
|
+
anyOf: [{
|
|
35
|
+
type: 'array',
|
|
36
|
+
items: signature,
|
|
37
|
+
minItems: 1,
|
|
38
|
+
}, signature]
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export default function(extend) {
|
|
42
|
+
if(extend) {
|
|
43
|
+
return bedrock.util.extend(true, bedrock.util.clone(schema), extend);
|
|
44
|
+
}
|
|
45
|
+
return schema;
|
|
46
|
+
}
|