@smartledger/bsv 3.2.1 → 3.3.2

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.
Files changed (70) hide show
  1. package/CHANGELOG.md +147 -0
  2. package/README.md +289 -55
  3. package/architecture_demo.js +247 -0
  4. package/bsv-covenant.min.js +10 -0
  5. package/bsv-gdaf.min.js +37 -0
  6. package/bsv-ltp.min.js +37 -0
  7. package/bsv-script-helper.min.js +10 -0
  8. package/bsv-security.min.js +31 -0
  9. package/bsv-shamir.min.js +12 -0
  10. package/bsv-smartcontract.min.js +37 -0
  11. package/bsv.bundle.js +9 -9
  12. package/bsv.min.js +3 -3
  13. package/build/bsv-covenant.min.js +10 -0
  14. package/build/bsv-script-helper.min.js +10 -0
  15. package/build/bsv-security.min.js +31 -0
  16. package/build/bsv-smartcontract.min.js +39 -0
  17. package/build/bsv.bundle.js +39 -0
  18. package/build/bsv.min.js +39 -0
  19. package/build/webpack.bundle.config.js +22 -0
  20. package/build/webpack.config.js +18 -0
  21. package/build/webpack.covenant.config.js +27 -0
  22. package/build/webpack.gdaf.config.js +54 -0
  23. package/build/webpack.ltp.config.js +17 -0
  24. package/build/webpack.script-helper.config.js +27 -0
  25. package/build/webpack.security.config.js +23 -0
  26. package/build/webpack.smartcontract.config.js +25 -0
  27. package/build/webpack.subproject.config.js +6 -0
  28. package/bundle-entry.js +341 -0
  29. package/complete_ltp_demo.js +511 -0
  30. package/covenant-entry.js +44 -0
  31. package/docs/pushtx-key-insights.md +106 -0
  32. package/gdaf-entry.js +54 -0
  33. package/index.js +272 -5
  34. package/lib/crypto/shamir.js +360 -0
  35. package/lib/gdaf/attestation-signer.js +461 -0
  36. package/lib/gdaf/attestation-verifier.js +600 -0
  37. package/lib/gdaf/did-resolver.js +382 -0
  38. package/lib/gdaf/index.js +471 -0
  39. package/lib/gdaf/schema-validator.js +682 -0
  40. package/lib/gdaf/smartledger-anchor.js +486 -0
  41. package/lib/gdaf/zk-prover.js +507 -0
  42. package/lib/ltp/anchor.js +438 -0
  43. package/lib/ltp/claim.js +1026 -0
  44. package/lib/ltp/index.js +470 -0
  45. package/lib/ltp/obligation.js +945 -0
  46. package/lib/ltp/proof.js +828 -0
  47. package/lib/ltp/registry.js +702 -0
  48. package/lib/ltp/right.js +765 -0
  49. package/lib/smart_contract/API_REFERENCE.md +1 -1
  50. package/lib/smart_contract/EXAMPLES.md +2 -2
  51. package/lib/smart_contract/QUICK_START.md +2 -2
  52. package/lib/smart_contract/README.md +1 -1
  53. package/lib/smart_contract/index.js +4 -0
  54. package/ltp-entry.js +92 -0
  55. package/package.json +91 -20
  56. package/script-helper-entry.js +49 -0
  57. package/security-entry.js +70 -0
  58. package/shamir-entry.js +173 -0
  59. package/shamir_demo.js +121 -0
  60. package/simple_demo.js +204 -0
  61. package/smartcontract-entry.js +133 -0
  62. package/test_shamir.js +221 -0
  63. package/test_standalone_shamir.html +83 -0
  64. package/tests/bundle-completeness-test.html +131 -0
  65. package/tests/bundle-demo.html +476 -0
  66. package/tests/smartcontract-test.html +239 -0
  67. package/tests/standalone-modules-test.html +260 -0
  68. package/tests/test.html +612 -0
  69. package/tests/unpkg-demo.html +194 -0
  70. package/docs/nchain.md +0 -958
@@ -0,0 +1,945 @@
1
+ 'use strict'
2
+
3
+ var bsv = require('../../')
4
+ var Hash = bsv.crypto.Hash
5
+ var ECDSA = bsv.crypto.ECDSA
6
+ var PrivateKey = bsv.PrivateKey
7
+ var $ = bsv.util.preconditions
8
+
9
+ /**
10
+ * Legal Token Protocol - Obligation Creation Primitives
11
+ *
12
+ * Provides primitives for legal obligation token creation, validation, and management
13
+ * without direct blockchain publishing. External systems handle obligation storage
14
+ * and blockchain anchoring operations.
15
+ */
16
+
17
+ /**
18
+ * Obligation Types
19
+ */
20
+ var ObligationTypes = {
21
+ CORRELATIVE_OBLIGATION: 'CorrelativeObligation',
22
+ CONTRACTUAL_OBLIGATION: 'ContractualObligation',
23
+ PAYMENT_OBLIGATION: 'PaymentObligation',
24
+ DELIVERY_OBLIGATION: 'DeliveryObligation',
25
+ PERFORMANCE_OBLIGATION: 'PerformanceObligation',
26
+ MAINTENANCE_OBLIGATION: 'MaintenanceObligation',
27
+ COMPLIANCE_OBLIGATION: 'ComplianceObligation',
28
+ REPORTING_OBLIGATION: 'ReportingObligation',
29
+ CONFIDENTIALITY_OBLIGATION: 'ConfidentialityObligation',
30
+ NON_COMPETE_OBLIGATION: 'NonCompeteObligation',
31
+ INDEMNIFICATION_OBLIGATION: 'IndemnificationObligation',
32
+ WARRANTY_OBLIGATION: 'WarrantyObligation',
33
+ SUPPORT_OBLIGATION: 'SupportObligation',
34
+ REGULATORY_OBLIGATION: 'RegulatoryObligation',
35
+ FIDUCIARY_OBLIGATION: 'FiduciaryObligation'
36
+ }
37
+
38
+ /**
39
+ * Obligation Priority Levels
40
+ */
41
+ var ObligationPriority = {
42
+ CRITICAL: 'CRITICAL',
43
+ HIGH: 'HIGH',
44
+ MEDIUM: 'MEDIUM',
45
+ LOW: 'LOW',
46
+ DEFERRED: 'DEFERRED'
47
+ }
48
+
49
+ /**
50
+ * Obligation Status Values
51
+ */
52
+ var ObligationStatus = {
53
+ PENDING: 'PENDING',
54
+ ACTIVE: 'ACTIVE',
55
+ IN_PROGRESS: 'IN_PROGRESS',
56
+ COMPLETED: 'COMPLETED',
57
+ OVERDUE: 'OVERDUE',
58
+ BREACHED: 'BREACHED',
59
+ WAIVED: 'WAIVED',
60
+ TERMINATED: 'TERMINATED'
61
+ }
62
+
63
+ /**
64
+ * Legal Obligation Token
65
+ */
66
+ var ObligationToken = {
67
+
68
+ /**
69
+ * Prepare legal obligation token for external processing
70
+ * @param {String} type - Obligation type (from ObligationTypes)
71
+ * @param {String} issuerDID - Issuer DID
72
+ * @param {String} obligorDID - Obligor DID (who has the obligation)
73
+ * @param {Object} obligation - Obligation details
74
+ * @param {PrivateKey} issuerPrivateKey - Issuer's private key
75
+ * @param {Object} options - Additional options
76
+ * @returns {Object} Prepared legal obligation token data
77
+ */
78
+ prepareObligationToken: function(type, issuerDID, obligorDID, obligation, issuerPrivateKey, options) {
79
+ options = options || {}
80
+
81
+ $.checkArgument(typeof type === 'string', 'Obligation type must be string')
82
+ $.checkArgument(typeof issuerDID === 'string', 'Issuer DID must be string')
83
+ $.checkArgument(typeof obligorDID === 'string', 'Obligor DID must be string')
84
+ $.checkArgument(obligation && typeof obligation === 'object', 'Obligation must be object')
85
+ $.checkArgument(issuerPrivateKey instanceof PrivateKey, 'Invalid issuer private key')
86
+
87
+ // Validate obligation type
88
+ var validTypes = Object.values(ObligationTypes)
89
+ $.checkArgument(validTypes.includes(type), 'Invalid obligation type: ' + type)
90
+
91
+ try {
92
+ var obligationToken = {
93
+ '@context': [
94
+ 'https://www.w3.org/2018/credentials/v1',
95
+ 'https://smartledger.technology/contexts/ltp/v1'
96
+ ],
97
+ id: 'urn:uuid:' + this._generateUUID(),
98
+ type: ['VerifiableCredential', 'LegalObligationToken', type],
99
+ issuer: issuerDID,
100
+ issuanceDate: new Date().toISOString(),
101
+ credentialSubject: {
102
+ id: obligorDID,
103
+ obligationType: type,
104
+ obligation: obligation,
105
+ jurisdiction: options.jurisdiction || 'US',
106
+ priority: options.priority || ObligationPriority.MEDIUM,
107
+ status: ObligationStatus.PENDING,
108
+ dueDate: options.dueDate || null,
109
+ effectiveDate: options.effectiveDate || new Date().toISOString(),
110
+ expirationDate: options.expirationDate || null,
111
+ correlativeRight: options.correlativeRight || null,
112
+ rightHolder: options.rightHolder || null,
113
+ enforceable: options.enforceable !== false,
114
+ penalties: options.penalties || null,
115
+ remedies: options.remedies || null
116
+ }
117
+ }
118
+
119
+ // Add metadata
120
+ if (options.metadata) {
121
+ obligationToken.credentialSubject.metadata = options.metadata
122
+ }
123
+
124
+ // Sign the token
125
+ var signedToken = this._signToken(obligationToken, issuerPrivateKey)
126
+
127
+ return {
128
+ success: true,
129
+ obligationToken: signedToken,
130
+ tokenHash: signedToken.tokenHash,
131
+ metadata: {
132
+ type: type,
133
+ issuer: issuerDID,
134
+ obligor: obligorDID,
135
+ priority: obligationToken.credentialSubject.priority,
136
+ status: obligationToken.credentialSubject.status,
137
+ jurisdiction: obligationToken.credentialSubject.jurisdiction,
138
+ dueDate: obligationToken.credentialSubject.dueDate,
139
+ correlativeRight: obligationToken.credentialSubject.correlativeRight
140
+ },
141
+ externalOperations: {
142
+ storeToken: {
143
+ endpoint: 'POST /obligations/tokens',
144
+ data: {
145
+ token: signedToken,
146
+ metadata: {
147
+ type: type,
148
+ issuer: issuerDID,
149
+ obligor: obligorDID,
150
+ priority: obligationToken.credentialSubject.priority,
151
+ status: obligationToken.credentialSubject.status,
152
+ jurisdiction: obligationToken.credentialSubject.jurisdiction,
153
+ dueDate: obligationToken.credentialSubject.dueDate,
154
+ correlativeRight: obligationToken.credentialSubject.correlativeRight
155
+ }
156
+ }
157
+ },
158
+ indexToken: {
159
+ endpoint: 'POST /obligations/index',
160
+ data: {
161
+ tokenId: signedToken.id,
162
+ tokenHash: signedToken.tokenHash,
163
+ type: type,
164
+ issuer: issuerDID,
165
+ obligor: obligorDID,
166
+ issuedAt: signedToken.issuanceDate,
167
+ dueDate: obligationToken.credentialSubject.dueDate,
168
+ priority: obligationToken.credentialSubject.priority
169
+ }
170
+ },
171
+ notifyObligor: {
172
+ endpoint: 'POST /notifications/obligation-issued',
173
+ data: {
174
+ tokenId: signedToken.id,
175
+ issuer: issuerDID,
176
+ obligor: obligorDID,
177
+ obligationType: type,
178
+ dueDate: obligationToken.credentialSubject.dueDate,
179
+ priority: obligationToken.credentialSubject.priority
180
+ }
181
+ },
182
+ scheduleReminders: obligationToken.credentialSubject.dueDate ? {
183
+ endpoint: 'POST /obligations/schedule-reminders',
184
+ data: {
185
+ tokenId: signedToken.id,
186
+ obligor: obligorDID,
187
+ dueDate: obligationToken.credentialSubject.dueDate,
188
+ reminderSchedule: options.reminderSchedule || ['7d', '3d', '1d']
189
+ }
190
+ } : null
191
+ }
192
+ }
193
+
194
+ } catch (error) {
195
+ return {
196
+ success: false,
197
+ error: error.message
198
+ }
199
+ }
200
+ },
201
+
202
+ /**
203
+ * Prepare obligation verification for external processing
204
+ * @param {Object} token - Obligation token to verify
205
+ * @param {Object} options - Verification options
206
+ * @returns {Object} Prepared verification data
207
+ */
208
+ prepareObligationVerification: function(token, options) {
209
+ options = options || {}
210
+
211
+ try {
212
+ var errors = []
213
+ var warnings = []
214
+
215
+ // Basic structure validation
216
+ this._validateTokenStructure(token, errors)
217
+
218
+ // Signature verification
219
+ this._verifyTokenSignature(token, errors)
220
+
221
+ // Temporal validation
222
+ this._validateTokenTemporal(token, errors, warnings)
223
+
224
+ // Type validation
225
+ this._validateObligationType(token, errors)
226
+
227
+ // Status validation
228
+ this._validateObligationStatus(token, errors, warnings)
229
+
230
+ // Priority validation
231
+ this._validateObligationPriority(token, warnings)
232
+
233
+ var verification = {
234
+ valid: errors.length === 0,
235
+ errors: errors,
236
+ warnings: warnings,
237
+ issuerDID: token.issuer,
238
+ obligorDID: token.credentialSubject ? token.credentialSubject.id : null,
239
+ obligationType: token.credentialSubject ? token.credentialSubject.obligationType : null,
240
+ status: token.credentialSubject ? token.credentialSubject.status : null,
241
+ priority: token.credentialSubject ? token.credentialSubject.priority : null,
242
+ isOverdue: this._checkIfOverdue(token),
243
+ verifiedAt: new Date().toISOString()
244
+ }
245
+
246
+ return {
247
+ success: true,
248
+ verification: verification,
249
+ externalOperations: {
250
+ recordVerification: {
251
+ endpoint: 'POST /obligations/verification-record',
252
+ data: {
253
+ tokenId: token.id,
254
+ result: verification.valid,
255
+ errors: errors,
256
+ warnings: warnings,
257
+ verifiedAt: verification.verifiedAt,
258
+ isOverdue: verification.isOverdue
259
+ }
260
+ },
261
+ auditVerification: {
262
+ endpoint: 'POST /audit/obligation-verification',
263
+ data: {
264
+ tokenId: token.id,
265
+ obligationType: verification.obligationType,
266
+ issuer: verification.issuerDID,
267
+ obligor: verification.obligorDID,
268
+ result: verification.valid,
269
+ verifiedAt: verification.verifiedAt
270
+ }
271
+ },
272
+ updateStatus: verification.isOverdue && token.credentialSubject.status === ObligationStatus.ACTIVE ? {
273
+ endpoint: 'PUT /obligations/tokens/' + token.id + '/status',
274
+ data: {
275
+ status: ObligationStatus.OVERDUE,
276
+ updatedAt: verification.verifiedAt,
277
+ reason: 'Due date passed'
278
+ }
279
+ } : null
280
+ }
281
+ }
282
+
283
+ } catch (error) {
284
+ return {
285
+ success: false,
286
+ error: 'Verification preparation failed: ' + error.message
287
+ }
288
+ }
289
+ },
290
+
291
+ /**
292
+ * Prepare obligation fulfillment for external processing
293
+ * @param {Object} token - Obligation token
294
+ * @param {Object} fulfillment - Fulfillment details
295
+ * @param {PrivateKey} obligorKey - Obligor's private key
296
+ * @param {Object} options - Fulfillment options
297
+ * @returns {Object} Prepared fulfillment data
298
+ */
299
+ prepareObligationFulfillment: function(token, fulfillment, obligorKey, options) {
300
+ options = options || {}
301
+
302
+ $.checkArgument(token && typeof token === 'object', 'Invalid token')
303
+ $.checkArgument(fulfillment && typeof fulfillment === 'object', 'Invalid fulfillment')
304
+ $.checkArgument(obligorKey instanceof PrivateKey, 'Invalid obligor key')
305
+
306
+ try {
307
+ // Verify current token
308
+ var verification = this.prepareObligationVerification(token, {})
309
+ if (!verification.success || !verification.verification.valid) {
310
+ return {
311
+ success: false,
312
+ error: 'Cannot fulfill invalid obligation: ' + verification.verification.errors.join(', ')
313
+ }
314
+ }
315
+
316
+ // Check if obligation can be fulfilled
317
+ if (token.credentialSubject.status === ObligationStatus.COMPLETED) {
318
+ return {
319
+ success: false,
320
+ error: 'Obligation already fulfilled'
321
+ }
322
+ }
323
+
324
+ if (token.credentialSubject.status === ObligationStatus.TERMINATED) {
325
+ return {
326
+ success: false,
327
+ error: 'Obligation has been terminated'
328
+ }
329
+ }
330
+
331
+ // Create fulfillment record
332
+ var fulfillmentRecord = {
333
+ '@context': [
334
+ 'https://www.w3.org/2018/credentials/v1',
335
+ 'https://smartledger.technology/contexts/ltp/v1'
336
+ ],
337
+ id: 'urn:uuid:' + this._generateUUID(),
338
+ type: ['VerifiableCredential', 'ObligationFulfillment'],
339
+ issuer: token.credentialSubject.id, // Obligor
340
+ issuanceDate: new Date().toISOString(),
341
+ credentialSubject: {
342
+ id: token.id, // References the obligation
343
+ fulfillmentType: fulfillment.type || 'FULL_FULFILLMENT',
344
+ fulfillmentDate: new Date().toISOString(),
345
+ evidence: fulfillment.evidence || null,
346
+ description: fulfillment.description || '',
347
+ completionPercentage: fulfillment.completionPercentage || 100,
348
+ attestations: fulfillment.attestations || [],
349
+ notes: fulfillment.notes || null
350
+ }
351
+ }
352
+
353
+ // Sign fulfillment with obligor key
354
+ var signedFulfillment = this._signToken(fulfillmentRecord, obligorKey)
355
+
356
+ // Determine new obligation status
357
+ var newStatus = fulfillmentRecord.credentialSubject.completionPercentage >= 100 ?
358
+ ObligationStatus.COMPLETED :
359
+ ObligationStatus.IN_PROGRESS
360
+
361
+ return {
362
+ success: true,
363
+ fulfillmentRecord: signedFulfillment,
364
+ newStatus: newStatus,
365
+ fulfillmentId: signedFulfillment.id,
366
+ externalOperations: {
367
+ recordFulfillment: {
368
+ endpoint: 'POST /obligations/fulfillments',
369
+ data: {
370
+ obligationId: token.id,
371
+ fulfillmentRecord: signedFulfillment,
372
+ obligor: token.credentialSubject.id,
373
+ fulfillmentDate: fulfillmentRecord.credentialSubject.fulfillmentDate,
374
+ completionPercentage: fulfillmentRecord.credentialSubject.completionPercentage
375
+ }
376
+ },
377
+ updateStatus: {
378
+ endpoint: 'PUT /obligations/tokens/' + token.id + '/status',
379
+ data: {
380
+ status: newStatus,
381
+ fulfillmentId: signedFulfillment.id,
382
+ updatedAt: fulfillmentRecord.credentialSubject.fulfillmentDate,
383
+ completionPercentage: fulfillmentRecord.credentialSubject.completionPercentage
384
+ }
385
+ },
386
+ notifyRightHolder: token.credentialSubject.rightHolder ? {
387
+ endpoint: 'POST /notifications/obligation-fulfilled',
388
+ data: {
389
+ obligationId: token.id,
390
+ fulfillmentId: signedFulfillment.id,
391
+ obligor: token.credentialSubject.id,
392
+ rightHolder: token.credentialSubject.rightHolder,
393
+ completionPercentage: fulfillmentRecord.credentialSubject.completionPercentage,
394
+ newStatus: newStatus
395
+ }
396
+ } : null,
397
+ auditFulfillment: {
398
+ endpoint: 'POST /audit/obligation-fulfillment',
399
+ data: {
400
+ obligationId: token.id,
401
+ fulfillmentId: signedFulfillment.id,
402
+ obligor: token.credentialSubject.id,
403
+ fulfilledAt: fulfillmentRecord.credentialSubject.fulfillmentDate,
404
+ completionPercentage: fulfillmentRecord.credentialSubject.completionPercentage
405
+ }
406
+ }
407
+ }
408
+ }
409
+
410
+ } catch (error) {
411
+ return {
412
+ success: false,
413
+ error: error.message
414
+ }
415
+ }
416
+ },
417
+
418
+ /**
419
+ * Prepare obligation breach assessment for external processing
420
+ * @param {Object} token - Obligation token
421
+ * @param {Object} breach - Breach details
422
+ * @param {Object} assessor - Assessor information
423
+ * @returns {Object} Prepared breach assessment data
424
+ */
425
+ prepareObligationBreachAssessment: function(token, breach, assessor) {
426
+ $.checkArgument(token && typeof token === 'object', 'Invalid token')
427
+ $.checkArgument(breach && typeof breach === 'object', 'Invalid breach details')
428
+ $.checkArgument(assessor && typeof assessor === 'object', 'Invalid assessor')
429
+
430
+ try {
431
+ var breachAssessment = {
432
+ '@context': [
433
+ 'https://www.w3.org/2018/credentials/v1',
434
+ 'https://smartledger.technology/contexts/ltp/v1'
435
+ ],
436
+ id: 'urn:uuid:' + this._generateUUID(),
437
+ type: ['VerifiableCredential', 'ObligationBreachAssessment'],
438
+ issuer: assessor.did || assessor.id,
439
+ issuanceDate: new Date().toISOString(),
440
+ credentialSubject: {
441
+ id: token.id, // References the obligation
442
+ breachType: breach.type || 'MATERIAL_BREACH',
443
+ breachDate: breach.date || new Date().toISOString(),
444
+ description: breach.description || '',
445
+ severity: breach.severity || 'MODERATE',
446
+ evidence: breach.evidence || [],
447
+ assessor: {
448
+ did: assessor.did || assessor.id,
449
+ name: assessor.name || 'Unknown',
450
+ authority: assessor.authority || null,
451
+ jurisdiction: assessor.jurisdiction || null
452
+ },
453
+ damages: breach.damages || null,
454
+ recommendedRemedies: breach.recommendedRemedies || [],
455
+ assessmentDate: new Date().toISOString()
456
+ }
457
+ }
458
+
459
+ var breachHash = Hash.sha256(Buffer.from(JSON.stringify(breachAssessment))).toString('hex')
460
+ breachAssessment.credentialSubject.assessmentHash = breachHash
461
+
462
+ return {
463
+ success: true,
464
+ breachAssessment: breachAssessment,
465
+ breachId: breachAssessment.id,
466
+ severity: breach.severity || 'MODERATE',
467
+ externalOperations: {
468
+ recordBreach: {
469
+ endpoint: 'POST /obligations/breaches',
470
+ data: {
471
+ obligationId: token.id,
472
+ breachAssessment: breachAssessment,
473
+ obligor: token.credentialSubject.id,
474
+ rightHolder: token.credentialSubject.rightHolder,
475
+ breachDate: breach.date || new Date().toISOString(),
476
+ severity: breach.severity || 'MODERATE'
477
+ }
478
+ },
479
+ updateStatus: {
480
+ endpoint: 'PUT /obligations/tokens/' + token.id + '/status',
481
+ data: {
482
+ status: ObligationStatus.BREACHED,
483
+ breachId: breachAssessment.id,
484
+ breachDate: breach.date || new Date().toISOString(),
485
+ updatedAt: new Date().toISOString()
486
+ }
487
+ },
488
+ notifyParties: {
489
+ endpoint: 'POST /notifications/obligation-breached',
490
+ data: {
491
+ obligationId: token.id,
492
+ breachId: breachAssessment.id,
493
+ obligor: token.credentialSubject.id,
494
+ rightHolder: token.credentialSubject.rightHolder,
495
+ breachType: breach.type || 'MATERIAL_BREACH',
496
+ severity: breach.severity || 'MODERATE'
497
+ }
498
+ },
499
+ escalateBreach: breach.severity === 'CRITICAL' ? {
500
+ endpoint: 'POST /legal/escalate-breach',
501
+ data: {
502
+ obligationId: token.id,
503
+ breachId: breachAssessment.id,
504
+ severity: breach.severity,
505
+ jurisdiction: token.credentialSubject.jurisdiction
506
+ }
507
+ } : null,
508
+ auditBreach: {
509
+ endpoint: 'POST /audit/obligation-breach',
510
+ data: {
511
+ obligationId: token.id,
512
+ breachId: breachAssessment.id,
513
+ obligor: token.credentialSubject.id,
514
+ assessedAt: breachAssessment.credentialSubject.assessmentDate,
515
+ severity: breach.severity || 'MODERATE'
516
+ }
517
+ }
518
+ }
519
+ }
520
+
521
+ } catch (error) {
522
+ return {
523
+ success: false,
524
+ error: error.message
525
+ }
526
+ }
527
+ },
528
+
529
+ /**
530
+ * Prepare obligation monitoring report for external processing
531
+ * @param {Array} obligations - Array of obligation tokens
532
+ * @param {Object} criteria - Monitoring criteria
533
+ * @returns {Object} Prepared monitoring report data
534
+ */
535
+ prepareObligationMonitoringReport: function(obligations, criteria) {
536
+ criteria = criteria || {}
537
+
538
+ $.checkArgument(Array.isArray(obligations), 'Obligations must be array')
539
+
540
+ try {
541
+ var report = {
542
+ reportId: 'rpt_' + this._generateUUID(),
543
+ generatedAt: new Date().toISOString(),
544
+ criteria: criteria,
545
+ summary: {
546
+ totalObligations: obligations.length,
547
+ byStatus: {},
548
+ byPriority: {},
549
+ byType: {},
550
+ overdue: 0,
551
+ dueSoon: 0,
552
+ completed: 0
553
+ },
554
+ obligations: [],
555
+ alerts: [],
556
+ recommendations: []
557
+ }
558
+
559
+ var now = new Date()
560
+ var sevenDaysFromNow = new Date(now.getTime() + (7 * 24 * 60 * 60 * 1000))
561
+
562
+ obligations.forEach(function(obligation) {
563
+ var obligationData = {
564
+ id: obligation.id,
565
+ type: obligation.credentialSubject.obligationType,
566
+ status: obligation.credentialSubject.status,
567
+ priority: obligation.credentialSubject.priority,
568
+ obligor: obligation.credentialSubject.id,
569
+ dueDate: obligation.credentialSubject.dueDate,
570
+ isOverdue: this._checkIfOverdue(obligation),
571
+ isDueSoon: false
572
+ }
573
+
574
+ // Check if due soon
575
+ if (obligation.credentialSubject.dueDate) {
576
+ var dueDate = new Date(obligation.credentialSubject.dueDate)
577
+ obligationData.isDueSoon = dueDate <= sevenDaysFromNow && dueDate > now
578
+ }
579
+
580
+ // Update summaries
581
+ report.summary.byStatus[obligationData.status] = (report.summary.byStatus[obligationData.status] || 0) + 1
582
+ report.summary.byPriority[obligationData.priority] = (report.summary.byPriority[obligationData.priority] || 0) + 1
583
+ report.summary.byType[obligationData.type] = (report.summary.byType[obligationData.type] || 0) + 1
584
+
585
+ if (obligationData.isOverdue) report.summary.overdue++
586
+ if (obligationData.isDueSoon) report.summary.dueSoon++
587
+ if (obligationData.status === ObligationStatus.COMPLETED) report.summary.completed++
588
+
589
+ // Generate alerts
590
+ if (obligationData.isOverdue && obligationData.priority === ObligationPriority.CRITICAL) {
591
+ report.alerts.push({
592
+ type: 'CRITICAL_OVERDUE',
593
+ obligationId: obligation.id,
594
+ message: 'Critical obligation is overdue',
595
+ priority: 'HIGH'
596
+ })
597
+ }
598
+
599
+ if (obligationData.isDueSoon && obligationData.priority === ObligationPriority.HIGH) {
600
+ report.alerts.push({
601
+ type: 'HIGH_PRIORITY_DUE_SOON',
602
+ obligationId: obligation.id,
603
+ message: 'High priority obligation due soon',
604
+ priority: 'MEDIUM'
605
+ })
606
+ }
607
+
608
+ report.obligations.push(obligationData)
609
+ }.bind(this))
610
+
611
+ // Generate recommendations
612
+ if (report.summary.overdue > 0) {
613
+ report.recommendations.push({
614
+ type: 'OVERDUE_MANAGEMENT',
615
+ message: 'Consider prioritizing overdue obligations',
616
+ count: report.summary.overdue
617
+ })
618
+ }
619
+
620
+ if (report.summary.dueSoon > 5) {
621
+ report.recommendations.push({
622
+ type: 'WORKLOAD_MANAGEMENT',
623
+ message: 'High number of obligations due soon - consider workload distribution',
624
+ count: report.summary.dueSoon
625
+ })
626
+ }
627
+
628
+ return {
629
+ success: true,
630
+ report: report,
631
+ externalOperations: {
632
+ storeReport: {
633
+ endpoint: 'POST /obligations/monitoring-reports',
634
+ data: {
635
+ report: report,
636
+ generatedAt: report.generatedAt
637
+ }
638
+ },
639
+ sendAlerts: report.alerts.length > 0 ? {
640
+ endpoint: 'POST /notifications/obligation-alerts',
641
+ data: {
642
+ reportId: report.reportId,
643
+ alerts: report.alerts,
644
+ summary: report.summary
645
+ }
646
+ } : null,
647
+ updateDashboard: {
648
+ endpoint: 'PUT /dashboard/obligation-metrics',
649
+ data: {
650
+ summary: report.summary,
651
+ lastUpdated: report.generatedAt
652
+ }
653
+ }
654
+ }
655
+ }
656
+
657
+ } catch (error) {
658
+ return {
659
+ success: false,
660
+ error: error.message
661
+ }
662
+ }
663
+ },
664
+
665
+ /**
666
+ * Get available obligation types
667
+ * @returns {Object} Obligation types
668
+ */
669
+ getObligationTypes: function() {
670
+ return ObligationTypes
671
+ },
672
+
673
+ /**
674
+ * Get obligation priority levels
675
+ * @returns {Object} Priority levels
676
+ */
677
+ getObligationPriority: function() {
678
+ return ObligationPriority
679
+ },
680
+
681
+ /**
682
+ * Get obligation status values
683
+ * @returns {Object} Status values
684
+ */
685
+ getObligationStatus: function() {
686
+ return ObligationStatus
687
+ },
688
+
689
+ /**
690
+ * Sign a token with private key
691
+ * @private
692
+ */
693
+ _signToken: function(token, privateKey) {
694
+ // Create canonical hash
695
+ var canonicalToken = this._canonicalizeToken(token)
696
+ var tokenHash = Hash.sha256(Buffer.from(canonicalToken))
697
+
698
+ // Sign with ECDSA
699
+ var ecdsa = new ECDSA()
700
+ ecdsa.hashbuf = tokenHash
701
+ ecdsa.privkey = privateKey
702
+ ecdsa.pubkey = privateKey.toPublicKey()
703
+
704
+ ecdsa.sign()
705
+ var signature = ecdsa.sig
706
+
707
+ // Create proof
708
+ var proof = {
709
+ type: 'EcdsaSecp256k1Signature2019',
710
+ created: new Date().toISOString(),
711
+ verificationMethod: 'did:smartledger:' + privateKey.toPublicKey().toString() + '#keys-1',
712
+ proofPurpose: 'assertionMethod',
713
+ jws: this._createJWS(tokenHash, signature)
714
+ }
715
+
716
+ // Add proof to token
717
+ var signedToken = JSON.parse(JSON.stringify(token))
718
+ signedToken.proof = proof
719
+ signedToken.tokenHash = tokenHash.toString('hex')
720
+
721
+ return signedToken
722
+ },
723
+
724
+ /**
725
+ * Create JWS signature
726
+ * @private
727
+ */
728
+ _createJWS: function(hash, signature) {
729
+ var header = {
730
+ alg: 'ES256K',
731
+ typ: 'JWT'
732
+ }
733
+
734
+ var headerB64 = Buffer.from(JSON.stringify(header)).toString('base64url')
735
+ var payloadB64 = hash.toString('base64url')
736
+ var signatureB64 = signature.toDER().toString('base64url')
737
+
738
+ return headerB64 + '..' + signatureB64
739
+ },
740
+
741
+ /**
742
+ * Canonicalize token for hashing
743
+ * @private
744
+ */
745
+ _canonicalizeToken: function(token) {
746
+ // Remove proof and hash fields
747
+ var canonical = JSON.parse(JSON.stringify(token))
748
+ delete canonical.proof
749
+ delete canonical.tokenHash
750
+
751
+ // Sort keys recursively
752
+ return JSON.stringify(this._sortObjectKeys(canonical))
753
+ },
754
+
755
+ /**
756
+ * Sort object keys recursively
757
+ * @private
758
+ */
759
+ _sortObjectKeys: function(obj) {
760
+ if (Array.isArray(obj)) {
761
+ return obj.map(this._sortObjectKeys.bind(this))
762
+ } else if (obj !== null && typeof obj === 'object') {
763
+ var sorted = {}
764
+ Object.keys(obj).sort().forEach(function(key) {
765
+ sorted[key] = this._sortObjectKeys(obj[key])
766
+ }.bind(this))
767
+ return sorted
768
+ }
769
+ return obj
770
+ },
771
+
772
+ /**
773
+ * Validate token structure
774
+ * @private
775
+ */
776
+ _validateTokenStructure: function(token, errors) {
777
+ if (!token['@context']) {
778
+ errors.push('Missing @context')
779
+ }
780
+
781
+ if (!token.id) {
782
+ errors.push('Missing id')
783
+ }
784
+
785
+ if (!token.type || !Array.isArray(token.type)) {
786
+ errors.push('Missing or invalid type')
787
+ }
788
+
789
+ if (!token.issuer) {
790
+ errors.push('Missing issuer')
791
+ }
792
+
793
+ if (!token.issuanceDate) {
794
+ errors.push('Missing issuanceDate')
795
+ }
796
+
797
+ if (!token.credentialSubject) {
798
+ errors.push('Missing credentialSubject')
799
+ }
800
+
801
+ if (!token.proof) {
802
+ errors.push('Missing proof')
803
+ }
804
+ },
805
+
806
+ /**
807
+ * Verify token signature
808
+ * @private
809
+ */
810
+ _verifyTokenSignature: function(token, errors) {
811
+ try {
812
+ if (!token.proof || !token.proof.jws) {
813
+ errors.push('Missing signature proof')
814
+ return
815
+ }
816
+
817
+ // Recreate canonical hash
818
+ var canonicalToken = this._canonicalizeToken(token)
819
+ var expectedHash = Hash.sha256(Buffer.from(canonicalToken))
820
+
821
+ // Compare with stored hash if available
822
+ if (token.tokenHash && token.tokenHash !== expectedHash.toString('hex')) {
823
+ errors.push('Token hash mismatch')
824
+ return
825
+ }
826
+
827
+ // TODO: Verify JWS signature with issuer's public key
828
+ // This would require DID resolution to get the public key
829
+
830
+ } catch (error) {
831
+ errors.push('Signature verification failed: ' + error.message)
832
+ }
833
+ },
834
+
835
+ /**
836
+ * Validate temporal aspects
837
+ * @private
838
+ */
839
+ _validateTokenTemporal: function(token, errors, warnings) {
840
+ var now = new Date()
841
+ var issuanceDate = new Date(token.issuanceDate)
842
+
843
+ if (issuanceDate > now) {
844
+ errors.push('Token issued in the future')
845
+ }
846
+
847
+ if (token.credentialSubject.effectiveDate) {
848
+ var effectiveDate = new Date(token.credentialSubject.effectiveDate)
849
+ if (now < effectiveDate) {
850
+ warnings.push('Obligation not yet effective')
851
+ }
852
+ }
853
+
854
+ if (token.credentialSubject.expirationDate) {
855
+ var expirationDate = new Date(token.credentialSubject.expirationDate)
856
+ if (now > expirationDate) {
857
+ errors.push('Obligation expired')
858
+ }
859
+ }
860
+ },
861
+
862
+ /**
863
+ * Validate obligation type
864
+ * @private
865
+ */
866
+ _validateObligationType: function(token, errors) {
867
+ if (!token.credentialSubject.obligationType) {
868
+ errors.push('Missing obligationType')
869
+ return
870
+ }
871
+
872
+ var validTypes = Object.values(ObligationTypes)
873
+ if (!validTypes.includes(token.credentialSubject.obligationType)) {
874
+ errors.push('Invalid obligation type: ' + token.credentialSubject.obligationType)
875
+ }
876
+ },
877
+
878
+ /**
879
+ * Validate obligation status
880
+ * @private
881
+ */
882
+ _validateObligationStatus: function(token, errors, warnings) {
883
+ if (!token.credentialSubject.status) {
884
+ errors.push('Missing status')
885
+ return
886
+ }
887
+
888
+ var validStatuses = Object.values(ObligationStatus)
889
+ if (!validStatuses.includes(token.credentialSubject.status)) {
890
+ errors.push('Invalid obligation status: ' + token.credentialSubject.status)
891
+ }
892
+
893
+ // Check for overdue obligations
894
+ if (this._checkIfOverdue(token) && token.credentialSubject.status === ObligationStatus.ACTIVE) {
895
+ warnings.push('Obligation is overdue but status is still ACTIVE')
896
+ }
897
+ },
898
+
899
+ /**
900
+ * Validate obligation priority
901
+ * @private
902
+ */
903
+ _validateObligationPriority: function(token, warnings) {
904
+ if (token.credentialSubject.priority) {
905
+ var validPriorities = Object.values(ObligationPriority)
906
+ if (!validPriorities.includes(token.credentialSubject.priority)) {
907
+ warnings.push('Invalid obligation priority: ' + token.credentialSubject.priority)
908
+ }
909
+ }
910
+ },
911
+
912
+ /**
913
+ * Check if obligation is overdue
914
+ * @private
915
+ */
916
+ _checkIfOverdue: function(token) {
917
+ if (!token.credentialSubject.dueDate) {
918
+ return false
919
+ }
920
+
921
+ var now = new Date()
922
+ var dueDate = new Date(token.credentialSubject.dueDate)
923
+
924
+ return now > dueDate && token.credentialSubject.status !== ObligationStatus.COMPLETED
925
+ },
926
+
927
+ /**
928
+ * Generate UUID
929
+ * @private
930
+ */
931
+ _generateUUID: function() {
932
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
933
+ var r = Math.random() * 16 | 0
934
+ var v = c === 'x' ? r : (r & 0x3 | 0x8)
935
+ return v.toString(16)
936
+ })
937
+ }
938
+ }
939
+
940
+ // Export static references for compatibility
941
+ ObligationToken.ObligationTypes = ObligationTypes
942
+ ObligationToken.ObligationPriority = ObligationPriority
943
+ ObligationToken.ObligationStatus = ObligationStatus
944
+
945
+ module.exports = ObligationToken