@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.
@@ -0,0 +1,1157 @@
1
+ /*!
2
+ * Copyright (c) 2012-2022 Digital Bazaar, Inc. All rights reserved.
3
+ */
4
+ import * as validation from '@bedrock/validation';
5
+ import {mock} from './mock.data.js';
6
+
7
+ const {validateInstance} = validation;
8
+
9
+ const expect = global.chai.expect;
10
+
11
+ describe('bedrock-validation', function() {
12
+ describe('invalid schema specified', function() {
13
+ it('should throw an error', function() {
14
+ expect(function() {
15
+ validateInstance({
16
+ instance: {some: 'object'}, schema: 'test-unknown-schema'
17
+ });
18
+ }).to.throw('Could not validate data; unknown schema name ' +
19
+ '(test-unknown-schema).');
20
+ });
21
+ });
22
+
23
+ describe('comment', function() {
24
+ const schema = validation.getSchema({name: 'comment'});
25
+ const validate = validation.compile({schema});
26
+ it('should be an Object', function() {
27
+ schema.should.be.an.instanceof(Object);
28
+ });
29
+ it('should reject empty comments', function() {
30
+ const result = validateInstance(
31
+ {instance: '', schema: 'comment'});
32
+ result.valid.should.be.false;
33
+ });
34
+ it('should reject empty comments w/compiled schema', function() {
35
+ const result = validate('');
36
+ result.valid.should.be.false;
37
+ });
38
+ it('should reject comments that are too long', function() {
39
+ const tmp = '12345678901234567890123456789012345678901234567890';
40
+ const max = schema.maxLength / tmp.length;
41
+ let str = '';
42
+ for(let i = 0; i < max; ++i) {
43
+ str += tmp;
44
+ }
45
+ const result = validateInstance(
46
+ {instance: str + '0', schema: 'comment'});
47
+ result.valid.should.be.false;
48
+ });
49
+ it('should accept valid comments', function() {
50
+ const small = validateInstance({instance: '1', schema: 'comment'});
51
+ should.not.exist(small.error);
52
+ small.valid.should.be.true;
53
+ const tmp = '12345678901234567890123456789012345678901234567890';
54
+ const max = schema.maxLength / tmp.length;
55
+ let str = '';
56
+ for(let i = 0; i < max; ++i) {
57
+ str += tmp;
58
+ }
59
+ const large = validateInstance({instance: str, schema: 'comment'});
60
+ large.valid.should.be.true;
61
+ });
62
+ it('should accept valid comments w/compiled schema', function() {
63
+ const small = validate('1');
64
+ should.not.exist(small.error);
65
+ small.valid.should.be.true;
66
+ const tmp = '12345678901234567890123456789012345678901234567890';
67
+ const max = schema.maxLength / tmp.length;
68
+ let str = '';
69
+ for(let i = 0; i < max; ++i) {
70
+ str += tmp;
71
+ }
72
+ const large = validate(str);
73
+ large.valid.should.be.true;
74
+ });
75
+ it('should accept normal non-letter symbols', function() {
76
+ const result = validateInstance({
77
+ instance: '-a-zA-Z0-9~!@#$%^&*()_=+\\|{}[];:\'"<>,./? ',
78
+ schema: 'comment'
79
+ });
80
+ result.valid.should.be.true;
81
+ });
82
+ it('should throw a "NotFoundError" error when schema does not exist',
83
+ function() {
84
+ let result;
85
+ let err;
86
+
87
+ try {
88
+ result = validateInstance({instance: {}, schema: 'test'});
89
+ } catch(e) {
90
+ err = e;
91
+ }
92
+
93
+ should.exist(err);
94
+ should.not.exist(result);
95
+ err.name.should.equal('NotFoundError');
96
+ });
97
+ it('should raise a body ValidationError via middleware', done => {
98
+ const req = {
99
+ body: ''
100
+ };
101
+ const res = {};
102
+ const next = function(err) {
103
+ should.exist(err);
104
+ err.name.should.equal('ValidationError');
105
+ done();
106
+ };
107
+
108
+ const bodySchema = validation.getSchema({name: 'comment'});
109
+ const middleware = validation.createValidateMiddleware({bodySchema});
110
+ middleware(req, res, next);
111
+ });
112
+ it('should raise a query ValidationError via middleware', done => {
113
+ const req = {
114
+ query: ''
115
+ };
116
+ const res = {};
117
+ const next = function(err) {
118
+ should.exist(err);
119
+ err.name.should.equal('ValidationError');
120
+ done();
121
+ };
122
+
123
+ const querySchema = validation.getSchema({name: 'comment'});
124
+ const middleware = validation.createValidateMiddleware({querySchema});
125
+ middleware(req, res, next);
126
+ });
127
+ it('should pass body validation via middleware', done => {
128
+ const req = {
129
+ body: 'comment'
130
+ };
131
+ const res = {};
132
+ const next = function(err) {
133
+ should.not.exist(err);
134
+ done();
135
+ };
136
+
137
+ const bodySchema = validation.getSchema({name: 'comment'});
138
+ const middleware = validation.createValidateMiddleware({bodySchema});
139
+ middleware(req, res, next);
140
+ });
141
+ it('should pass query validation via middleware', done => {
142
+ const req = {
143
+ query: 'comment'
144
+ };
145
+ const res = {};
146
+ const next = function(err) {
147
+ should.not.exist(err);
148
+ done();
149
+ };
150
+
151
+ const querySchema = validation.getSchema({name: 'comment'});
152
+ const middleware = validation.createValidateMiddleware({querySchema});
153
+ middleware(req, res, next);
154
+ });
155
+ it('should accept valid comment with extend', function() {
156
+ const extend = {name: 'test'};
157
+ const schema = validation.schemas.comment(extend);
158
+ const result = validateInstance({instance: 'test comment', schema});
159
+ schema.name.should.equal('test');
160
+ result.valid.should.be.true;
161
+ });
162
+ });
163
+
164
+ describe('description', function() {
165
+ const schema = validation.getSchema({name: 'description'});
166
+ it('should be an Object', function() {
167
+ schema.should.be.an.instanceof(Object);
168
+ });
169
+ it('should accept valid description', function() {
170
+ const result = validateInstance({
171
+ instance: 'test description',
172
+ schema: 'description'
173
+ });
174
+ result.valid.should.be.true;
175
+ });
176
+ it('should reject an invalid description', function() {
177
+ const result = validateInstance({
178
+ instance: {},
179
+ schema: 'description'
180
+ });
181
+ result.valid.should.be.false;
182
+ });
183
+ it('should accept valid description with extend', function() {
184
+ const extend = {name: 'test'};
185
+ const schema = validation.schemas.description(extend);
186
+ const result = validateInstance({
187
+ instance: 'test description',
188
+ schema
189
+ });
190
+ schema.name.should.equal('test');
191
+ result.valid.should.be.true;
192
+ });
193
+ });
194
+
195
+ describe('identifier', function() {
196
+ const schema = validation.getSchema({name: 'identifier'});
197
+ it('should be an Object', function() {
198
+ schema.should.be.an.instanceof(Object);
199
+ });
200
+ it('should accept valid identifier', function() {
201
+ const result = validateInstance({
202
+ instance: '1234',
203
+ schema: 'identifier'
204
+ });
205
+ result.valid.should.be.true;
206
+ });
207
+ it('should reject an invalid identifier', function() {
208
+ const result = validateInstance({
209
+ instance: '',
210
+ schema: 'identifier'
211
+ });
212
+ result.valid.should.be.false;
213
+ });
214
+ it('should accept valid identifier with extend', function() {
215
+ const extend = {name: 'test'};
216
+ const schema = validation.schemas.identifier(extend);
217
+ const result = validateInstance({
218
+ instance: '1234',
219
+ schema
220
+ });
221
+ schema.name.should.equal('test');
222
+ result.valid.should.be.true;
223
+ });
224
+ });
225
+
226
+ describe('label', function() {
227
+ const schema = validation.getSchema({name: 'label'});
228
+ it('should be an Object', function() {
229
+ schema.should.be.an.instanceof(Object);
230
+ });
231
+ it('should accept valid label', function() {
232
+ const result = validateInstance({
233
+ instance: 'test label',
234
+ schema: 'label'
235
+ });
236
+ result.valid.should.be.true;
237
+ });
238
+ it('should reject an invalid label', function() {
239
+ const result = validateInstance({
240
+ instance: {},
241
+ schema: 'label'
242
+ });
243
+ result.valid.should.be.false;
244
+ });
245
+ it('should accept valid label with extend', function() {
246
+ const extend = {name: 'test'};
247
+ const schema = validation.schemas.label(extend);
248
+ const result = validateInstance({
249
+ instance: 'test label',
250
+ schema
251
+ });
252
+ schema.name.should.equal('test');
253
+ result.valid.should.be.true;
254
+ });
255
+ });
256
+
257
+ describe('title', function() {
258
+ const schema = validation.getSchema({name: 'title'});
259
+ it('should be an Object', function() {
260
+ schema.should.be.an.instanceof(Object);
261
+ });
262
+ it('should accept valid title', function() {
263
+ const result = validateInstance({
264
+ instance: 'Test Title',
265
+ schema: 'title'
266
+ });
267
+ result.valid.should.be.true;
268
+ });
269
+ it('should reject an invalid title', function() {
270
+ const result = validateInstance({
271
+ instance: {},
272
+ schema: 'title'
273
+ });
274
+ result.valid.should.be.false;
275
+ });
276
+ it('should accept valid title with extend', function() {
277
+ const extend = {name: 'test'};
278
+ const schema = validation.schemas.title(extend);
279
+ const result = validateInstance({
280
+ instance: 'Test Title',
281
+ schema
282
+ });
283
+ schema.name.should.equal('test');
284
+ result.valid.should.be.true;
285
+ });
286
+ });
287
+
288
+ describe('url', function() {
289
+ const schema = validation.getSchema({name: 'url'});
290
+ it('should be an Object', function() {
291
+ schema.should.be.an.instanceof(Object);
292
+ });
293
+ it('should accept valid url', function() {
294
+ const result = validateInstance({
295
+ instance: 'http://foo.com/v2',
296
+ schema: 'url'
297
+ });
298
+ result.valid.should.be.true;
299
+ });
300
+ it('should reject an invalid url', function() {
301
+ const result = validateInstance({
302
+ instance: {},
303
+ schema: 'url'
304
+ });
305
+ result.valid.should.be.false;
306
+ });
307
+ it('should accept valid url with extend', function() {
308
+ const extend = {name: 'test'};
309
+ const schema = validation.schemas.url(extend);
310
+ const result = validateInstance({
311
+ instance: 'http://foo.com/v2',
312
+ schema
313
+ });
314
+ schema.name.should.equal('test');
315
+ result.valid.should.be.true;
316
+ });
317
+ });
318
+
319
+ describe('w3cDateTime', function() {
320
+ const schema = validation.getSchema({name: 'w3cDateTime'});
321
+ it('should be an Object', function() {
322
+ schema.should.be.an.instanceof(Object);
323
+ });
324
+ it('should accept valid w3cDateTime', function() {
325
+ const result = validateInstance({
326
+ instance: '2016-01-01T01:00:00Z',
327
+ schema: 'w3cDateTime'
328
+ });
329
+ result.valid.should.be.true;
330
+ });
331
+ it('should reject an invalid w3cDateTime', function() {
332
+ const result = validateInstance({
333
+ instance: {},
334
+ schema: 'w3cDateTime'
335
+ });
336
+ result.valid.should.be.false;
337
+ });
338
+ it('should accept valid w3cDateTime with extend', function() {
339
+ const extend = {name: 'test'};
340
+ const schema = validation.schemas.w3cDateTime(extend);
341
+ const result = validateInstance({
342
+ instance: '2016-01-01T01:00:00Z',
343
+ schema
344
+ });
345
+ schema.name.should.equal('test');
346
+ result.valid.should.be.true;
347
+ });
348
+ });
349
+
350
+ describe('personName', function() {
351
+ const schema = validation.getSchema({name: 'personName'});
352
+ it('should be an Object', function() {
353
+ schema.should.be.an.instanceof(Object);
354
+ });
355
+ it('should accept valid personName', function() {
356
+ const result = validateInstance({
357
+ instance: 'Name',
358
+ schema: 'personName'
359
+ });
360
+ result.valid.should.be.true;
361
+ });
362
+ it('should reject an invalid personName', function() {
363
+ const result = validateInstance({
364
+ instance: {},
365
+ schema: 'personName'
366
+ });
367
+ result.valid.should.be.false;
368
+ });
369
+ it('should accept valid personName with extend', function() {
370
+ const extend = {name: 'test'};
371
+ const schema = validation.schemas.personName(extend);
372
+ const result = validateInstance({
373
+ instance: 'Name',
374
+ schema
375
+ });
376
+ schema.name.should.equal('test');
377
+ result.valid.should.be.true;
378
+ });
379
+ });
380
+
381
+ describe('privateKeyPem', function() {
382
+ const schema = validation.getSchema({name: 'privateKeyPem'});
383
+ const {privateKey} = mock.keys.alpha;
384
+ it('should be an Object', function() {
385
+ schema.should.be.an.instanceof(Object);
386
+ });
387
+ it('should accept valid privateKeyPem', function() {
388
+ const result = validateInstance({
389
+ instance: privateKey,
390
+ schema: 'privateKeyPem'
391
+ });
392
+ result.valid.should.be.true;
393
+ });
394
+ it('should reject an invalid privateKeyPem', function() {
395
+ const result = validateInstance({
396
+ instance: {},
397
+ schema: 'privateKeyPem'
398
+ });
399
+ result.valid.should.be.false;
400
+ });
401
+ it('should accept valid privateKeyPem with extend', function() {
402
+ const extend = {name: 'test'};
403
+ const schema = validation.schemas.privateKeyPem(extend);
404
+ const result = validateInstance({
405
+ instance: privateKey,
406
+ schema
407
+ });
408
+ schema.name.should.equal('test');
409
+ result.valid.should.be.true;
410
+ });
411
+ });
412
+
413
+ describe('publicKeyPem', function() {
414
+ const schema = validation.getSchema({name: 'publicKeyPem'});
415
+ const {publicKey} = mock.keys.alpha;
416
+ it('should be an Object', function() {
417
+ schema.should.be.an.instanceof(Object);
418
+ });
419
+ it('should accept valid publicKeyPem', function() {
420
+ const result = validateInstance({
421
+ instance: publicKey,
422
+ schema: 'publicKeyPem'
423
+ });
424
+ result.valid.should.be.true;
425
+ });
426
+ it('should reject an invalid publicKeyPem', function() {
427
+ const result = validateInstance({
428
+ instance: {},
429
+ schema: 'publicKeyPem'
430
+ });
431
+ result.valid.should.be.false;
432
+ });
433
+ it('should accept valid privateKeyPem with extend', function() {
434
+ const extend = {name: 'test'};
435
+ const schema = validation.schemas.publicKeyPem(extend);
436
+ const result = validateInstance({
437
+ instance: publicKey,
438
+ schema
439
+ });
440
+ schema.name.should.equal('test');
441
+ result.valid.should.be.true;
442
+ });
443
+ });
444
+
445
+ describe('email', function() {
446
+ const schema = validation.getSchema({name: 'email'});
447
+ it('should be an Object', function() {
448
+ schema.should.be.an.instanceof(Object);
449
+ });
450
+ it('should reject empty emails', function() {
451
+ const result = validateInstance({
452
+ instance: '',
453
+ schema: 'email'
454
+ });
455
+ result.valid.should.be.false;
456
+ });
457
+ it('should reject emails without `@`', function() {
458
+ const result = validateInstance({
459
+ instance: 'abcdefg',
460
+ schema: 'email'
461
+ });
462
+ result.valid.should.be.false;
463
+ });
464
+ it('should accept valid emails', function() {
465
+ const small = validateInstance({
466
+ instance: 'a@b.io',
467
+ schema: 'email'
468
+ });
469
+ should.not.exist(small.error);
470
+ small.valid.should.be.true;
471
+ });
472
+ it('should accept normal non-letter symbols', function() {
473
+ const result = validateInstance({
474
+ instance: 'abc123~!$%^&*_=+-@example.org',
475
+ schema: 'email'
476
+ });
477
+ result.valid.should.be.true;
478
+ });
479
+ it('should not accept emails with uppercase chars', function() {
480
+ const schema = validation.getSchema({name: 'email'});
481
+ const result = validateInstance({
482
+ instance: 'aBC@DEF.com',
483
+ schema
484
+ });
485
+ result.valid.should.be.false;
486
+ });
487
+ it('should reject emails with uppercase chars', function() {
488
+ const schema = validation.schemas.email({}, {lowerCaseOnly: true});
489
+ const result = validateInstance({
490
+ instance: 'aBC@DEF.com',
491
+ schema
492
+ });
493
+ result.valid.should.be.false;
494
+ });
495
+ });
496
+
497
+ describe('nonce', function() {
498
+ const schema = validation.getSchema({name: 'nonce'});
499
+ it('should be an Object', function() {
500
+ schema.should.be.an.instanceof(Object);
501
+ });
502
+ it('should reject empty nonces', function() {
503
+ const result = validateInstance({
504
+ instance: '',
505
+ schema: 'nonce'
506
+ });
507
+ result.valid.should.be.false;
508
+ });
509
+ it('should reject nonces that are too short', function() {
510
+ const result = validateInstance({
511
+ instance: '1234567',
512
+ schema: 'nonce'
513
+ });
514
+ result.valid.should.be.false;
515
+ });
516
+ it('should reject nonces that are too long', function() {
517
+ const result = validateInstance({
518
+ instance:
519
+ // 65 chars
520
+ '1234567890123456789012345678901234567890' +
521
+ '1234567890123456789012345',
522
+ schema: 'nonce'
523
+ });
524
+ result.valid.should.be.false;
525
+ });
526
+ it('should accept valid nonces', function() {
527
+ const small = validateInstance({
528
+ instance: '12345678',
529
+ schema: 'nonce'
530
+ });
531
+ small.valid.should.be.true;
532
+ const large = validateInstance({
533
+ instance:
534
+ // 64 chars
535
+ '1234567890123456789012345678901234567890' +
536
+ '123456789012345678901234',
537
+ schema: 'nonce'
538
+ });
539
+ large.valid.should.be.true;
540
+ });
541
+ it('should accept normal non-letter characters', function() {
542
+ const result = validateInstance({
543
+ instance: '-a-zA-Z0-9~!$%^&*()_=+. ',
544
+ schema: 'nonce'
545
+ });
546
+ result.valid.should.be.true;
547
+ });
548
+ it('should reject invalid characters', function() {
549
+ const result = validateInstance({
550
+ instance: '|||||||||',
551
+ schema: 'nonce'
552
+ });
553
+ result.valid.should.be.false;
554
+ });
555
+ it('should accept valid nonces with an extend', function() {
556
+ const extend = {name: 'test'};
557
+ const schema = validation.schemas.nonce(extend);
558
+ const result = validateInstance({
559
+ instance: '12345678',
560
+ schema
561
+ });
562
+ schema.name.should.equal('test');
563
+ result.valid.should.be.true;
564
+ });
565
+ });
566
+
567
+ describe('slug', function() {
568
+ const schema = validation.getSchema({name: 'slug'});
569
+ const validate = validation.compile({schema});
570
+ it('should be an Object', function() {
571
+ schema.should.be.an.instanceof(Object);
572
+ });
573
+ it('should reject empty slugs', function() {
574
+ const result = validateInstance({
575
+ instance: '',
576
+ schema: 'slug'
577
+ });
578
+ result.valid.should.be.false;
579
+ });
580
+ it('should reject slugs that are too short', function() {
581
+ // 2 chars
582
+ const result = validateInstance({
583
+ instance: '12',
584
+ schema: 'slug'
585
+ });
586
+ result.valid.should.be.false;
587
+ });
588
+ it('should reject slugs that are too long', function() {
589
+ // 33 chars
590
+ const result = validateInstance({
591
+ instance: '12345678901234567890123456789012345678901',
592
+ schema: 'slug'
593
+ });
594
+ result.valid.should.be.false;
595
+ });
596
+ it('should accept valid slugs', function() {
597
+ // 3 chars
598
+ let result = validateInstance({
599
+ instance: 'a23',
600
+ schema: 'slug'
601
+ });
602
+ result.valid.should.be.true;
603
+ // 40 chars
604
+ result = validateInstance({
605
+ instance: '1234567890123456789012345678901234567890',
606
+ schema: 'slug'
607
+ });
608
+ result.valid.should.be.true;
609
+ // uuids
610
+ result = validateInstance({
611
+ instance: '2f5f3815-fba0-4e07-a248-d79c26ca8fd6',
612
+ schema: 'slug'
613
+ });
614
+ result.valid.should.be.true;
615
+ });
616
+ it('should accept normal non-letter characters', function() {
617
+ const result = validateInstance({
618
+ instance: 'az-az09~_.',
619
+ schema: 'slug'
620
+ });
621
+ result.valid.should.be.true;
622
+ });
623
+ it('should reject invalid characters', function() {
624
+ let result = validateInstance({
625
+ instance: 'badchar@',
626
+ schema: 'slug'
627
+ });
628
+ result.valid.should.be.false;
629
+ result = validateInstance({
630
+ instance: '-hyphenstart',
631
+ schema: 'slug'
632
+ });
633
+ result.valid.should.be.false;
634
+ });
635
+ it('should mask value when error occurs', function() {
636
+ schema.errors.mask = true;
637
+ const result = validateInstance({
638
+ instance: 'sl',
639
+ schema
640
+ });
641
+ result.valid.should.be.false;
642
+ result.error.details.errors[0].details.value.should.equal('***MASKED***');
643
+ });
644
+ it('should mask value when error occurs w/compiled schema', function() {
645
+ schema.errors.mask = true;
646
+ const result = validate('sl');
647
+ result.valid.should.be.false;
648
+ result.error.details.errors[0].details.value.should.equal('***MASKED***');
649
+ });
650
+ it('should mask value when error occurs with a custom mask', function() {
651
+ schema.errors.mask = 'custom mask value';
652
+ const result = validateInstance({
653
+ instance: 'sl',
654
+ schema
655
+ });
656
+ result.valid.should.be.false;
657
+ result.error.details.errors[0].details.value.should
658
+ .equal('custom mask value');
659
+ });
660
+ it('should mask value when error occurs with a custom mask ' +
661
+ 'w/compiled schema', function() {
662
+ schema.errors.mask = 'custom mask value';
663
+ const result = validate('sl');
664
+ result.valid.should.be.false;
665
+ result.error.details.errors[0].details.value.should
666
+ .equal('custom mask value');
667
+ });
668
+ it('should accept valid slug with extend', function() {
669
+ const extend = {name: 'test'};
670
+ const schema = validation.schemas.slug(extend);
671
+ const result = validateInstance({
672
+ instance: 'a23',
673
+ schema
674
+ });
675
+ schema.name.should.equal('test');
676
+ result.valid.should.be.true;
677
+ });
678
+ });
679
+
680
+ describe('jsonldContext', function() {
681
+ const schema = validation.getSchema({name: 'jsonldContext'});
682
+ it('should be an Object', function() {
683
+ schema.should.be.an.instanceof(Object);
684
+ });
685
+ it('should accept a URL', function() {
686
+ const schema = validation.schemas.jsonldContext('http://foo.com/v1');
687
+ const result = validateInstance({
688
+ instance: 'http://foo.com/v1',
689
+ schema
690
+ });
691
+ result.valid.should.be.true;
692
+ });
693
+ it('should accept a URL with an extend', function() {
694
+ const extend = {name: 'test'};
695
+ const schema = validation.schemas.jsonldContext(
696
+ 'http://foo.com/v1', extend);
697
+ const result = validateInstance({
698
+ instance: 'http://foo.com/v1',
699
+ schema
700
+ });
701
+ schema.name.should.equal('test');
702
+ result.valid.should.be.true;
703
+ });
704
+ it('should reject the wrong a URL', function() {
705
+ const schema = validation.schemas.jsonldContext('http://foo.com/v1');
706
+ const result = validateInstance({
707
+ instance: 'http://foo.com/v2',
708
+ schema
709
+ });
710
+ result.valid.should.be.false;
711
+ });
712
+ it('should accept an array of URLs', function() {
713
+ const schema = validation.schemas.jsonldContext([
714
+ 'http://foo.com/v1',
715
+ 'http://bar.com/v1'
716
+ ]);
717
+ const result = validateInstance({
718
+ instance: ['http://foo.com/v1', 'http://bar.com/v1'],
719
+ schema
720
+ });
721
+ result.valid.should.be.true;
722
+ });
723
+ it('should reject the wrong array of URLs', function() {
724
+ const schema = validation.schemas.jsonldContext([
725
+ 'http://foo.com/v1',
726
+ 'http://bar.com/v1'
727
+ ]);
728
+ const result = validateInstance({
729
+ instance: ['http://foo.com/v1', 'http://wrong.com/v1'],
730
+ schema
731
+ });
732
+ result.valid.should.be.false;
733
+ });
734
+ it('should accept an array of objects', function() {
735
+ const schema = validation.schemas.jsonldContext([
736
+ {url: 'http://foo.com/v1'},
737
+ {url: 'http://bar.com/v1'}
738
+ ]);
739
+ const result = validateInstance({
740
+ instance: [{url: 'http://foo.com/v1'}, {url: 'http://bar.com/v1'}],
741
+ schema
742
+ });
743
+ result.valid.should.be.true;
744
+ });
745
+ it('should accept an array of objects w/compiled schema', function() {
746
+ const schema = validation.schemas.jsonldContext([
747
+ {url: 'http://foo.com/v1'},
748
+ {url: 'http://bar.com/v1'}
749
+ ]);
750
+ const validate = validation.compile({schema});
751
+ const result = validate([
752
+ {url: 'http://foo.com/v1'},
753
+ {url: 'http://bar.com/v1'}
754
+ ]);
755
+ result.valid.should.be.true;
756
+ });
757
+ });
758
+
759
+ describe('jsonldType', function() {
760
+ const schema = validation.getSchema({name: 'jsonldType'});
761
+ it('should be an Object', function() {
762
+ schema.should.be.an.instanceof(Object);
763
+ });
764
+ it('should accept a string', function() {
765
+ const schema = validation.schemas.jsonldType('Group');
766
+ const type = 'Group';
767
+ const result = validateInstance({
768
+ instance: type,
769
+ schema
770
+ });
771
+ result.valid.should.be.true;
772
+ });
773
+ it('should accept a string with alternates', function() {
774
+ const alternate = 1;
775
+ const schema = validation.schemas.jsonldType('Group', alternate);
776
+ const type = 'Group';
777
+ const result = validateInstance({
778
+ instance: type,
779
+ schema
780
+ });
781
+ schema.anyOf.length.should.equal(4);
782
+ result.valid.should.be.true;
783
+ });
784
+ it('should reject the wrong string', function() {
785
+ const schema = validation.schemas.jsonldType('Group');
786
+ const type = 'Wrong';
787
+ const result = validateInstance({
788
+ instance: type,
789
+ schema
790
+ });
791
+ result.valid.should.be.false;
792
+ });
793
+ it('should accept an array of strings', function() {
794
+ const schema = validation.schemas.jsonldType(['Group', 'Name']);
795
+ const type = ['Group', 'Name'];
796
+ const result = validateInstance({
797
+ instance: type,
798
+ schema
799
+ });
800
+ result.valid.should.be.true;
801
+ });
802
+ it('should reject the wrong array of strings', function() {
803
+ const schema = validation.schemas.jsonldType(['Group', 'Name']);
804
+ const type = ['Group', 'Wrong'];
805
+ const result = validateInstance({
806
+ instance: type,
807
+ schema
808
+ });
809
+ result.valid.should.be.false;
810
+ });
811
+ });
812
+
813
+ describe('linkedDataSignature', function() {
814
+ const schema = validation.getSchema({name: 'linkedDataSignature'});
815
+
816
+ it('should be an Object', function() {
817
+ schema.should.be.an.instanceof(Object);
818
+ });
819
+
820
+ it('should validate a LinkedDataSignature2015 signature', function() {
821
+ const signature = {
822
+ type: 'LinkedDataSignature2015',
823
+ created: '2016-01-01T01:00:00Z',
824
+ creator: 'urn:5dd6a7e2-4c32-4a21-60b3-2385e5b6bcd4/keys/1',
825
+ // eslint-disable-next-line max-len
826
+ signatureValue: 'Lc6l7gxEPV1lKTj4KADaER52CiMBpvsHg7eZZJXzRK3U8N/eUYxITlenu3svj4KPrdnaBfMXGo3U/vAVaQNF5Er0g/SXC2KpUmRN4uyMYgQ5NwWklS2JqjJ/0Y3hio4GOgdMDiqrlZJvfQdtRaJjKoskc7F3bZtDVsX6Sr95erfOeobHOIMcbNIC0a96oYOaQlOeOC45BqQaUaczYKPayGEeQN2lfD+qR6b1MR4xtWNrx5pzzPpAPkjj3I91wiVQER43s/nq5XZKkDk8V8eD7xEURoDUcu3rA1qHLfrpRHJGCErXNc784O4R4Oqm5zQlkyB1mWJxnz3qSqzgqVG0sQ=='
827
+ };
828
+ const result = validateInstance({instance: signature, schema});
829
+ result.valid.should.be.true;
830
+ });
831
+
832
+ it('should validate a LinkedDataSignature2016 signature', function() {
833
+ const signature = {
834
+ type: 'LinkedDataSignature2016',
835
+ created: '2016-01-01T01:00:00Z',
836
+ creator: 'urn:5dd6a7e2-4c32-4a21-60b3-2385e5b6bcd4/keys/1',
837
+ // eslint-disable-next-line max-len
838
+ signatureValue: 'Lc6l7gxEPV1lKTj4KADaER52CiMBpvsHg7eZZJXzRK3U8N/eUYxITlenu3svj4KPrdnaBfMXGo3U/vAVaQNF5Er0g/SXC2KpUmRN4uyMYgQ5NwWklS2JqjJ/0Y3hio4GOgdMDiqrlZJvfQdtRaJjKoskc7F3bZtDVsX6Sr95erfOeobHOIMcbNIC0a96oYOaQlOeOC45BqQaUaczYKPayGEeQN2lfD+qR6b1MR4xtWNrx5pzzPpAPkjj3I91wiVQER43s/nq5XZKkDk8V8eD7xEURoDUcu3rA1qHLfrpRHJGCErXNc784O4R4Oqm5zQlkyB1mWJxnz3qSqzgqVG0sQ=='
839
+ };
840
+ const result = validateInstance({instance: signature, schema});
841
+ result.valid.should.be.true;
842
+ });
843
+
844
+ it('should validate a LinkedDataSignature2015 with an extend', function() {
845
+ const signature = {
846
+ type: 'LinkedDataSignature2015',
847
+ created: '2016-01-01T01:00:00Z',
848
+ creator: 'urn:5dd6a7e2-4c32-4a21-60b3-2385e5b6bcd4/keys/1',
849
+ // eslint-disable-next-line max-len
850
+ signatureValue: 'Lc6l7gxEPV1lKTj4KADaER52CiMBpvsHg7eZZJXzRK3U8N/eUYxITlenu3svj4KPrdnaBfMXGo3U/vAVaQNF5Er0g/SXC2KpUmRN4uyMYgQ5NwWklS2JqjJ/0Y3hio4GOgdMDiqrlZJvfQdtRaJjKoskc7F3bZtDVsX6Sr95erfOeobHOIMcbNIC0a96oYOaQlOeOC45BqQaUaczYKPayGEeQN2lfD+qR6b1MR4xtWNrx5pzzPpAPkjj3I91wiVQER43s/nq5XZKkDk8V8eD7xEURoDUcu3rA1qHLfrpRHJGCErXNc784O4R4Oqm5zQlkyB1mWJxnz3qSqzgqVG0sQ=='
851
+ };
852
+ const extend = {name: 'test'};
853
+ const schema = validation.schemas.linkedDataSignature(extend);
854
+ const result = validateInstance({instance: signature, schema});
855
+ schema.name.should.equal('test');
856
+ result.valid.should.be.true;
857
+ });
858
+
859
+ it('should NOT validate a GraphSignature2012 signature', function() {
860
+ const signature = {
861
+ type: 'GraphSignature2012',
862
+ created: '2016-01-01T01:00:00Z',
863
+ creator: 'urn:5dd6a7e2-4c32-4a21-60b3-2385e5b6bcd4/keys/1',
864
+ // eslint-disable-next-line max-len
865
+ signatureValue: 'Lc6l7gxEPV1lKTj4KADaER52CiMBpvsHg7eZZJXzRK3U8N/eUYxITlenu3svj4KPrdnaBfMXGo3U/vAVaQNF5Er0g/SXC2KpUmRN4uyMYgQ5NwWklS2JqjJ/0Y3hio4GOgdMDiqrlZJvfQdtRaJjKoskc7F3bZtDVsX6Sr95erfOeobHOIMcbNIC0a96oYOaQlOeOC45BqQaUaczYKPayGEeQN2lfD+qR6b1MR4xtWNrx5pzzPpAPkjj3I91wiVQER43s/nq5XZKkDk8V8eD7xEURoDUcu3rA1qHLfrpRHJGCErXNc784O4R4Oqm5zQlkyB1mWJxnz3qSqzgqVG0sQ=='
866
+ };
867
+ const result = validateInstance({instance: signature, schema});
868
+ result.valid.should.be.false;
869
+ });
870
+
871
+ it('should NOT validate a signature w/missing type', function() {
872
+ const signature = {
873
+ created: '2016-01-01T01:00:00Z',
874
+ creator: 'urn:5dd6a7e2-4c32-4a21-60b3-2385e5b6bcd4/keys/1',
875
+ // eslint-disable-next-line max-len
876
+ signatureValue: 'Lc6l7gxEPV1lKTj4KADaER52CiMBpvsHg7eZZJXzRK3U8N/eUYxITlenu3svj4KPrdnaBfMXGo3U/vAVaQNF5Er0g/SXC2KpUmRN4uyMYgQ5NwWklS2JqjJ/0Y3hio4GOgdMDiqrlZJvfQdtRaJjKoskc7F3bZtDVsX6Sr95erfOeobHOIMcbNIC0a96oYOaQlOeOC45BqQaUaczYKPayGEeQN2lfD+qR6b1MR4xtWNrx5pzzPpAPkjj3I91wiVQER43s/nq5XZKkDk8V8eD7xEURoDUcu3rA1qHLfrpRHJGCErXNc784O4R4Oqm5zQlkyB1mWJxnz3qSqzgqVG0sQ=='
877
+ };
878
+ const result = validateInstance({instance: signature, schema});
879
+ result.valid.should.be.false;
880
+ });
881
+
882
+ // eslint-disable-next-line max-len
883
+ it('should NOT validate a LinkedDataSignature2015 signature w/missing created', function() {
884
+ const signature = {
885
+ type: 'LinkedDataSignature2015',
886
+ creator: 'urn:5dd6a7e2-4c32-4a21-60b3-2385e5b6bcd4/keys/1',
887
+ // eslint-disable-next-line max-len
888
+ signatureValue: 'Lc6l7gxEPV1lKTj4KADaER52CiMBpvsHg7eZZJXzRK3U8N/eUYxITlenu3svj4KPrdnaBfMXGo3U/vAVaQNF5Er0g/SXC2KpUmRN4uyMYgQ5NwWklS2JqjJ/0Y3hio4GOgdMDiqrlZJvfQdtRaJjKoskc7F3bZtDVsX6Sr95erfOeobHOIMcbNIC0a96oYOaQlOeOC45BqQaUaczYKPayGEeQN2lfD+qR6b1MR4xtWNrx5pzzPpAPkjj3I91wiVQER43s/nq5XZKkDk8V8eD7xEURoDUcu3rA1qHLfrpRHJGCErXNc784O4R4Oqm5zQlkyB1mWJxnz3qSqzgqVG0sQ=='
889
+ };
890
+ const result = validateInstance({instance: signature, schema});
891
+ result.valid.should.be.false;
892
+ });
893
+
894
+ // eslint-disable-next-line max-len
895
+ it('should NOT validate a LinkedDataSignature2015 signature w/missing creator', function() {
896
+ const signature = {
897
+ type: 'LinkedDataSignature2015',
898
+ created: '2016-01-01T01:00:00Z',
899
+ // eslint-disable-next-line max-len
900
+ signatureValue: 'Lc6l7gxEPV1lKTj4KADaER52CiMBpvsHg7eZZJXzRK3U8N/eUYxITlenu3svj4KPrdnaBfMXGo3U/vAVaQNF5Er0g/SXC2KpUmRN4uyMYgQ5NwWklS2JqjJ/0Y3hio4GOgdMDiqrlZJvfQdtRaJjKoskc7F3bZtDVsX6Sr95erfOeobHOIMcbNIC0a96oYOaQlOeOC45BqQaUaczYKPayGEeQN2lfD+qR6b1MR4xtWNrx5pzzPpAPkjj3I91wiVQER43s/nq5XZKkDk8V8eD7xEURoDUcu3rA1qHLfrpRHJGCErXNc784O4R4Oqm5zQlkyB1mWJxnz3qSqzgqVG0sQ=='
901
+ };
902
+ const result = validateInstance({instance: signature, schema});
903
+ result.valid.should.be.false;
904
+ });
905
+
906
+ // eslint-disable-next-line max-len
907
+ it('should NOT validate a LinkedDataSignature2015 signature w/missing signature', function() {
908
+ const signature = {
909
+ type: 'LinkedDataSignature2015',
910
+ created: '2016-01-01T01:00:00Z',
911
+ creator: 'urn:5dd6a7e2-4c32-4a21-60b3-2385e5b6bcd4/keys/1'
912
+ };
913
+ const result = validateInstance({instance: signature, schema});
914
+ result.valid.should.be.false;
915
+ });
916
+ });
917
+
918
+ describe('linkedDataSignature2020', function() {
919
+ const schema = validation.getSchema({name: 'linkedDataSignature2020'});
920
+
921
+ it('should be an Object', function() {
922
+ schema.should.be.an.instanceof(Object);
923
+ });
924
+
925
+ it('should validate a LinkedDataSignature2020 signature', function() {
926
+ const signature = {
927
+ type: 'Ed25519Signature2020',
928
+ created: '2021-01-01T19:23:24Z',
929
+ verificationMethod: 'https://example.edu/issuers/565049#' +
930
+ 'z6MknCCLeeHBUaHu4aHSVLDCYQW9gjVJ7a63FpMvtuVMy53T',
931
+ proofPurpose: 'assertionMethod',
932
+ proofValue: 'z3MvGcVxzRzzpKF1HA11EjvfPZsN8NAb7kXBRfeTm3CBg2gcJLQM5hZ' +
933
+ 'Nmj6Ccd9Lk4C1YueiFZvkSx4FuHVYVouQk'
934
+ };
935
+ const result = validateInstance({instance: signature, schema});
936
+ result.valid.should.be.true;
937
+ });
938
+
939
+ it('should NOT validate a signature w/missing type', function() {
940
+ const signature = {
941
+ created: '2021-01-01T19:23:24Z',
942
+ verificationMethod: 'https://example.edu/issuers/565049#' +
943
+ 'z6MknCCLeeHBUaHu4aHSVLDCYQW9gjVJ7a63FpMvtuVMy53T',
944
+ proofPurpose: 'assertionMethod',
945
+ proofValue: 'z3MvGcVxzRzzpKF1HA11EjvfPZsN8NAb7kXBRfeTm3CBg2gcJLQM5hZ' +
946
+ 'Nmj6Ccd9Lk4C1YueiFZvkSx4FuHVYVouQk'
947
+ };
948
+ const result = validateInstance({instance: signature, schema});
949
+ result.valid.should.be.false;
950
+ });
951
+
952
+ it('should NOT validate a signature with missing created', function() {
953
+ const signature = {
954
+ type: 'Ed25519Signature2020',
955
+ verificationMethod: 'https://example.edu/issuers/565049#' +
956
+ 'z6MknCCLeeHBUaHu4aHSVLDCYQW9gjVJ7a63FpMvtuVMy53T',
957
+ proofPurpose: 'assertionMethod',
958
+ proofValue: 'z3MvGcVxzRzzpKF1HA11EjvfPZsN8NAb7kXBRfeTm3CBg2gcJLQM5hZ' +
959
+ 'Nmj6Ccd9Lk4C1YueiFZvkSx4FuHVYVouQk'
960
+ };
961
+ const result = validateInstance({instance: signature, schema});
962
+ result.valid.should.be.false;
963
+ });
964
+
965
+ it('should NOT validate a with missing verificationMethod', function() {
966
+ const signature = {
967
+ type: 'Ed25519Signature2020',
968
+ proofPurpose: 'assertionMethod',
969
+ proofValue: 'z3MvGcVxzRzzpKF1HA11EjvfPZsN8NAb7kXBRfeTm3CBg2gcJLQM5hZ' +
970
+ 'Nmj6Ccd9Lk4C1YueiFZvkSx4FuHVYVouQk'
971
+ };
972
+ const result = validateInstance({instance: signature, schema});
973
+ result.valid.should.be.false;
974
+ });
975
+
976
+ // eslint-disable-next-line max-len
977
+ it('should NOT validate a signature w/missing proofValue', function() {
978
+ const signature = {
979
+ type: 'Ed25519Signature2020',
980
+ verificationMethod: 'https://example.edu/issuers/565049#' +
981
+ 'z6MknCCLeeHBUaHu4aHSVLDCYQW9gjVJ7a63FpMvtuVMy53T',
982
+ proofPurpose: 'assertionMethod'
983
+ };
984
+ const result = validateInstance({instance: signature, schema});
985
+ result.valid.should.be.false;
986
+ });
987
+ });
988
+
989
+ describe('credential', function() {
990
+ const schema = validation.getSchema({name: 'credential'});
991
+ it('should be an Object', function() {
992
+ schema.should.be.an.instanceof(Object);
993
+ });
994
+ it('should validate a credential', function() {
995
+ const credential = {
996
+ issuer: 'test',
997
+ issued: '1997-07-16T19:20:30',
998
+ claim: {
999
+ id: '1234'
1000
+ }
1001
+ };
1002
+ const result = validateInstance({instance: credential, schema});
1003
+ result.valid.should.be.true;
1004
+ });
1005
+ it('should validate a credential with an extend', function() {
1006
+ const credential = {
1007
+ issuer: 'test',
1008
+ issued: '2016-01-01T01:00:00Z',
1009
+ claim: {
1010
+ id: '1234'
1011
+ }
1012
+ };
1013
+ const extend = {name: 'test'};
1014
+ const schema = validation.schemas.credential(extend);
1015
+ const result = validateInstance({instance: credential, schema});
1016
+ schema.name.should.equal('test');
1017
+ result.valid.should.be.true;
1018
+ });
1019
+ });
1020
+
1021
+ describe('jsonPatch', function() {
1022
+ const schema = validation.getSchema({name: 'jsonPatch'});
1023
+
1024
+ it('should be an Object', function() {
1025
+ schema.should.be.an.instanceof(Object);
1026
+ });
1027
+
1028
+ it('should validate a JSON patch', function() {
1029
+ const patch = [
1030
+ {op: 'add', path: '/email', value: 'pdoe@example.com'}
1031
+ ];
1032
+ const result = validateInstance({instance: patch, schema});
1033
+ result.valid.should.be.true;
1034
+ });
1035
+
1036
+ it('should NOT validate a JSON patch that is an empty array', function() {
1037
+ const patch = [];
1038
+ const result = validateInstance({instance: patch, schema});
1039
+ result.valid.should.be.false;
1040
+ });
1041
+
1042
+ it('should NOT validate a JSON patch that is not an array', function() {
1043
+ const patch = {
1044
+ op: 'add', path: '/email', value: 'pdoe@example.com'
1045
+ };
1046
+ const result = validateInstance({instance: patch, schema});
1047
+ result.valid.should.be.false;
1048
+ });
1049
+
1050
+ it('should NOT validate a JSON patch with an extra property', function() {
1051
+ const patch = [
1052
+ {op: 'add', path: '/email', value: 'pdoe@example.com', extra: true}
1053
+ ];
1054
+ const result = validateInstance({instance: patch, schema});
1055
+ result.valid.should.be.false;
1056
+ });
1057
+ it('should validate a JSON patch with extend', function() {
1058
+ const patch = [
1059
+ {op: 'add', path: '/email', value: 'pdoe@example.com'}
1060
+ ];
1061
+ const extend = {name: 'test'};
1062
+ const schema = validation.schemas.jsonPatch(extend);
1063
+ const result = validateInstance({instance: patch, schema});
1064
+ schema.name.should.equal('test');
1065
+ result.valid.should.be.true;
1066
+ });
1067
+ });
1068
+
1069
+ describe('sequencedPatch', function() {
1070
+ const schema = validation.getSchema({name: 'sequencedPatch'});
1071
+
1072
+ it('should be an Object', function() {
1073
+ schema.should.be.an.instanceof(Object);
1074
+ });
1075
+
1076
+ it('should validate a sequenced JSON patch', function() {
1077
+ const doc = {
1078
+ target: 'some-identifier',
1079
+ patch: [
1080
+ {op: 'add', path: '/email', value: 'pdoe@example.com'}
1081
+ ],
1082
+ sequence: 1
1083
+ };
1084
+ const result = validateInstance({instance: doc, schema});
1085
+ result.valid.should.be.true;
1086
+ });
1087
+
1088
+ // eslint-disable-next-line max-len
1089
+ it('should NOT validate a sequenced JSON patch without a sequence', function() {
1090
+ const doc = {
1091
+ target: 'some-identifier',
1092
+ patch: [
1093
+ {op: 'add', path: '/email', value: 'pdoe@example.com'}
1094
+ ]
1095
+ };
1096
+ const result = validateInstance({instance: doc, schema});
1097
+ result.valid.should.be.false;
1098
+ });
1099
+
1100
+ // eslint-disable-next-line max-len
1101
+ it('should NOT validate a sequenced JSON patch without a target', function() {
1102
+ const doc = {
1103
+ patch: [
1104
+ {op: 'add', path: '/email', value: 'pdoe@example.com'}
1105
+ ],
1106
+ sequence: 1
1107
+ };
1108
+ const result = validateInstance({instance: doc, schema});
1109
+ result.valid.should.be.false;
1110
+ });
1111
+
1112
+ // eslint-disable-next-line max-len
1113
+ it('should NOT validate a sequenced JSON patch with a negative sequence', function() {
1114
+ const doc = {
1115
+ target: 'some-identifier',
1116
+ patch: [
1117
+ {op: 'add', path: '/email', value: 'pdoe@example.com'}
1118
+ ],
1119
+ sequence: -1
1120
+ };
1121
+ const result = validateInstance({instance: doc, schema});
1122
+ result.valid.should.be.false;
1123
+ });
1124
+
1125
+ it('should validate a sequenced JSON patch with extend', function() {
1126
+ const doc = {
1127
+ target: 'some-identifier',
1128
+ patch: [
1129
+ {op: 'add', path: '/email', value: 'pdoe@example.com'}
1130
+ ],
1131
+ sequence: 1
1132
+ };
1133
+ const extend = {name: 'test'};
1134
+ const schema = validation.schemas.sequencedPatch(extend);
1135
+ const result = validateInstance({instance: doc, schema});
1136
+ schema.name.should.equal('test');
1137
+ result.valid.should.be.true;
1138
+ });
1139
+
1140
+ it('should validate a sequenced JSON patch with extend ' +
1141
+ 'and w/compiled schema', function() {
1142
+ const doc = {
1143
+ target: 'some-identifier',
1144
+ patch: [
1145
+ {op: 'add', path: '/email', value: 'pdoe@example.com'}
1146
+ ],
1147
+ sequence: 1
1148
+ };
1149
+ const extend = {name: 'test'};
1150
+ const schema = validation.schemas.sequencedPatch(extend);
1151
+ const validate = validation.compile({schema});
1152
+ const result = validate(doc);
1153
+ schema.name.should.equal('test');
1154
+ result.valid.should.be.true;
1155
+ });
1156
+ });
1157
+ });