smartledger-bsv 3.2.1 → 3.3.1
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/CHANGELOG.md +147 -0
- package/README.md +289 -55
- package/architecture_demo.js +247 -0
- package/bsv-covenant.min.js +10 -0
- package/bsv-gdaf.min.js +37 -0
- package/bsv-ltp.min.js +37 -0
- package/bsv-script-helper.min.js +10 -0
- package/bsv-security.min.js +31 -0
- package/bsv-shamir.min.js +12 -0
- package/bsv-smartcontract.min.js +37 -0
- package/bsv.bundle.js +9 -9
- package/bsv.min.js +3 -3
- package/build/bsv-covenant.min.js +10 -0
- package/build/bsv-script-helper.min.js +10 -0
- package/build/bsv-security.min.js +31 -0
- package/build/bsv-smartcontract.min.js +39 -0
- package/build/bsv.bundle.js +39 -0
- package/build/bsv.min.js +39 -0
- package/build/webpack.bundle.config.js +22 -0
- package/build/webpack.config.js +18 -0
- package/build/webpack.covenant.config.js +27 -0
- package/build/webpack.gdaf.config.js +54 -0
- package/build/webpack.ltp.config.js +17 -0
- package/build/webpack.script-helper.config.js +27 -0
- package/build/webpack.security.config.js +23 -0
- package/build/webpack.smartcontract.config.js +25 -0
- package/build/webpack.subproject.config.js +6 -0
- package/bundle-entry.js +341 -0
- package/complete_ltp_demo.js +511 -0
- package/covenant-entry.js +44 -0
- package/docs/pushtx-key-insights.md +106 -0
- package/gdaf-entry.js +54 -0
- package/index.js +272 -5
- package/lib/crypto/shamir.js +360 -0
- package/lib/gdaf/attestation-signer.js +461 -0
- package/lib/gdaf/attestation-verifier.js +600 -0
- package/lib/gdaf/did-resolver.js +382 -0
- package/lib/gdaf/index.js +471 -0
- package/lib/gdaf/schema-validator.js +682 -0
- package/lib/gdaf/smartledger-anchor.js +486 -0
- package/lib/gdaf/zk-prover.js +507 -0
- package/lib/ltp/anchor.js +438 -0
- package/lib/ltp/claim.js +1026 -0
- package/lib/ltp/index.js +470 -0
- package/lib/ltp/obligation.js +945 -0
- package/lib/ltp/proof.js +828 -0
- package/lib/ltp/registry.js +702 -0
- package/lib/ltp/right.js +765 -0
- package/lib/smart_contract/API_REFERENCE.md +1 -1
- package/lib/smart_contract/EXAMPLES.md +2 -2
- package/lib/smart_contract/QUICK_START.md +2 -2
- package/lib/smart_contract/README.md +1 -1
- package/lib/smart_contract/index.js +4 -0
- package/ltp-entry.js +92 -0
- package/package.json +91 -20
- package/script-helper-entry.js +49 -0
- package/security-entry.js +70 -0
- package/shamir-entry.js +173 -0
- package/shamir_demo.js +121 -0
- package/simple_demo.js +204 -0
- package/smartcontract-entry.js +133 -0
- package/test_shamir.js +221 -0
- package/test_standalone_shamir.html +83 -0
- package/tests/bundle-completeness-test.html +131 -0
- package/tests/bundle-demo.html +476 -0
- package/tests/smartcontract-test.html +239 -0
- package/tests/standalone-modules-test.html +260 -0
- package/tests/test.html +612 -0
- package/tests/unpkg-demo.html +194 -0
- package/docs/nchain.md +0 -958
|
@@ -0,0 +1,682 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
var $ = require('../util/preconditions')
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* VC Schema System
|
|
7
|
+
*
|
|
8
|
+
* Provides W3C Verifiable Credential schema definitions and validation
|
|
9
|
+
* for the Global Digital Attestation Framework (GDAF). Includes
|
|
10
|
+
* predefined schemas for common credential types and custom schema
|
|
11
|
+
* validation capabilities.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Schema definitions
|
|
16
|
+
*/
|
|
17
|
+
var schemas = {
|
|
18
|
+
// Email Verification Credential
|
|
19
|
+
EmailVerifiedCredential: {
|
|
20
|
+
'@context': [
|
|
21
|
+
'https://www.w3.org/2018/credentials/v1',
|
|
22
|
+
'https://smartledger.technology/contexts/email/v1'
|
|
23
|
+
],
|
|
24
|
+
type: ['VerifiableCredential', 'EmailVerifiedCredential'],
|
|
25
|
+
requiredFields: [
|
|
26
|
+
'credentialSubject.email',
|
|
27
|
+
'credentialSubject.verified'
|
|
28
|
+
],
|
|
29
|
+
properties: {
|
|
30
|
+
credentialSubject: {
|
|
31
|
+
type: 'object',
|
|
32
|
+
required: ['email', 'verified'],
|
|
33
|
+
properties: {
|
|
34
|
+
email: {
|
|
35
|
+
type: 'string',
|
|
36
|
+
format: 'email'
|
|
37
|
+
},
|
|
38
|
+
verified: {
|
|
39
|
+
type: 'boolean'
|
|
40
|
+
},
|
|
41
|
+
verificationMethod: {
|
|
42
|
+
type: 'string'
|
|
43
|
+
},
|
|
44
|
+
verificationTimestamp: {
|
|
45
|
+
type: 'string',
|
|
46
|
+
format: 'date-time'
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
// Age Verification Credential
|
|
54
|
+
AgeVerifiedCredential: {
|
|
55
|
+
'@context': [
|
|
56
|
+
'https://www.w3.org/2018/credentials/v1',
|
|
57
|
+
'https://smartledger.technology/contexts/age/v1'
|
|
58
|
+
],
|
|
59
|
+
type: ['VerifiableCredential', 'AgeVerifiedCredential'],
|
|
60
|
+
requiredFields: [
|
|
61
|
+
'credentialSubject.ageOver',
|
|
62
|
+
'credentialSubject.verified'
|
|
63
|
+
],
|
|
64
|
+
properties: {
|
|
65
|
+
credentialSubject: {
|
|
66
|
+
type: 'object',
|
|
67
|
+
required: ['ageOver', 'verified'],
|
|
68
|
+
properties: {
|
|
69
|
+
ageOver: {
|
|
70
|
+
type: 'number',
|
|
71
|
+
minimum: 0,
|
|
72
|
+
maximum: 150
|
|
73
|
+
},
|
|
74
|
+
verified: {
|
|
75
|
+
type: 'boolean'
|
|
76
|
+
},
|
|
77
|
+
birthDateHash: {
|
|
78
|
+
type: 'string',
|
|
79
|
+
pattern: '^[a-fA-F0-9]{64}$'
|
|
80
|
+
},
|
|
81
|
+
verificationMethod: {
|
|
82
|
+
type: 'string'
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
// KYC Verification Credential
|
|
90
|
+
KYCVerifiedCredential: {
|
|
91
|
+
'@context': [
|
|
92
|
+
'https://www.w3.org/2018/credentials/v1',
|
|
93
|
+
'https://smartledger.technology/contexts/kyc/v1'
|
|
94
|
+
],
|
|
95
|
+
type: ['VerifiableCredential', 'KYCVerifiedCredential'],
|
|
96
|
+
requiredFields: [
|
|
97
|
+
'credentialSubject.kycLevel',
|
|
98
|
+
'credentialSubject.verified',
|
|
99
|
+
'credentialSubject.verifyingAuthority'
|
|
100
|
+
],
|
|
101
|
+
properties: {
|
|
102
|
+
credentialSubject: {
|
|
103
|
+
type: 'object',
|
|
104
|
+
required: ['kycLevel', 'verified', 'verifyingAuthority'],
|
|
105
|
+
properties: {
|
|
106
|
+
kycLevel: {
|
|
107
|
+
type: 'string',
|
|
108
|
+
enum: ['basic', 'enhanced', 'premium', 'institutional']
|
|
109
|
+
},
|
|
110
|
+
verified: {
|
|
111
|
+
type: 'boolean'
|
|
112
|
+
},
|
|
113
|
+
verifyingAuthority: {
|
|
114
|
+
type: 'string'
|
|
115
|
+
},
|
|
116
|
+
verificationTimestamp: {
|
|
117
|
+
type: 'string',
|
|
118
|
+
format: 'date-time'
|
|
119
|
+
},
|
|
120
|
+
firstNameHash: {
|
|
121
|
+
type: 'string',
|
|
122
|
+
pattern: '^[a-fA-F0-9]{64}$'
|
|
123
|
+
},
|
|
124
|
+
lastNameHash: {
|
|
125
|
+
type: 'string',
|
|
126
|
+
pattern: '^[a-fA-F0-9]{64}$'
|
|
127
|
+
},
|
|
128
|
+
ssnHash: {
|
|
129
|
+
type: 'string',
|
|
130
|
+
pattern: '^[a-fA-F0-9]{64}$'
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
// Organization Credential
|
|
138
|
+
OrganizationCredential: {
|
|
139
|
+
'@context': [
|
|
140
|
+
'https://www.w3.org/2018/credentials/v1',
|
|
141
|
+
'https://smartledger.technology/contexts/organization/v1'
|
|
142
|
+
],
|
|
143
|
+
type: ['VerifiableCredential', 'OrganizationCredential'],
|
|
144
|
+
requiredFields: [
|
|
145
|
+
'credentialSubject.name',
|
|
146
|
+
'credentialSubject.type',
|
|
147
|
+
'credentialSubject.verified'
|
|
148
|
+
],
|
|
149
|
+
properties: {
|
|
150
|
+
credentialSubject: {
|
|
151
|
+
type: 'object',
|
|
152
|
+
required: ['name', 'type', 'verified'],
|
|
153
|
+
properties: {
|
|
154
|
+
name: {
|
|
155
|
+
type: 'string'
|
|
156
|
+
},
|
|
157
|
+
type: {
|
|
158
|
+
type: 'string',
|
|
159
|
+
enum: ['Corporation', 'LLC', 'Partnership', 'NGO', 'Government', 'Other']
|
|
160
|
+
},
|
|
161
|
+
verified: {
|
|
162
|
+
type: 'boolean'
|
|
163
|
+
},
|
|
164
|
+
taxIdHash: {
|
|
165
|
+
type: 'string',
|
|
166
|
+
pattern: '^[a-fA-F0-9]{64}$'
|
|
167
|
+
},
|
|
168
|
+
incorporationState: {
|
|
169
|
+
type: 'string'
|
|
170
|
+
},
|
|
171
|
+
industry: {
|
|
172
|
+
type: 'string'
|
|
173
|
+
},
|
|
174
|
+
verificationMethod: {
|
|
175
|
+
type: 'string'
|
|
176
|
+
},
|
|
177
|
+
verificationTimestamp: {
|
|
178
|
+
type: 'string',
|
|
179
|
+
format: 'date-time'
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
// SSN Verification Credential
|
|
187
|
+
SSNVerifiedCredential: {
|
|
188
|
+
'@context': [
|
|
189
|
+
'https://www.w3.org/2018/credentials/v1',
|
|
190
|
+
'https://smartledger.technology/contexts/ssn/v1'
|
|
191
|
+
],
|
|
192
|
+
type: ['VerifiableCredential', 'SSNVerifiedCredential'],
|
|
193
|
+
requiredFields: [
|
|
194
|
+
'credentialSubject.ssnHash',
|
|
195
|
+
'credentialSubject.verified',
|
|
196
|
+
'credentialSubject.verifyingAuthority'
|
|
197
|
+
],
|
|
198
|
+
properties: {
|
|
199
|
+
credentialSubject: {
|
|
200
|
+
type: 'object',
|
|
201
|
+
required: ['ssnHash', 'verified', 'verifyingAuthority'],
|
|
202
|
+
properties: {
|
|
203
|
+
ssnHash: {
|
|
204
|
+
type: 'string',
|
|
205
|
+
pattern: '^[a-fA-F0-9]{64}$'
|
|
206
|
+
},
|
|
207
|
+
verified: {
|
|
208
|
+
type: 'boolean'
|
|
209
|
+
},
|
|
210
|
+
verifyingAuthority: {
|
|
211
|
+
type: 'string'
|
|
212
|
+
},
|
|
213
|
+
verificationTimestamp: {
|
|
214
|
+
type: 'string',
|
|
215
|
+
format: 'date-time'
|
|
216
|
+
},
|
|
217
|
+
issuingState: {
|
|
218
|
+
type: 'string'
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
// Educational Credential
|
|
226
|
+
EducationalCredential: {
|
|
227
|
+
'@context': [
|
|
228
|
+
'https://www.w3.org/2018/credentials/v1',
|
|
229
|
+
'https://smartledger.technology/contexts/education/v1'
|
|
230
|
+
],
|
|
231
|
+
type: ['VerifiableCredential', 'EducationalCredential'],
|
|
232
|
+
requiredFields: [
|
|
233
|
+
'credentialSubject.degree',
|
|
234
|
+
'credentialSubject.institution',
|
|
235
|
+
'credentialSubject.graduationDate'
|
|
236
|
+
],
|
|
237
|
+
properties: {
|
|
238
|
+
credentialSubject: {
|
|
239
|
+
type: 'object',
|
|
240
|
+
required: ['degree', 'institution', 'graduationDate'],
|
|
241
|
+
properties: {
|
|
242
|
+
degree: {
|
|
243
|
+
type: 'string'
|
|
244
|
+
},
|
|
245
|
+
institution: {
|
|
246
|
+
type: 'string'
|
|
247
|
+
},
|
|
248
|
+
graduationDate: {
|
|
249
|
+
type: 'string',
|
|
250
|
+
format: 'date'
|
|
251
|
+
},
|
|
252
|
+
gpa: {
|
|
253
|
+
type: 'number',
|
|
254
|
+
minimum: 0.0,
|
|
255
|
+
maximum: 4.0
|
|
256
|
+
},
|
|
257
|
+
major: {
|
|
258
|
+
type: 'string'
|
|
259
|
+
},
|
|
260
|
+
honors: {
|
|
261
|
+
type: 'array',
|
|
262
|
+
items: {
|
|
263
|
+
type: 'string'
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
|
|
271
|
+
// Professional License Credential
|
|
272
|
+
ProfessionalLicenseCredential: {
|
|
273
|
+
'@context': [
|
|
274
|
+
'https://www.w3.org/2018/credentials/v1',
|
|
275
|
+
'https://smartledger.technology/contexts/license/v1'
|
|
276
|
+
],
|
|
277
|
+
type: ['VerifiableCredential', 'ProfessionalLicenseCredential'],
|
|
278
|
+
requiredFields: [
|
|
279
|
+
'credentialSubject.licenseType',
|
|
280
|
+
'credentialSubject.licenseNumber',
|
|
281
|
+
'credentialSubject.issuingAuthority',
|
|
282
|
+
'credentialSubject.isValid'
|
|
283
|
+
],
|
|
284
|
+
properties: {
|
|
285
|
+
credentialSubject: {
|
|
286
|
+
type: 'object',
|
|
287
|
+
required: ['licenseType', 'licenseNumber', 'issuingAuthority', 'isValid'],
|
|
288
|
+
properties: {
|
|
289
|
+
licenseType: {
|
|
290
|
+
type: 'string'
|
|
291
|
+
},
|
|
292
|
+
licenseNumber: {
|
|
293
|
+
type: 'string'
|
|
294
|
+
},
|
|
295
|
+
issuingAuthority: {
|
|
296
|
+
type: 'string'
|
|
297
|
+
},
|
|
298
|
+
issuingState: {
|
|
299
|
+
type: 'string'
|
|
300
|
+
},
|
|
301
|
+
isValid: {
|
|
302
|
+
type: 'boolean'
|
|
303
|
+
},
|
|
304
|
+
issueDate: {
|
|
305
|
+
type: 'string',
|
|
306
|
+
format: 'date'
|
|
307
|
+
},
|
|
308
|
+
expirationDate: {
|
|
309
|
+
type: 'string',
|
|
310
|
+
format: 'date'
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Schema validator
|
|
320
|
+
*/
|
|
321
|
+
var SchemaValidator = {
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Get schema by credential type
|
|
325
|
+
* @param {String} credentialType - Type of credential
|
|
326
|
+
* @returns {Object} Schema definition
|
|
327
|
+
*/
|
|
328
|
+
getSchema: function(credentialType) {
|
|
329
|
+
return schemas[credentialType] || null
|
|
330
|
+
},
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Get all available schemas
|
|
334
|
+
* @returns {Object} All schema definitions
|
|
335
|
+
*/
|
|
336
|
+
getAllSchemas: function() {
|
|
337
|
+
return schemas
|
|
338
|
+
},
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Validate credential against schema
|
|
342
|
+
* @param {Object} credential - Credential to validate
|
|
343
|
+
* @param {String|Object} schema - Schema name or definition
|
|
344
|
+
* @returns {Object} Validation result
|
|
345
|
+
*/
|
|
346
|
+
validate: function(credential, schema) {
|
|
347
|
+
try {
|
|
348
|
+
$.checkArgument(credential && typeof credential === 'object', 'Invalid credential')
|
|
349
|
+
|
|
350
|
+
var schemaDefinition
|
|
351
|
+
if (typeof schema === 'string') {
|
|
352
|
+
schemaDefinition = schemas[schema]
|
|
353
|
+
if (!schemaDefinition) {
|
|
354
|
+
return {
|
|
355
|
+
valid: false,
|
|
356
|
+
errors: ['Unknown schema type: ' + schema]
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
} else if (typeof schema === 'object') {
|
|
360
|
+
schemaDefinition = schema
|
|
361
|
+
} else {
|
|
362
|
+
return {
|
|
363
|
+
valid: false,
|
|
364
|
+
errors: ['Invalid schema parameter']
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
var errors = []
|
|
369
|
+
var warnings = []
|
|
370
|
+
|
|
371
|
+
// Validate required credential structure
|
|
372
|
+
this._validateCredentialStructure(credential, errors)
|
|
373
|
+
|
|
374
|
+
// Validate credential types
|
|
375
|
+
this._validateCredentialTypes(credential, schemaDefinition, errors)
|
|
376
|
+
|
|
377
|
+
// Validate required fields
|
|
378
|
+
this._validateRequiredFields(credential, schemaDefinition, errors)
|
|
379
|
+
|
|
380
|
+
// Validate field properties
|
|
381
|
+
this._validateFieldProperties(credential, schemaDefinition, errors, warnings)
|
|
382
|
+
|
|
383
|
+
return {
|
|
384
|
+
valid: errors.length === 0,
|
|
385
|
+
errors: errors,
|
|
386
|
+
warnings: warnings
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
} catch (error) {
|
|
390
|
+
return {
|
|
391
|
+
valid: false,
|
|
392
|
+
errors: ['Schema validation error: ' + error.message]
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Validate basic credential structure
|
|
399
|
+
* @private
|
|
400
|
+
*/
|
|
401
|
+
_validateCredentialStructure: function(credential, errors) {
|
|
402
|
+
if (!credential['@context']) {
|
|
403
|
+
errors.push('Missing @context')
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
if (!credential.type) {
|
|
407
|
+
errors.push('Missing type')
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
if (!credential.issuer) {
|
|
411
|
+
errors.push('Missing issuer')
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
if (!credential.issuanceDate) {
|
|
415
|
+
errors.push('Missing issuanceDate')
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
if (!credential.credentialSubject) {
|
|
419
|
+
errors.push('Missing credentialSubject')
|
|
420
|
+
}
|
|
421
|
+
},
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Validate credential types
|
|
425
|
+
* @private
|
|
426
|
+
*/
|
|
427
|
+
_validateCredentialTypes: function(credential, schema, errors) {
|
|
428
|
+
if (!Array.isArray(credential.type)) {
|
|
429
|
+
errors.push('Credential type must be array')
|
|
430
|
+
return
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
if (schema.type && Array.isArray(schema.type)) {
|
|
434
|
+
for (var i = 0; i < schema.type.length; i++) {
|
|
435
|
+
if (!credential.type.includes(schema.type[i])) {
|
|
436
|
+
errors.push('Missing required type: ' + schema.type[i])
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
},
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Validate required fields
|
|
444
|
+
* @private
|
|
445
|
+
*/
|
|
446
|
+
_validateRequiredFields: function(credential, schema, errors) {
|
|
447
|
+
if (schema.requiredFields && Array.isArray(schema.requiredFields)) {
|
|
448
|
+
for (var i = 0; i < schema.requiredFields.length; i++) {
|
|
449
|
+
var fieldPath = schema.requiredFields[i]
|
|
450
|
+
var value = this._getNestedProperty(credential, fieldPath)
|
|
451
|
+
|
|
452
|
+
if (value === undefined || value === null) {
|
|
453
|
+
errors.push('Missing required field: ' + fieldPath)
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
},
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Validate field properties
|
|
461
|
+
* @private
|
|
462
|
+
*/
|
|
463
|
+
_validateFieldProperties: function(credential, schema, errors, warnings) {
|
|
464
|
+
if (schema.properties && schema.properties.credentialSubject) {
|
|
465
|
+
this._validateObjectProperties(
|
|
466
|
+
credential.credentialSubject,
|
|
467
|
+
schema.properties.credentialSubject,
|
|
468
|
+
'credentialSubject',
|
|
469
|
+
errors,
|
|
470
|
+
warnings
|
|
471
|
+
)
|
|
472
|
+
}
|
|
473
|
+
},
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Validate object properties recursively
|
|
477
|
+
* @private
|
|
478
|
+
*/
|
|
479
|
+
_validateObjectProperties: function(obj, schema, path, errors, warnings) {
|
|
480
|
+
if (!obj || typeof obj !== 'object') {
|
|
481
|
+
return
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
if (schema.properties) {
|
|
485
|
+
Object.keys(schema.properties).forEach(function(prop) {
|
|
486
|
+
var value = obj[prop]
|
|
487
|
+
var propSchema = schema.properties[prop]
|
|
488
|
+
var propPath = path + '.' + prop
|
|
489
|
+
|
|
490
|
+
if (value !== undefined && value !== null) {
|
|
491
|
+
this._validateProperty(value, propSchema, propPath, errors, warnings)
|
|
492
|
+
}
|
|
493
|
+
}.bind(this))
|
|
494
|
+
}
|
|
495
|
+
},
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Validate individual property
|
|
499
|
+
* @private
|
|
500
|
+
*/
|
|
501
|
+
_validateProperty: function(value, schema, path, errors, warnings) {
|
|
502
|
+
// Type validation
|
|
503
|
+
if (schema.type) {
|
|
504
|
+
var actualType = Array.isArray(value) ? 'array' : typeof value
|
|
505
|
+
if (actualType !== schema.type) {
|
|
506
|
+
errors.push('Invalid type for ' + path + ': expected ' + schema.type + ', got ' + actualType)
|
|
507
|
+
return
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// String validations
|
|
512
|
+
if (schema.type === 'string') {
|
|
513
|
+
if (schema.format === 'email' && !this._isValidEmail(value)) {
|
|
514
|
+
errors.push('Invalid email format for ' + path)
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
if (schema.format === 'date' && !this._isValidDate(value)) {
|
|
518
|
+
errors.push('Invalid date format for ' + path)
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
if (schema.format === 'date-time' && !this._isValidDateTime(value)) {
|
|
522
|
+
errors.push('Invalid date-time format for ' + path)
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
if (schema.pattern && !new RegExp(schema.pattern).test(value)) {
|
|
526
|
+
errors.push('Value does not match pattern for ' + path)
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
if (schema.enum && !schema.enum.includes(value)) {
|
|
530
|
+
errors.push('Invalid enum value for ' + path + ': ' + value)
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// Number validations
|
|
535
|
+
if (schema.type === 'number') {
|
|
536
|
+
if (schema.minimum !== undefined && value < schema.minimum) {
|
|
537
|
+
errors.push('Value below minimum for ' + path + ': ' + value + ' < ' + schema.minimum)
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
if (schema.maximum !== undefined && value > schema.maximum) {
|
|
541
|
+
errors.push('Value above maximum for ' + path + ': ' + value + ' > ' + schema.maximum)
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// Array validations
|
|
546
|
+
if (schema.type === 'array' && schema.items) {
|
|
547
|
+
for (var i = 0; i < value.length; i++) {
|
|
548
|
+
this._validateProperty(value[i], schema.items, path + '[' + i + ']', errors, warnings)
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
},
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* Get nested property value
|
|
555
|
+
* @private
|
|
556
|
+
*/
|
|
557
|
+
_getNestedProperty: function(obj, path) {
|
|
558
|
+
return path.split('.').reduce(function(current, prop) {
|
|
559
|
+
return current && current[prop]
|
|
560
|
+
}, obj)
|
|
561
|
+
},
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Validate email format
|
|
565
|
+
* @private
|
|
566
|
+
*/
|
|
567
|
+
_isValidEmail: function(email) {
|
|
568
|
+
var emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
|
569
|
+
return emailRegex.test(email)
|
|
570
|
+
},
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* Validate date format (YYYY-MM-DD)
|
|
574
|
+
* @private
|
|
575
|
+
*/
|
|
576
|
+
_isValidDate: function(dateString) {
|
|
577
|
+
var date = new Date(dateString)
|
|
578
|
+
return !isNaN(date.getTime()) && dateString.match(/^\d{4}-\d{2}-\d{2}$/)
|
|
579
|
+
},
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* Validate date-time format (ISO 8601)
|
|
583
|
+
* @private
|
|
584
|
+
*/
|
|
585
|
+
_isValidDateTime: function(dateTimeString) {
|
|
586
|
+
var date = new Date(dateTimeString)
|
|
587
|
+
return !isNaN(date.getTime())
|
|
588
|
+
},
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Add custom schema
|
|
592
|
+
* @param {String} name - Schema name
|
|
593
|
+
* @param {Object} definition - Schema definition
|
|
594
|
+
*/
|
|
595
|
+
addSchema: function(name, definition) {
|
|
596
|
+
$.checkArgument(typeof name === 'string', 'Schema name must be string')
|
|
597
|
+
$.checkArgument(definition && typeof definition === 'object', 'Invalid schema definition')
|
|
598
|
+
|
|
599
|
+
schemas[name] = definition
|
|
600
|
+
},
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* Create schema template
|
|
604
|
+
* @param {String} credentialType - Type of credential
|
|
605
|
+
* @returns {Object} Template credential
|
|
606
|
+
*/
|
|
607
|
+
createTemplate: function(credentialType) {
|
|
608
|
+
var schema = schemas[credentialType]
|
|
609
|
+
if (!schema) {
|
|
610
|
+
throw new Error('Unknown credential type: ' + credentialType)
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
var template = {
|
|
614
|
+
'@context': schema['@context'] || ['https://www.w3.org/2018/credentials/v1'],
|
|
615
|
+
type: schema.type || ['VerifiableCredential'],
|
|
616
|
+
issuer: 'did:smartledger:ISSUER_DID_HERE',
|
|
617
|
+
issuanceDate: new Date().toISOString(),
|
|
618
|
+
credentialSubject: this._createSubjectTemplate(schema.properties ? schema.properties.credentialSubject : {})
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
return template
|
|
622
|
+
},
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* Create subject template from schema
|
|
626
|
+
* @private
|
|
627
|
+
*/
|
|
628
|
+
_createSubjectTemplate: function(subjectSchema) {
|
|
629
|
+
var template = {
|
|
630
|
+
id: 'SUBJECT_ID_HERE'
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
if (subjectSchema.properties) {
|
|
634
|
+
Object.keys(subjectSchema.properties).forEach(function(prop) {
|
|
635
|
+
var propSchema = subjectSchema.properties[prop]
|
|
636
|
+
template[prop] = this._getDefaultValue(propSchema)
|
|
637
|
+
}.bind(this))
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
return template
|
|
641
|
+
},
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* Get default value for property type
|
|
645
|
+
* @private
|
|
646
|
+
*/
|
|
647
|
+
_getDefaultValue: function(schema) {
|
|
648
|
+
switch (schema.type) {
|
|
649
|
+
case 'string':
|
|
650
|
+
if (schema.enum) {
|
|
651
|
+
return schema.enum[0]
|
|
652
|
+
}
|
|
653
|
+
if (schema.format === 'email') {
|
|
654
|
+
return 'example@example.com'
|
|
655
|
+
}
|
|
656
|
+
if (schema.format === 'date') {
|
|
657
|
+
return '2023-01-01'
|
|
658
|
+
}
|
|
659
|
+
if (schema.format === 'date-time') {
|
|
660
|
+
return new Date().toISOString()
|
|
661
|
+
}
|
|
662
|
+
return 'PLACEHOLDER_STRING'
|
|
663
|
+
|
|
664
|
+
case 'number':
|
|
665
|
+
return schema.minimum || 0
|
|
666
|
+
|
|
667
|
+
case 'boolean':
|
|
668
|
+
return true
|
|
669
|
+
|
|
670
|
+
case 'array':
|
|
671
|
+
return []
|
|
672
|
+
|
|
673
|
+
case 'object':
|
|
674
|
+
return {}
|
|
675
|
+
|
|
676
|
+
default:
|
|
677
|
+
return null
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
module.exports = SchemaValidator
|