@originals/sdk 1.4.3 → 1.4.5
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/dist/adapters/FeeOracleMock.d.ts +6 -0
- package/dist/adapters/FeeOracleMock.js +8 -0
- package/dist/adapters/index.d.ts +4 -0
- package/dist/adapters/index.js +4 -0
- package/dist/adapters/providers/OrdHttpProvider.d.ts +56 -0
- package/dist/adapters/providers/OrdHttpProvider.js +110 -0
- package/dist/adapters/providers/OrdMockProvider.d.ts +70 -0
- package/dist/adapters/providers/OrdMockProvider.js +75 -0
- package/dist/adapters/types.d.ts +71 -0
- package/dist/adapters/types.js +1 -0
- package/dist/bitcoin/BitcoinManager.d.ts +15 -0
- package/dist/bitcoin/BitcoinManager.js +262 -0
- package/dist/bitcoin/BroadcastClient.d.ts +30 -0
- package/dist/bitcoin/BroadcastClient.js +35 -0
- package/dist/bitcoin/OrdinalsClient.d.ts +21 -0
- package/dist/bitcoin/OrdinalsClient.js +105 -0
- package/dist/bitcoin/PSBTBuilder.d.ts +24 -0
- package/dist/bitcoin/PSBTBuilder.js +80 -0
- package/dist/bitcoin/fee-calculation.d.ts +14 -0
- package/dist/bitcoin/fee-calculation.js +31 -0
- package/dist/bitcoin/providers/OrdNodeProvider.d.ts +38 -0
- package/dist/bitcoin/providers/OrdNodeProvider.js +67 -0
- package/dist/bitcoin/providers/OrdinalsProvider.d.ts +33 -0
- package/dist/bitcoin/providers/OrdinalsProvider.js +50 -0
- package/dist/bitcoin/providers/types.d.ts +63 -0
- package/dist/bitcoin/providers/types.js +1 -0
- package/dist/bitcoin/transactions/commit.d.ts +89 -0
- package/dist/bitcoin/transactions/commit.js +311 -0
- package/dist/bitcoin/transactions/index.d.ts +7 -0
- package/dist/bitcoin/transactions/index.js +8 -0
- package/dist/bitcoin/transfer.d.ts +9 -0
- package/dist/bitcoin/transfer.js +26 -0
- package/dist/bitcoin/utxo-selection.d.ts +78 -0
- package/dist/bitcoin/utxo-selection.js +237 -0
- package/dist/bitcoin/utxo.d.ts +26 -0
- package/dist/bitcoin/utxo.js +78 -0
- package/dist/contexts/credentials-v1.json +195 -0
- package/dist/contexts/credentials-v2-examples.json +5 -0
- package/dist/contexts/credentials-v2.json +301 -0
- package/dist/contexts/credentials.json +195 -0
- package/dist/contexts/data-integrity-v2.json +81 -0
- package/dist/contexts/dids.json +57 -0
- package/dist/contexts/ed255192020.json +93 -0
- package/dist/contexts/ordinals-plus.json +23 -0
- package/dist/contexts/originals.json +22 -0
- package/dist/core/OriginalsSDK.d.ts +158 -0
- package/dist/core/OriginalsSDK.js +274 -0
- package/dist/crypto/Multikey.d.ts +30 -0
- package/dist/crypto/Multikey.js +149 -0
- package/dist/crypto/Signer.d.ts +21 -0
- package/dist/crypto/Signer.js +196 -0
- package/dist/crypto/noble-init.d.ts +18 -0
- package/dist/crypto/noble-init.js +106 -0
- package/dist/did/BtcoDidResolver.d.ts +57 -0
- package/dist/did/BtcoDidResolver.js +166 -0
- package/dist/did/DIDManager.d.ts +101 -0
- package/dist/did/DIDManager.js +493 -0
- package/dist/did/Ed25519Verifier.d.ts +30 -0
- package/dist/did/Ed25519Verifier.js +59 -0
- package/dist/did/KeyManager.d.ts +17 -0
- package/dist/did/KeyManager.js +207 -0
- package/dist/did/WebVHManager.d.ts +100 -0
- package/dist/did/WebVHManager.js +312 -0
- package/dist/did/createBtcoDidDocument.d.ts +10 -0
- package/dist/did/createBtcoDidDocument.js +42 -0
- package/dist/did/providers/OrdinalsClientProviderAdapter.d.ts +23 -0
- package/dist/did/providers/OrdinalsClientProviderAdapter.js +51 -0
- package/dist/events/EventEmitter.d.ts +115 -0
- package/dist/events/EventEmitter.js +198 -0
- package/dist/events/index.d.ts +7 -0
- package/dist/events/index.js +6 -0
- package/dist/events/types.d.ts +286 -0
- package/dist/events/types.js +9 -0
- package/dist/examples/basic-usage.d.ts +3 -0
- package/dist/examples/basic-usage.js +62 -0
- package/dist/examples/create-module-original.d.ts +32 -0
- package/dist/examples/create-module-original.js +376 -0
- package/dist/examples/full-lifecycle-flow.d.ts +56 -0
- package/dist/examples/full-lifecycle-flow.js +419 -0
- package/dist/examples/run.d.ts +12 -0
- package/dist/examples/run.js +51 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.js +52 -0
- package/dist/kinds/KindRegistry.d.ts +76 -0
- package/dist/kinds/KindRegistry.js +216 -0
- package/dist/kinds/index.d.ts +33 -0
- package/dist/kinds/index.js +36 -0
- package/dist/kinds/types.d.ts +363 -0
- package/dist/kinds/types.js +25 -0
- package/dist/kinds/validators/AgentValidator.d.ts +14 -0
- package/dist/kinds/validators/AgentValidator.js +155 -0
- package/dist/kinds/validators/AppValidator.d.ts +14 -0
- package/dist/kinds/validators/AppValidator.js +135 -0
- package/dist/kinds/validators/DatasetValidator.d.ts +14 -0
- package/dist/kinds/validators/DatasetValidator.js +148 -0
- package/dist/kinds/validators/DocumentValidator.d.ts +14 -0
- package/dist/kinds/validators/DocumentValidator.js +180 -0
- package/dist/kinds/validators/MediaValidator.d.ts +14 -0
- package/dist/kinds/validators/MediaValidator.js +172 -0
- package/dist/kinds/validators/ModuleValidator.d.ts +14 -0
- package/dist/kinds/validators/ModuleValidator.js +140 -0
- package/dist/kinds/validators/base.d.ts +96 -0
- package/dist/kinds/validators/base.js +218 -0
- package/dist/kinds/validators/index.d.ts +10 -0
- package/dist/kinds/validators/index.js +10 -0
- package/dist/lifecycle/BatchOperations.d.ts +147 -0
- package/dist/lifecycle/BatchOperations.js +251 -0
- package/dist/lifecycle/LifecycleManager.d.ts +362 -0
- package/dist/lifecycle/LifecycleManager.js +1692 -0
- package/dist/lifecycle/OriginalsAsset.d.ts +164 -0
- package/dist/lifecycle/OriginalsAsset.js +380 -0
- package/dist/lifecycle/ProvenanceQuery.d.ts +126 -0
- package/dist/lifecycle/ProvenanceQuery.js +220 -0
- package/dist/lifecycle/ResourceVersioning.d.ts +73 -0
- package/dist/lifecycle/ResourceVersioning.js +127 -0
- package/dist/migration/MigrationManager.d.ts +86 -0
- package/dist/migration/MigrationManager.js +412 -0
- package/dist/migration/audit/AuditLogger.d.ts +51 -0
- package/dist/migration/audit/AuditLogger.js +156 -0
- package/dist/migration/checkpoint/CheckpointManager.d.ts +31 -0
- package/dist/migration/checkpoint/CheckpointManager.js +96 -0
- package/dist/migration/checkpoint/CheckpointStorage.d.ts +26 -0
- package/dist/migration/checkpoint/CheckpointStorage.js +89 -0
- package/dist/migration/index.d.ts +22 -0
- package/dist/migration/index.js +27 -0
- package/dist/migration/operations/BaseMigration.d.ts +48 -0
- package/dist/migration/operations/BaseMigration.js +83 -0
- package/dist/migration/operations/PeerToBtcoMigration.d.ts +25 -0
- package/dist/migration/operations/PeerToBtcoMigration.js +67 -0
- package/dist/migration/operations/PeerToWebvhMigration.d.ts +19 -0
- package/dist/migration/operations/PeerToWebvhMigration.js +46 -0
- package/dist/migration/operations/WebvhToBtcoMigration.d.ts +25 -0
- package/dist/migration/operations/WebvhToBtcoMigration.js +67 -0
- package/dist/migration/rollback/RollbackManager.d.ts +29 -0
- package/dist/migration/rollback/RollbackManager.js +146 -0
- package/dist/migration/state/StateMachine.d.ts +25 -0
- package/dist/migration/state/StateMachine.js +76 -0
- package/dist/migration/state/StateTracker.d.ts +36 -0
- package/dist/migration/state/StateTracker.js +123 -0
- package/dist/migration/types.d.ts +306 -0
- package/dist/migration/types.js +33 -0
- package/dist/migration/validation/BitcoinValidator.d.ts +13 -0
- package/dist/migration/validation/BitcoinValidator.js +83 -0
- package/dist/migration/validation/CredentialValidator.d.ts +13 -0
- package/dist/migration/validation/CredentialValidator.js +46 -0
- package/dist/migration/validation/DIDCompatibilityValidator.d.ts +16 -0
- package/dist/migration/validation/DIDCompatibilityValidator.js +127 -0
- package/dist/migration/validation/LifecycleValidator.d.ts +10 -0
- package/dist/migration/validation/LifecycleValidator.js +52 -0
- package/dist/migration/validation/StorageValidator.d.ts +10 -0
- package/dist/migration/validation/StorageValidator.js +65 -0
- package/dist/migration/validation/ValidationPipeline.d.ts +29 -0
- package/dist/migration/validation/ValidationPipeline.js +180 -0
- package/dist/resources/ResourceManager.d.ts +231 -0
- package/dist/resources/ResourceManager.js +573 -0
- package/dist/resources/index.d.ts +11 -0
- package/dist/resources/index.js +10 -0
- package/dist/resources/types.d.ts +93 -0
- package/dist/resources/types.js +80 -0
- package/dist/storage/LocalStorageAdapter.d.ts +11 -0
- package/dist/storage/LocalStorageAdapter.js +53 -0
- package/dist/storage/MemoryStorageAdapter.d.ts +6 -0
- package/dist/storage/MemoryStorageAdapter.js +21 -0
- package/dist/storage/StorageAdapter.d.ts +16 -0
- package/dist/storage/StorageAdapter.js +1 -0
- package/dist/storage/index.d.ts +2 -0
- package/dist/storage/index.js +2 -0
- package/dist/types/bitcoin.d.ts +84 -0
- package/dist/types/bitcoin.js +1 -0
- package/dist/types/common.d.ts +82 -0
- package/dist/types/common.js +1 -0
- package/dist/types/credentials.d.ts +75 -0
- package/dist/types/credentials.js +1 -0
- package/dist/types/did.d.ts +26 -0
- package/dist/types/did.js +1 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.js +5 -0
- package/dist/types/network.d.ts +78 -0
- package/dist/types/network.js +145 -0
- package/dist/utils/EventLogger.d.ts +71 -0
- package/dist/utils/EventLogger.js +232 -0
- package/dist/utils/Logger.d.ts +106 -0
- package/dist/utils/Logger.js +257 -0
- package/dist/utils/MetricsCollector.d.ts +110 -0
- package/dist/utils/MetricsCollector.js +264 -0
- package/dist/utils/bitcoin-address.d.ts +38 -0
- package/dist/utils/bitcoin-address.js +113 -0
- package/dist/utils/cbor.d.ts +2 -0
- package/dist/utils/cbor.js +9 -0
- package/dist/utils/encoding.d.ts +37 -0
- package/dist/utils/encoding.js +120 -0
- package/dist/utils/hash.d.ts +1 -0
- package/dist/utils/hash.js +5 -0
- package/dist/utils/retry.d.ts +10 -0
- package/dist/utils/retry.js +35 -0
- package/dist/utils/satoshi-validation.d.ts +60 -0
- package/dist/utils/satoshi-validation.js +156 -0
- package/dist/utils/serialization.d.ts +14 -0
- package/dist/utils/serialization.js +76 -0
- package/dist/utils/telemetry.d.ts +17 -0
- package/dist/utils/telemetry.js +24 -0
- package/dist/utils/validation.d.ts +5 -0
- package/dist/utils/validation.js +98 -0
- package/dist/vc/CredentialManager.d.ts +329 -0
- package/dist/vc/CredentialManager.js +615 -0
- package/dist/vc/Issuer.d.ts +27 -0
- package/dist/vc/Issuer.js +70 -0
- package/dist/vc/Verifier.d.ts +16 -0
- package/dist/vc/Verifier.js +50 -0
- package/dist/vc/cryptosuites/bbs.d.ts +44 -0
- package/dist/vc/cryptosuites/bbs.js +213 -0
- package/dist/vc/cryptosuites/bbsSimple.d.ts +9 -0
- package/dist/vc/cryptosuites/bbsSimple.js +12 -0
- package/dist/vc/cryptosuites/eddsa.d.ts +30 -0
- package/dist/vc/cryptosuites/eddsa.js +81 -0
- package/dist/vc/documentLoader.d.ts +16 -0
- package/dist/vc/documentLoader.js +59 -0
- package/dist/vc/proofs/data-integrity.d.ts +21 -0
- package/dist/vc/proofs/data-integrity.js +15 -0
- package/dist/vc/utils/jsonld.d.ts +2 -0
- package/dist/vc/utils/jsonld.js +15 -0
- package/package.json +2 -1
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
// Initialize noble crypto libraries first (idempotent - safe to import multiple times)
|
|
2
|
+
import '../crypto/noble-init.js';
|
|
3
|
+
import * as secp256k1 from '@noble/secp256k1';
|
|
4
|
+
import * as ed25519 from '@noble/ed25519';
|
|
5
|
+
import { p256 } from '@noble/curves/p256';
|
|
6
|
+
import { multikey } from '../crypto/Multikey';
|
|
7
|
+
function toMultikeyType(type) {
|
|
8
|
+
if (type === 'ES256K')
|
|
9
|
+
return 'Secp256k1';
|
|
10
|
+
if (type === 'Ed25519')
|
|
11
|
+
return 'Ed25519';
|
|
12
|
+
if (type === 'ES256')
|
|
13
|
+
return 'P256';
|
|
14
|
+
throw new Error(`Unsupported key type: ${type}`);
|
|
15
|
+
}
|
|
16
|
+
function fromMultikeyType(type) {
|
|
17
|
+
if (type === 'Secp256k1')
|
|
18
|
+
return 'ES256K';
|
|
19
|
+
if (type === 'Ed25519')
|
|
20
|
+
return 'Ed25519';
|
|
21
|
+
if (type === 'P256')
|
|
22
|
+
return 'ES256';
|
|
23
|
+
throw new Error('Unsupported key type');
|
|
24
|
+
}
|
|
25
|
+
export class KeyManager {
|
|
26
|
+
constructor() {
|
|
27
|
+
// Noble crypto libraries are initialized via noble-init.ts (imported at SDK entry point)
|
|
28
|
+
// No initialization needed here
|
|
29
|
+
}
|
|
30
|
+
async generateKeyPair(type) {
|
|
31
|
+
if (type === 'ES256K') {
|
|
32
|
+
const privateKeyBytes = secp256k1.utils.randomPrivateKey();
|
|
33
|
+
const publicKeyBytes = secp256k1.getPublicKey(privateKeyBytes, true);
|
|
34
|
+
return {
|
|
35
|
+
privateKey: multikey.encodePrivateKey(privateKeyBytes, 'Secp256k1'),
|
|
36
|
+
publicKey: multikey.encodePublicKey(publicKeyBytes, 'Secp256k1')
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
if (type === 'Ed25519') {
|
|
40
|
+
const privateKeyBytes = ed25519.utils.randomPrivateKey();
|
|
41
|
+
const publicKeyBytes = await ed25519.getPublicKeyAsync(privateKeyBytes);
|
|
42
|
+
return {
|
|
43
|
+
privateKey: multikey.encodePrivateKey(privateKeyBytes, 'Ed25519'),
|
|
44
|
+
publicKey: multikey.encodePublicKey(publicKeyBytes, 'Ed25519')
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
if (type === 'ES256') {
|
|
48
|
+
const privateKeyBytes = p256.utils.randomPrivateKey();
|
|
49
|
+
const publicKeyBytes = p256.getPublicKey(privateKeyBytes, true);
|
|
50
|
+
return {
|
|
51
|
+
privateKey: multikey.encodePrivateKey(privateKeyBytes, 'P256'),
|
|
52
|
+
publicKey: multikey.encodePublicKey(publicKeyBytes, 'P256')
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
throw new Error(`Unsupported key type: ${type}`);
|
|
56
|
+
}
|
|
57
|
+
async rotateKeys(didDoc, newKeyPair) {
|
|
58
|
+
const multikeyContext = 'https://w3id.org/security/multikey/v1';
|
|
59
|
+
const securityContext = 'https://w3id.org/security/v1';
|
|
60
|
+
// Ensure required contexts are present
|
|
61
|
+
const updatedContext = [...didDoc['@context']];
|
|
62
|
+
if (!updatedContext.includes(multikeyContext)) {
|
|
63
|
+
updatedContext.push(multikeyContext);
|
|
64
|
+
}
|
|
65
|
+
if (!updatedContext.includes(securityContext)) {
|
|
66
|
+
updatedContext.push(securityContext);
|
|
67
|
+
}
|
|
68
|
+
// Generate new key ID
|
|
69
|
+
const existingKeys = didDoc.verificationMethod || [];
|
|
70
|
+
const keyIndex = existingKeys.length;
|
|
71
|
+
const newKeyId = `${didDoc.id}#keys-${keyIndex}`;
|
|
72
|
+
// Mark all existing verification methods as revoked with current timestamp
|
|
73
|
+
const revokedTimestamp = new Date().toISOString();
|
|
74
|
+
const revokedVerificationMethods = existingKeys.map(vm => ({
|
|
75
|
+
...vm,
|
|
76
|
+
revoked: revokedTimestamp
|
|
77
|
+
}));
|
|
78
|
+
// Create new verification method
|
|
79
|
+
const newVerificationMethod = {
|
|
80
|
+
id: newKeyId,
|
|
81
|
+
type: 'Multikey',
|
|
82
|
+
controller: didDoc.id,
|
|
83
|
+
publicKeyMultibase: newKeyPair.publicKey
|
|
84
|
+
};
|
|
85
|
+
// Update authentication and assertionMethod arrays to reference only the new key
|
|
86
|
+
const newKeyReference = newKeyId;
|
|
87
|
+
const updated = {
|
|
88
|
+
...didDoc,
|
|
89
|
+
'@context': updatedContext,
|
|
90
|
+
verificationMethod: [...revokedVerificationMethods, newVerificationMethod],
|
|
91
|
+
authentication: [newKeyReference],
|
|
92
|
+
assertionMethod: [newKeyReference]
|
|
93
|
+
};
|
|
94
|
+
// Preserve other properties if they exist
|
|
95
|
+
if (didDoc.keyAgreement) {
|
|
96
|
+
updated.keyAgreement = didDoc.keyAgreement;
|
|
97
|
+
}
|
|
98
|
+
if (didDoc.capabilityInvocation) {
|
|
99
|
+
updated.capabilityInvocation = didDoc.capabilityInvocation;
|
|
100
|
+
}
|
|
101
|
+
if (didDoc.capabilityDelegation) {
|
|
102
|
+
updated.capabilityDelegation = didDoc.capabilityDelegation;
|
|
103
|
+
}
|
|
104
|
+
if (didDoc.service) {
|
|
105
|
+
updated.service = didDoc.service;
|
|
106
|
+
}
|
|
107
|
+
return updated;
|
|
108
|
+
}
|
|
109
|
+
async recoverFromCompromise(didDoc) {
|
|
110
|
+
// Determine key type from existing verification methods or default to Ed25519
|
|
111
|
+
let keyType = 'Ed25519';
|
|
112
|
+
if (didDoc.verificationMethod && didDoc.verificationMethod.length > 0) {
|
|
113
|
+
try {
|
|
114
|
+
const firstKey = didDoc.verificationMethod[0];
|
|
115
|
+
const decoded = multikey.decodePublicKey(firstKey.publicKeyMultibase);
|
|
116
|
+
keyType = fromMultikeyType(decoded.type);
|
|
117
|
+
}
|
|
118
|
+
catch (e) {
|
|
119
|
+
// If decoding fails, use default Ed25519
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Generate new key pair
|
|
123
|
+
const newKeyPair = await this.generateKeyPair(keyType);
|
|
124
|
+
// Ensure required contexts
|
|
125
|
+
const multikeyContext = 'https://w3id.org/security/multikey/v1';
|
|
126
|
+
const securityContext = 'https://w3id.org/security/v1';
|
|
127
|
+
const credentialsContext = 'https://www.w3.org/2018/credentials/v1';
|
|
128
|
+
const updatedContext = [...didDoc['@context']];
|
|
129
|
+
if (!updatedContext.includes(multikeyContext)) {
|
|
130
|
+
updatedContext.push(multikeyContext);
|
|
131
|
+
}
|
|
132
|
+
if (!updatedContext.includes(securityContext)) {
|
|
133
|
+
updatedContext.push(securityContext);
|
|
134
|
+
}
|
|
135
|
+
// Mark all existing verification methods as compromised
|
|
136
|
+
const compromisedTimestamp = new Date().toISOString();
|
|
137
|
+
const existingKeys = didDoc.verificationMethod || [];
|
|
138
|
+
const compromisedVerificationMethods = existingKeys.map(vm => ({
|
|
139
|
+
...vm,
|
|
140
|
+
compromised: compromisedTimestamp
|
|
141
|
+
}));
|
|
142
|
+
// Collect IDs of compromised keys
|
|
143
|
+
const previousVerificationMethodIds = existingKeys.map(vm => vm.id);
|
|
144
|
+
// Generate new key ID
|
|
145
|
+
const keyIndex = existingKeys.length;
|
|
146
|
+
const newKeyId = `${didDoc.id}#keys-${keyIndex}`;
|
|
147
|
+
// Create new verification method
|
|
148
|
+
const newVerificationMethod = {
|
|
149
|
+
id: newKeyId,
|
|
150
|
+
type: 'Multikey',
|
|
151
|
+
controller: didDoc.id,
|
|
152
|
+
publicKeyMultibase: newKeyPair.publicKey
|
|
153
|
+
};
|
|
154
|
+
// Update DID document
|
|
155
|
+
const updatedDidDocument = {
|
|
156
|
+
...didDoc,
|
|
157
|
+
'@context': updatedContext,
|
|
158
|
+
verificationMethod: [...compromisedVerificationMethods, newVerificationMethod],
|
|
159
|
+
authentication: [newKeyId],
|
|
160
|
+
assertionMethod: [newKeyId]
|
|
161
|
+
};
|
|
162
|
+
// Preserve other properties
|
|
163
|
+
if (didDoc.keyAgreement) {
|
|
164
|
+
updatedDidDocument.keyAgreement = didDoc.keyAgreement;
|
|
165
|
+
}
|
|
166
|
+
if (didDoc.capabilityInvocation) {
|
|
167
|
+
updatedDidDocument.capabilityInvocation = didDoc.capabilityInvocation;
|
|
168
|
+
}
|
|
169
|
+
if (didDoc.capabilityDelegation) {
|
|
170
|
+
updatedDidDocument.capabilityDelegation = didDoc.capabilityDelegation;
|
|
171
|
+
}
|
|
172
|
+
if (didDoc.service) {
|
|
173
|
+
updatedDidDocument.service = didDoc.service;
|
|
174
|
+
}
|
|
175
|
+
// Create recovery credential
|
|
176
|
+
const recoveryCredential = {
|
|
177
|
+
'@context': [credentialsContext, securityContext],
|
|
178
|
+
type: ['VerifiableCredential', 'KeyRecoveryCredential'],
|
|
179
|
+
issuer: didDoc.id,
|
|
180
|
+
issuanceDate: compromisedTimestamp,
|
|
181
|
+
credentialSubject: {
|
|
182
|
+
id: didDoc.id,
|
|
183
|
+
recoveredAt: compromisedTimestamp,
|
|
184
|
+
recoveryReason: 'key_compromise',
|
|
185
|
+
previousVerificationMethods: previousVerificationMethodIds,
|
|
186
|
+
newVerificationMethod: newKeyId
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
return { didDocument: updatedDidDocument, recoveryCredential, newKeyPair };
|
|
190
|
+
}
|
|
191
|
+
encodePublicKeyMultibase(publicKey, type) {
|
|
192
|
+
const mkType = toMultikeyType(type);
|
|
193
|
+
return multikey.encodePublicKey(new Uint8Array(publicKey), mkType);
|
|
194
|
+
}
|
|
195
|
+
decodePublicKeyMultibase(encoded) {
|
|
196
|
+
if (!encoded || typeof encoded !== 'string') {
|
|
197
|
+
throw new Error('Invalid multibase string');
|
|
198
|
+
}
|
|
199
|
+
try {
|
|
200
|
+
const decoded = multikey.decodePublicKey(encoded);
|
|
201
|
+
return { key: Buffer.from(decoded.key), type: fromMultikeyType(decoded.type) };
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
throw new Error('Invalid multibase string');
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { DIDDocument, KeyPair, ExternalSigner, ExternalVerifier } from '../types';
|
|
2
|
+
interface VerificationMethod {
|
|
3
|
+
id?: string;
|
|
4
|
+
type: string;
|
|
5
|
+
controller?: string;
|
|
6
|
+
publicKeyMultibase: string;
|
|
7
|
+
secretKeyMultibase?: string;
|
|
8
|
+
purpose?: 'authentication' | 'assertionMethod' | 'keyAgreement' | 'capabilityInvocation' | 'capabilityDelegation';
|
|
9
|
+
}
|
|
10
|
+
interface DIDLogEntry {
|
|
11
|
+
versionId: string;
|
|
12
|
+
versionTime: string;
|
|
13
|
+
parameters: Record<string, unknown>;
|
|
14
|
+
state: Record<string, unknown>;
|
|
15
|
+
proof?: Record<string, unknown>[];
|
|
16
|
+
}
|
|
17
|
+
type DIDLog = DIDLogEntry[];
|
|
18
|
+
export interface CreateWebVHOptions {
|
|
19
|
+
domain: string;
|
|
20
|
+
keyPair?: KeyPair;
|
|
21
|
+
paths?: string[];
|
|
22
|
+
portable?: boolean;
|
|
23
|
+
outputDir?: string;
|
|
24
|
+
externalSigner?: ExternalSigner;
|
|
25
|
+
externalVerifier?: ExternalVerifier;
|
|
26
|
+
verificationMethods?: VerificationMethod[];
|
|
27
|
+
updateKeys?: string[];
|
|
28
|
+
}
|
|
29
|
+
export interface CreateWebVHResult {
|
|
30
|
+
did: string;
|
|
31
|
+
didDocument: DIDDocument;
|
|
32
|
+
log: DIDLog;
|
|
33
|
+
keyPair: KeyPair;
|
|
34
|
+
logPath?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* WebVH DID Manager for creating and managing did:webvh identifiers
|
|
38
|
+
*/
|
|
39
|
+
export declare class WebVHManager {
|
|
40
|
+
private keyManager;
|
|
41
|
+
constructor();
|
|
42
|
+
/**
|
|
43
|
+
* Creates a new did:webvh DID with proper cryptographic signing
|
|
44
|
+
* @param options - Creation options including domain and optional key pair or external signer
|
|
45
|
+
* @returns The created DID, document, log, and key pair (if generated)
|
|
46
|
+
*/
|
|
47
|
+
createDIDWebVH(options: CreateWebVHOptions): Promise<CreateWebVHResult>;
|
|
48
|
+
/**
|
|
49
|
+
* Validates a path segment to prevent directory traversal attacks
|
|
50
|
+
* @param segment - Path segment to validate
|
|
51
|
+
* @returns true if valid, false otherwise
|
|
52
|
+
*/
|
|
53
|
+
private isValidPathSegment;
|
|
54
|
+
/**
|
|
55
|
+
* Type guard to validate a DID document structure
|
|
56
|
+
* @param doc - Object to validate
|
|
57
|
+
* @returns true if the object is a valid DIDDocument
|
|
58
|
+
*/
|
|
59
|
+
private isDIDDocument;
|
|
60
|
+
/**
|
|
61
|
+
* Saves the DID log to the appropriate did.jsonl path
|
|
62
|
+
* @param did - The DID identifier
|
|
63
|
+
* @param log - The DID log to save
|
|
64
|
+
* @param baseDir - Base directory for saving (e.g., public/.well-known)
|
|
65
|
+
* @returns The full path where the log was saved
|
|
66
|
+
*/
|
|
67
|
+
saveDIDLog(did: string, log: DIDLog, baseDir: string): Promise<string>;
|
|
68
|
+
/**
|
|
69
|
+
* Loads a DID log from a did.jsonl file
|
|
70
|
+
* @param logPath - Path to the did.jsonl file
|
|
71
|
+
* @returns The loaded DID log
|
|
72
|
+
*/
|
|
73
|
+
loadDIDLog(logPath: string): Promise<DIDLog>;
|
|
74
|
+
/**
|
|
75
|
+
* Updates a DID:WebVH document
|
|
76
|
+
* @param did - The DID to update
|
|
77
|
+
* @param currentLog - The current DID log
|
|
78
|
+
* @param updates - Updates to apply to the DID document
|
|
79
|
+
* @param signer - The signer to use (must be authorized in updateKeys)
|
|
80
|
+
* @param verifier - Optional verifier
|
|
81
|
+
* @param outputDir - Optional directory to save the updated log
|
|
82
|
+
* @returns Updated DID document and log
|
|
83
|
+
*/
|
|
84
|
+
updateDIDWebVH(options: {
|
|
85
|
+
did: string;
|
|
86
|
+
currentLog: DIDLog;
|
|
87
|
+
updates: Partial<DIDDocument>;
|
|
88
|
+
signer: ExternalSigner | {
|
|
89
|
+
privateKey: string;
|
|
90
|
+
publicKey: string;
|
|
91
|
+
};
|
|
92
|
+
verifier?: ExternalVerifier;
|
|
93
|
+
outputDir?: string;
|
|
94
|
+
}): Promise<{
|
|
95
|
+
didDocument: DIDDocument;
|
|
96
|
+
log: DIDLog;
|
|
97
|
+
logPath?: string;
|
|
98
|
+
}>;
|
|
99
|
+
}
|
|
100
|
+
export {};
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import { KeyManager } from './KeyManager';
|
|
2
|
+
import { multikey } from '../crypto/Multikey';
|
|
3
|
+
import { Ed25519Signer } from '../crypto/Signer';
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
/**
|
|
7
|
+
* Adapter to use Originals SDK signers with didwebvh-ts
|
|
8
|
+
*/
|
|
9
|
+
class OriginalsWebVHSigner {
|
|
10
|
+
constructor(privateKeyMultibase, verificationMethod, prepareDataForSigning, options = {}) {
|
|
11
|
+
this.privateKeyMultibase = privateKeyMultibase;
|
|
12
|
+
this.verificationMethod = options.verificationMethod || verificationMethod;
|
|
13
|
+
this.useStaticId = options.useStaticId || false;
|
|
14
|
+
this.signer = new Ed25519Signer();
|
|
15
|
+
this.prepareDataForSigning = prepareDataForSigning;
|
|
16
|
+
}
|
|
17
|
+
async sign(input) {
|
|
18
|
+
// Prepare the data for signing using didwebvh-ts's canonical approach
|
|
19
|
+
const dataToSign = await this.prepareDataForSigning(input.document, input.proof);
|
|
20
|
+
// Sign using our Ed25519 signer
|
|
21
|
+
const signature = await this.signer.sign(Buffer.from(dataToSign), this.privateKeyMultibase);
|
|
22
|
+
// Encode signature as multibase
|
|
23
|
+
const proofValue = multikey.encodeMultibase(signature);
|
|
24
|
+
return { proofValue };
|
|
25
|
+
}
|
|
26
|
+
async verify(signature, message, publicKey) {
|
|
27
|
+
// Decode the public key to multibase format
|
|
28
|
+
const publicKeyMultibase = multikey.encodePublicKey(publicKey, 'Ed25519');
|
|
29
|
+
// Verify using our Ed25519 signer
|
|
30
|
+
const messageBuffer = Buffer.from(message);
|
|
31
|
+
const signatureBuffer = Buffer.from(signature);
|
|
32
|
+
return this.signer.verify(messageBuffer, signatureBuffer, publicKeyMultibase);
|
|
33
|
+
}
|
|
34
|
+
getVerificationMethodId() {
|
|
35
|
+
// didwebvh-ts requires verification method to be a did:key: identifier
|
|
36
|
+
// Extract the multibase key from the verification method
|
|
37
|
+
const publicKeyMultibase = this.verificationMethod?.publicKeyMultibase;
|
|
38
|
+
if (!publicKeyMultibase) {
|
|
39
|
+
throw new Error('Verification method must have publicKeyMultibase');
|
|
40
|
+
}
|
|
41
|
+
// Return as did:key format which didwebvh-ts expects
|
|
42
|
+
return `did:key:${publicKeyMultibase}`;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* WebVH DID Manager for creating and managing did:webvh identifiers
|
|
47
|
+
*/
|
|
48
|
+
export class WebVHManager {
|
|
49
|
+
constructor() {
|
|
50
|
+
this.keyManager = new KeyManager();
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Creates a new did:webvh DID with proper cryptographic signing
|
|
54
|
+
* @param options - Creation options including domain and optional key pair or external signer
|
|
55
|
+
* @returns The created DID, document, log, and key pair (if generated)
|
|
56
|
+
*/
|
|
57
|
+
async createDIDWebVH(options) {
|
|
58
|
+
const { domain, keyPair: providedKeyPair, paths = [], portable = false, outputDir, externalSigner, externalVerifier, verificationMethods: providedVerificationMethods, updateKeys: providedUpdateKeys } = options;
|
|
59
|
+
// Validate path segments before creating DID to prevent directory traversal
|
|
60
|
+
if (paths && paths.length > 0) {
|
|
61
|
+
for (const segment of paths) {
|
|
62
|
+
if (!this.isValidPathSegment(segment)) {
|
|
63
|
+
throw new Error(`Invalid path segment in DID: "${segment}". Path segments cannot contain '.', '..', path separators, or be absolute paths.`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Dynamically import didwebvh-ts to avoid module resolution issues
|
|
68
|
+
const mod = await import('didwebvh-ts');
|
|
69
|
+
const { createDID, prepareDataForSigning } = mod;
|
|
70
|
+
// Runtime validation of imported module
|
|
71
|
+
if (typeof createDID !== 'function' || typeof prepareDataForSigning !== 'function') {
|
|
72
|
+
throw new Error('Failed to load didwebvh-ts: invalid module exports');
|
|
73
|
+
}
|
|
74
|
+
let signer;
|
|
75
|
+
let verifier;
|
|
76
|
+
let keyPair;
|
|
77
|
+
let verificationMethods;
|
|
78
|
+
let updateKeys;
|
|
79
|
+
// Use external signer if provided (e.g., Turnkey integration)
|
|
80
|
+
if (externalSigner) {
|
|
81
|
+
if (!providedVerificationMethods || providedVerificationMethods.length === 0) {
|
|
82
|
+
throw new Error('verificationMethods are required when using externalSigner');
|
|
83
|
+
}
|
|
84
|
+
if (!providedUpdateKeys || providedUpdateKeys.length === 0) {
|
|
85
|
+
throw new Error('updateKeys are required when using externalSigner');
|
|
86
|
+
}
|
|
87
|
+
signer = externalSigner;
|
|
88
|
+
verifier = externalVerifier || externalSigner; // Use signer as verifier if not provided
|
|
89
|
+
verificationMethods = providedVerificationMethods;
|
|
90
|
+
updateKeys = providedUpdateKeys;
|
|
91
|
+
keyPair = undefined; // No key pair when using external signer
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
// Generate or use provided key pair (Ed25519 for did:webvh)
|
|
95
|
+
keyPair = providedKeyPair || await this.keyManager.generateKeyPair('Ed25519');
|
|
96
|
+
// Create verification methods
|
|
97
|
+
verificationMethods = [
|
|
98
|
+
{
|
|
99
|
+
type: 'Multikey',
|
|
100
|
+
publicKeyMultibase: keyPair.publicKey,
|
|
101
|
+
}
|
|
102
|
+
];
|
|
103
|
+
// Create signer using our adapter
|
|
104
|
+
const internalSigner = new OriginalsWebVHSigner(keyPair.privateKey, verificationMethods[0], prepareDataForSigning, { verificationMethod: verificationMethods[0] });
|
|
105
|
+
signer = internalSigner;
|
|
106
|
+
verifier = internalSigner; // Use the same signer as verifier
|
|
107
|
+
updateKeys = [`did:key:${keyPair.publicKey}`]; // Use did:key format for authorization
|
|
108
|
+
}
|
|
109
|
+
// Create the DID using didwebvh-ts
|
|
110
|
+
const result = await createDID({
|
|
111
|
+
domain,
|
|
112
|
+
signer,
|
|
113
|
+
verifier,
|
|
114
|
+
updateKeys,
|
|
115
|
+
verificationMethods,
|
|
116
|
+
context: [
|
|
117
|
+
'https://www.w3.org/ns/did/v1',
|
|
118
|
+
'https://w3id.org/security/multikey/v1'
|
|
119
|
+
],
|
|
120
|
+
paths,
|
|
121
|
+
portable,
|
|
122
|
+
authentication: ['#key-0'],
|
|
123
|
+
assertionMethod: ['#key-0'],
|
|
124
|
+
});
|
|
125
|
+
// Validate the returned DID document
|
|
126
|
+
if (!this.isDIDDocument(result.doc)) {
|
|
127
|
+
throw new Error('Invalid DID document returned from createDID');
|
|
128
|
+
}
|
|
129
|
+
// Save the log to did.jsonl if output directory is provided
|
|
130
|
+
let logPath;
|
|
131
|
+
if (outputDir) {
|
|
132
|
+
logPath = await this.saveDIDLog(result.did, result.log, outputDir);
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
did: result.did,
|
|
136
|
+
didDocument: result.doc,
|
|
137
|
+
log: result.log,
|
|
138
|
+
keyPair: keyPair || { publicKey: '', privateKey: '' }, // Return empty keypair if using external signer
|
|
139
|
+
logPath,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Validates a path segment to prevent directory traversal attacks
|
|
144
|
+
* @param segment - Path segment to validate
|
|
145
|
+
* @returns true if valid, false otherwise
|
|
146
|
+
*/
|
|
147
|
+
isValidPathSegment(segment) {
|
|
148
|
+
// Reject empty segments, dots, or segments with path separators
|
|
149
|
+
if (!segment || segment === '.' || segment === '..') {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
// Reject segments containing path separators or other dangerous characters
|
|
153
|
+
if (segment.includes('/') || segment.includes('\\') || segment.includes('\0')) {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
// Reject absolute paths (starting with / or drive letter on Windows)
|
|
157
|
+
if (path.isAbsolute(segment)) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Type guard to validate a DID document structure
|
|
164
|
+
* @param doc - Object to validate
|
|
165
|
+
* @returns true if the object is a valid DIDDocument
|
|
166
|
+
*/
|
|
167
|
+
isDIDDocument(doc) {
|
|
168
|
+
if (!doc || typeof doc !== 'object') {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
const d = doc;
|
|
172
|
+
// Check required fields
|
|
173
|
+
if (!Array.isArray(d['@context']) || d['@context'].length === 0) {
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
if (typeof d.id !== 'string' || !d.id.startsWith('did:')) {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Saves the DID log to the appropriate did.jsonl path
|
|
183
|
+
* @param did - The DID identifier
|
|
184
|
+
* @param log - The DID log to save
|
|
185
|
+
* @param baseDir - Base directory for saving (e.g., public/.well-known)
|
|
186
|
+
* @returns The full path where the log was saved
|
|
187
|
+
*/
|
|
188
|
+
async saveDIDLog(did, log, baseDir) {
|
|
189
|
+
// Parse the DID to extract domain and path components
|
|
190
|
+
// Format: did:webvh:domain[:port]:path1:path2...
|
|
191
|
+
const didParts = did.split(':');
|
|
192
|
+
if (didParts.length < 3 || didParts[0] !== 'did' || didParts[1] !== 'webvh') {
|
|
193
|
+
throw new Error('Invalid did:webvh format');
|
|
194
|
+
}
|
|
195
|
+
// Extract path parts (everything after domain)
|
|
196
|
+
const pathParts = didParts.slice(3);
|
|
197
|
+
// Validate all path segments to prevent directory traversal
|
|
198
|
+
for (const segment of pathParts) {
|
|
199
|
+
if (!this.isValidPathSegment(segment)) {
|
|
200
|
+
throw new Error(`Invalid path segment in DID: "${segment}". Path segments cannot contain '.', '..', path separators, or be absolute paths.`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
// Extract and sanitize domain for filesystem safety
|
|
204
|
+
const rawDomain = decodeURIComponent(didParts[2]);
|
|
205
|
+
// Normalize: lowercase and replace any characters not in [a-z0-9._-] with '_'
|
|
206
|
+
const safeDomain = rawDomain
|
|
207
|
+
.toLowerCase()
|
|
208
|
+
.replace(/[^a-z0-9._-]/g, '_');
|
|
209
|
+
// Validate the sanitized domain (reject '..' and other dangerous patterns)
|
|
210
|
+
if (!this.isValidPathSegment(safeDomain)) {
|
|
211
|
+
throw new Error(`Invalid domain segment in DID: "${rawDomain}"`);
|
|
212
|
+
}
|
|
213
|
+
// Construct the file path with domain isolation
|
|
214
|
+
// For did:webvh:example.com:user:alice -> baseDir/did/example.com/user/alice/did.jsonl
|
|
215
|
+
// For did:webvh:example.com:alice -> baseDir/did/example.com/alice/did.jsonl
|
|
216
|
+
const segments = [safeDomain, ...pathParts];
|
|
217
|
+
const didPath = path.join(baseDir, 'did', ...segments, 'did.jsonl');
|
|
218
|
+
// Verify the resolved path is still within baseDir (defense in depth)
|
|
219
|
+
const resolvedBaseDir = path.resolve(baseDir);
|
|
220
|
+
const resolvedPath = path.resolve(didPath);
|
|
221
|
+
const relativePath = path.relative(resolvedBaseDir, resolvedPath);
|
|
222
|
+
if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
|
|
223
|
+
throw new Error('Invalid DID path: resolved path is outside base directory');
|
|
224
|
+
}
|
|
225
|
+
// Create directories if they don't exist
|
|
226
|
+
const dirPath = path.dirname(didPath);
|
|
227
|
+
await fs.promises.mkdir(dirPath, { recursive: true });
|
|
228
|
+
// Convert log to JSONL format (one JSON object per line)
|
|
229
|
+
const jsonlContent = log.map((entry) => JSON.stringify(entry)).join('\n');
|
|
230
|
+
// Write the log file
|
|
231
|
+
await fs.promises.writeFile(didPath, jsonlContent, 'utf8');
|
|
232
|
+
return didPath;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Loads a DID log from a did.jsonl file
|
|
236
|
+
* @param logPath - Path to the did.jsonl file
|
|
237
|
+
* @returns The loaded DID log
|
|
238
|
+
*/
|
|
239
|
+
async loadDIDLog(logPath) {
|
|
240
|
+
const content = await fs.promises.readFile(logPath, 'utf8');
|
|
241
|
+
const lines = content.trim().split('\n');
|
|
242
|
+
return lines.map(line => JSON.parse(line));
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Updates a DID:WebVH document
|
|
246
|
+
* @param did - The DID to update
|
|
247
|
+
* @param currentLog - The current DID log
|
|
248
|
+
* @param updates - Updates to apply to the DID document
|
|
249
|
+
* @param signer - The signer to use (must be authorized in updateKeys)
|
|
250
|
+
* @param verifier - Optional verifier
|
|
251
|
+
* @param outputDir - Optional directory to save the updated log
|
|
252
|
+
* @returns Updated DID document and log
|
|
253
|
+
*/
|
|
254
|
+
async updateDIDWebVH(options) {
|
|
255
|
+
const { did, currentLog, updates, signer: providedSigner, verifier: providedVerifier, outputDir } = options;
|
|
256
|
+
// Dynamically import didwebvh-ts
|
|
257
|
+
const mod = await import('didwebvh-ts');
|
|
258
|
+
const { updateDID, prepareDataForSigning } = mod;
|
|
259
|
+
if (typeof updateDID !== 'function') {
|
|
260
|
+
throw new Error('Failed to load didwebvh-ts: invalid module exports');
|
|
261
|
+
}
|
|
262
|
+
let signer;
|
|
263
|
+
let verifier;
|
|
264
|
+
// Check if using external signer or internal keypair
|
|
265
|
+
if ('sign' in providedSigner && 'getVerificationMethodId' in providedSigner) {
|
|
266
|
+
// External signer
|
|
267
|
+
signer = providedSigner;
|
|
268
|
+
verifier = providedVerifier;
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
// Internal signer with keypair
|
|
272
|
+
const keyPair = providedSigner;
|
|
273
|
+
const verificationMethod = {
|
|
274
|
+
type: 'Multikey',
|
|
275
|
+
publicKeyMultibase: keyPair.publicKey,
|
|
276
|
+
};
|
|
277
|
+
const internalSigner = new OriginalsWebVHSigner(keyPair.privateKey, verificationMethod, prepareDataForSigning, { verificationMethod });
|
|
278
|
+
signer = internalSigner;
|
|
279
|
+
verifier = internalSigner;
|
|
280
|
+
}
|
|
281
|
+
// Get the current document from the log
|
|
282
|
+
const currentEntry = currentLog[currentLog.length - 1];
|
|
283
|
+
const currentDoc = currentEntry.state;
|
|
284
|
+
// Merge updates with current document
|
|
285
|
+
const updatedDoc = {
|
|
286
|
+
...currentDoc,
|
|
287
|
+
...updates,
|
|
288
|
+
id: did, // Ensure ID doesn't change
|
|
289
|
+
};
|
|
290
|
+
// Update the DID using didwebvh-ts
|
|
291
|
+
const result = await updateDID({
|
|
292
|
+
log: currentLog,
|
|
293
|
+
doc: updatedDoc,
|
|
294
|
+
signer,
|
|
295
|
+
verifier,
|
|
296
|
+
});
|
|
297
|
+
// Validate the returned DID document
|
|
298
|
+
if (!this.isDIDDocument(result.doc)) {
|
|
299
|
+
throw new Error('Invalid DID document returned from updateDID');
|
|
300
|
+
}
|
|
301
|
+
// Save the updated log if output directory is provided
|
|
302
|
+
let logPath;
|
|
303
|
+
if (outputDir) {
|
|
304
|
+
logPath = await this.saveDIDLog(did, result.log, outputDir);
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
didDocument: result.doc,
|
|
308
|
+
log: result.log,
|
|
309
|
+
logPath,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { DIDDocument } from '../types/did';
|
|
2
|
+
import { MultikeyType } from '../crypto/Multikey';
|
|
3
|
+
export type BitcoinNetwork = 'mainnet' | 'regtest' | 'signet';
|
|
4
|
+
interface CreateBtcoDidDocumentParams {
|
|
5
|
+
publicKey: Uint8Array;
|
|
6
|
+
keyType: MultikeyType;
|
|
7
|
+
controller?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function createBtcoDidDocument(satNumber: number | string, network: BitcoinNetwork, params: CreateBtcoDidDocumentParams): DIDDocument;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { multikey } from '../crypto/Multikey';
|
|
2
|
+
import { validateSatoshiNumber } from '../utils/satoshi-validation';
|
|
3
|
+
function getDidPrefix(network) {
|
|
4
|
+
if (network === 'mainnet')
|
|
5
|
+
return 'did:btco';
|
|
6
|
+
if (network === 'signet')
|
|
7
|
+
return 'did:btco:sig';
|
|
8
|
+
if (network === 'regtest')
|
|
9
|
+
return 'did:btco:reg';
|
|
10
|
+
throw new Error(`Unsupported Bitcoin network: ${network}`);
|
|
11
|
+
}
|
|
12
|
+
function buildVerificationMethod(did, params) {
|
|
13
|
+
const fragment = '#0';
|
|
14
|
+
const id = `${did}${fragment}`;
|
|
15
|
+
const controller = params.controller ?? did;
|
|
16
|
+
return {
|
|
17
|
+
id,
|
|
18
|
+
type: 'Multikey',
|
|
19
|
+
controller,
|
|
20
|
+
publicKeyMultibase: multikey.encodePublicKey(params.publicKey, params.keyType)
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export function createBtcoDidDocument(satNumber, network, params) {
|
|
24
|
+
// Validate satNumber parameter at entry
|
|
25
|
+
const validation = validateSatoshiNumber(satNumber);
|
|
26
|
+
if (!validation.valid) {
|
|
27
|
+
throw new Error(`Invalid satoshi number: ${validation.error}`);
|
|
28
|
+
}
|
|
29
|
+
const did = `${getDidPrefix(network)}:${String(satNumber)}`;
|
|
30
|
+
const vm = buildVerificationMethod(did, params);
|
|
31
|
+
const document = {
|
|
32
|
+
'@context': [
|
|
33
|
+
'https://www.w3.org/ns/did/v1',
|
|
34
|
+
'https://w3id.org/security/multikey/v1'
|
|
35
|
+
],
|
|
36
|
+
id: did,
|
|
37
|
+
verificationMethod: [vm],
|
|
38
|
+
authentication: [vm.id],
|
|
39
|
+
assertionMethod: [vm.id]
|
|
40
|
+
};
|
|
41
|
+
return document;
|
|
42
|
+
}
|