@sphereon/ssi-sdk-ext.did-utils 0.26.1-feature.SPRIND.124.esim.31 → 0.26.1-feature.SPRIND.124.esim.47
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/did-functions.d.ts.map +1 -1
- package/dist/did-functions.js +28 -28
- package/dist/did-functions.js.map +1 -1
- package/package.json +4 -4
- package/src/did-functions.ts +773 -764
package/src/did-functions.ts
CHANGED
|
@@ -1,283 +1,293 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import {computeAddress} from '@ethersproject/transactions'
|
|
2
|
+
import {UniResolver} from '@sphereon/did-uni-client'
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
ENC_KEY_ALGS,
|
|
5
|
+
getKms,
|
|
6
|
+
JwkKeyUse,
|
|
7
|
+
keyTypeFromCryptographicSuite,
|
|
8
|
+
sanitizedJwk,
|
|
9
|
+
signatureAlgorithmFromKey,
|
|
10
|
+
TKeyType,
|
|
11
|
+
toJwk,
|
|
11
12
|
} from '@sphereon/ssi-sdk-ext.key-utils'
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import { DIDDocument, DIDDocumentSection, DIDResolutionResult, IAgentContext, IDIDManager, IIdentifier, IKey, IResolver } from '@veramo/core'
|
|
13
|
+
import {base64ToHex, hexKeyFromPEMBasedJwk} from '@sphereon/ssi-sdk-ext.x509-utils'
|
|
14
|
+
import {base58ToBytes, base64ToBytes, bytesToHex, hexToBytes, multibaseKeyToBytes} from '@sphereon/ssi-sdk.core'
|
|
15
|
+
import {JWK} from '@sphereon/ssi-types'
|
|
16
|
+
import {convertPublicKeyToX25519} from '@stablelib/ed25519'
|
|
17
17
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
DIDDocument,
|
|
19
|
+
DIDDocumentSection,
|
|
20
|
+
DIDResolutionResult,
|
|
21
|
+
IAgentContext,
|
|
22
|
+
IDIDManager,
|
|
23
|
+
IIdentifier,
|
|
24
|
+
IKey,
|
|
25
|
+
IResolver
|
|
26
|
+
} from '@veramo/core'
|
|
27
|
+
import {
|
|
28
|
+
_ExtendedIKey,
|
|
29
|
+
_ExtendedVerificationMethod,
|
|
30
|
+
_NormalizedVerificationMethod,
|
|
31
|
+
compressIdentifierSecp256k1Keys,
|
|
32
|
+
convertIdentifierEncryptionKeys,
|
|
33
|
+
getEthereumAddress,
|
|
34
|
+
isDefined,
|
|
35
|
+
mapIdentifierKeysToDoc,
|
|
26
36
|
} from '@veramo/utils'
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
37
|
+
import {createJWT, Signer} from 'did-jwt'
|
|
38
|
+
import {DIDResolutionOptions, JsonWebKey, Resolvable, VerificationMethod} from 'did-resolver'
|
|
29
39
|
// @ts-ignore
|
|
30
40
|
import elliptic from 'elliptic'
|
|
31
41
|
import * as u8a from 'uint8arrays'
|
|
32
42
|
import {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
CreateIdentifierOpts,
|
|
44
|
+
CreateOrGetIdentifierOpts,
|
|
45
|
+
DID_PREFIX,
|
|
46
|
+
GetOrCreateResult,
|
|
47
|
+
GetSignerArgs,
|
|
48
|
+
IdentifierAliasEnum,
|
|
49
|
+
IdentifierProviderOpts,
|
|
50
|
+
IDIDOptions,
|
|
51
|
+
SignJwtArgs,
|
|
52
|
+
SupportedDidMethodEnum,
|
|
43
53
|
} from './types'
|
|
44
54
|
|
|
45
55
|
export const getAuthenticationKey = async (
|
|
46
|
-
{
|
|
47
|
-
identifier,
|
|
48
|
-
offlineWhenNoDIDRegistered,
|
|
49
|
-
noVerificationMethodFallback,
|
|
50
|
-
keyType,
|
|
51
|
-
controllerKey,
|
|
52
|
-
}: {
|
|
53
|
-
identifier: IIdentifier
|
|
54
|
-
keyType?: TKeyType
|
|
55
|
-
offlineWhenNoDIDRegistered?: boolean
|
|
56
|
-
noVerificationMethodFallback?: boolean
|
|
57
|
-
controllerKey?: boolean
|
|
58
|
-
},
|
|
59
|
-
context: IAgentContext<IResolver & IDIDManager>
|
|
60
|
-
): Promise<_ExtendedIKey> => {
|
|
61
|
-
return await getFirstKeyWithRelation(
|
|
62
56
|
{
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
57
|
+
identifier,
|
|
58
|
+
offlineWhenNoDIDRegistered,
|
|
59
|
+
noVerificationMethodFallback,
|
|
60
|
+
keyType,
|
|
61
|
+
controllerKey,
|
|
62
|
+
}: {
|
|
63
|
+
identifier: IIdentifier
|
|
64
|
+
keyType?: TKeyType
|
|
65
|
+
offlineWhenNoDIDRegistered?: boolean
|
|
66
|
+
noVerificationMethodFallback?: boolean
|
|
67
|
+
controllerKey?: boolean
|
|
69
68
|
},
|
|
70
|
-
context
|
|
71
|
-
)
|
|
72
|
-
}
|
|
73
|
-
export const getFirstKeyWithRelation = async (
|
|
74
|
-
{
|
|
75
|
-
identifier,
|
|
76
|
-
offlineWhenNoDIDRegistered,
|
|
77
|
-
noVerificationMethodFallback,
|
|
78
|
-
keyType,
|
|
79
|
-
controllerKey,
|
|
80
|
-
vmRelationship,
|
|
81
|
-
}: {
|
|
82
|
-
identifier: IIdentifier
|
|
83
|
-
keyType?: TKeyType
|
|
84
|
-
offlineWhenNoDIDRegistered?: boolean
|
|
85
|
-
noVerificationMethodFallback?: boolean
|
|
86
|
-
controllerKey?: boolean
|
|
87
|
-
vmRelationship: DIDDocumentSection
|
|
88
|
-
},
|
|
89
|
-
context: IAgentContext<IResolver & IDIDManager>
|
|
69
|
+
context: IAgentContext<IResolver & IDIDManager>
|
|
90
70
|
): Promise<_ExtendedIKey> => {
|
|
91
|
-
|
|
92
|
-
try {
|
|
93
|
-
key =
|
|
94
|
-
(await getFirstKeyWithRelationFromDIDDoc(
|
|
71
|
+
return await getFirstKeyWithRelation(
|
|
95
72
|
{
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
73
|
+
identifier,
|
|
74
|
+
offlineWhenNoDIDRegistered,
|
|
75
|
+
noVerificationMethodFallback,
|
|
76
|
+
keyType,
|
|
77
|
+
controllerKey,
|
|
78
|
+
vmRelationship: 'authentication',
|
|
101
79
|
},
|
|
102
80
|
context
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
export const getFirstKeyWithRelation = async (
|
|
84
|
+
{
|
|
85
|
+
identifier,
|
|
86
|
+
offlineWhenNoDIDRegistered,
|
|
87
|
+
noVerificationMethodFallback,
|
|
88
|
+
keyType,
|
|
89
|
+
controllerKey,
|
|
90
|
+
vmRelationship,
|
|
91
|
+
}: {
|
|
92
|
+
identifier: IIdentifier
|
|
93
|
+
keyType?: TKeyType
|
|
94
|
+
offlineWhenNoDIDRegistered?: boolean
|
|
95
|
+
noVerificationMethodFallback?: boolean
|
|
96
|
+
controllerKey?: boolean
|
|
97
|
+
vmRelationship: DIDDocumentSection
|
|
98
|
+
},
|
|
99
|
+
context: IAgentContext<IResolver & IDIDManager>
|
|
100
|
+
): Promise<_ExtendedIKey> => {
|
|
101
|
+
let key: _ExtendedIKey | undefined = undefined
|
|
102
|
+
try {
|
|
103
|
+
key =
|
|
104
|
+
(await getFirstKeyWithRelationFromDIDDoc(
|
|
105
|
+
{
|
|
106
|
+
identifier,
|
|
107
|
+
vmRelationship,
|
|
108
|
+
errorOnNotFound: false,
|
|
109
|
+
keyType,
|
|
110
|
+
controllerKey,
|
|
111
|
+
},
|
|
112
|
+
context
|
|
113
|
+
)) ??
|
|
114
|
+
(noVerificationMethodFallback || vmRelationship === 'verificationMethod' // let's not fallback to the same value again
|
|
115
|
+
? undefined
|
|
116
|
+
: await getFirstKeyWithRelationFromDIDDoc(
|
|
117
|
+
{
|
|
118
|
+
identifier,
|
|
119
|
+
vmRelationship: 'verificationMethod',
|
|
120
|
+
errorOnNotFound: false,
|
|
121
|
+
keyType,
|
|
122
|
+
controllerKey,
|
|
123
|
+
},
|
|
124
|
+
context
|
|
125
|
+
))
|
|
126
|
+
} catch (e) {
|
|
127
|
+
if (e instanceof Error) {
|
|
128
|
+
if (!e.message.includes('404') || !offlineWhenNoDIDRegistered) {
|
|
129
|
+
throw e
|
|
130
|
+
}
|
|
131
|
+
} else {
|
|
132
|
+
throw e
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (!key && offlineWhenNoDIDRegistered) {
|
|
136
|
+
const offlineDID = toDidDocument(identifier)
|
|
137
|
+
key =
|
|
138
|
+
(await getFirstKeyWithRelationFromDIDDoc(
|
|
139
|
+
{
|
|
140
|
+
identifier,
|
|
141
|
+
vmRelationship,
|
|
142
|
+
errorOnNotFound: false,
|
|
143
|
+
didDocument: offlineDID,
|
|
144
|
+
keyType,
|
|
145
|
+
controllerKey,
|
|
146
|
+
},
|
|
147
|
+
context
|
|
148
|
+
)) ??
|
|
149
|
+
(noVerificationMethodFallback || vmRelationship === 'verificationMethod' // let's not fallback to the same value again
|
|
150
|
+
? undefined
|
|
151
|
+
: await getFirstKeyWithRelationFromDIDDoc(
|
|
152
|
+
{
|
|
153
|
+
identifier,
|
|
154
|
+
vmRelationship: 'verificationMethod',
|
|
155
|
+
errorOnNotFound: false,
|
|
156
|
+
didDocument: offlineDID,
|
|
157
|
+
keyType,
|
|
158
|
+
controllerKey,
|
|
159
|
+
},
|
|
160
|
+
context
|
|
161
|
+
))
|
|
162
|
+
if (!key) {
|
|
163
|
+
key = identifier.keys
|
|
164
|
+
.map((key) => key as _ExtendedIKey)
|
|
165
|
+
.filter((key) => keyType === undefined || key.type === keyType || (controllerKey && key.kid === identifier.controllerKeyId))
|
|
166
|
+
.find((key) => key.meta.verificationMethod?.type.includes('authentication') || key.meta.purposes?.includes('authentication'))
|
|
167
|
+
}
|
|
168
|
+
}
|
|
152
169
|
if (!key) {
|
|
153
|
-
|
|
154
|
-
.map((key) => key as _ExtendedIKey)
|
|
155
|
-
.filter((key) => keyType === undefined || key.type === keyType || (controllerKey && key.kid === identifier.controllerKeyId))
|
|
156
|
-
.find((key) => key.meta.verificationMethod?.type.includes('authentication') || key.meta.purposes?.includes('authentication'))
|
|
170
|
+
throw Error(`Could not find authentication key for DID ${identifier.did}`)
|
|
157
171
|
}
|
|
158
|
-
|
|
159
|
-
if (!key) {
|
|
160
|
-
throw Error(`Could not find authentication key for DID ${identifier.did}`)
|
|
161
|
-
}
|
|
162
|
-
return key
|
|
172
|
+
return key
|
|
163
173
|
}
|
|
164
174
|
|
|
165
175
|
export const getOrCreatePrimaryIdentifier = async (
|
|
166
|
-
|
|
167
|
-
|
|
176
|
+
context: IAgentContext<IDIDManager>,
|
|
177
|
+
opts?: CreateOrGetIdentifierOpts
|
|
168
178
|
): Promise<GetOrCreateResult<IIdentifier>> => {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
179
|
+
const primaryIdentifier = await getPrimaryIdentifier(context, {...opts?.createOpts?.options, ...(opts?.method && {method: opts.method})})
|
|
180
|
+
if (primaryIdentifier !== undefined) {
|
|
181
|
+
return {
|
|
182
|
+
created: false,
|
|
183
|
+
result: primaryIdentifier,
|
|
184
|
+
}
|
|
174
185
|
}
|
|
175
|
-
}
|
|
176
186
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
+
if (opts?.method === SupportedDidMethodEnum.DID_KEY) {
|
|
188
|
+
const createOpts = opts?.createOpts ?? {}
|
|
189
|
+
createOpts.options = {codecName: 'EBSI', type: 'Secp256r1', ...createOpts}
|
|
190
|
+
opts.createOpts = createOpts
|
|
191
|
+
}
|
|
192
|
+
const createdIdentifier = await createIdentifier(context, opts)
|
|
193
|
+
return {
|
|
194
|
+
created: true,
|
|
195
|
+
result: createdIdentifier,
|
|
196
|
+
}
|
|
187
197
|
}
|
|
188
198
|
|
|
189
199
|
export const getPrimaryIdentifier = async (context: IAgentContext<IDIDManager>, opts?: IdentifierProviderOpts): Promise<IIdentifier | undefined> => {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
200
|
+
const identifiers = (await context.agent.didManagerFind(opts?.method ? {provider: `${DID_PREFIX}${opts?.method}`} : {})).filter(
|
|
201
|
+
(identifier: IIdentifier) => opts?.type === undefined || identifier.keys.some((key: IKey) => key.type === opts?.type)
|
|
202
|
+
)
|
|
193
203
|
|
|
194
|
-
|
|
204
|
+
return identifiers && identifiers.length > 0 ? identifiers[0] : undefined
|
|
195
205
|
}
|
|
196
206
|
|
|
197
207
|
export const createIdentifier = async (context: IAgentContext<IDIDManager>, opts?: CreateIdentifierOpts): Promise<IIdentifier> => {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
208
|
+
return await context.agent.didManagerCreate({
|
|
209
|
+
kms: await getKms(context, opts?.createOpts?.kms),
|
|
210
|
+
...(opts?.method && {provider: `${DID_PREFIX}${opts?.method}`}),
|
|
211
|
+
alias: opts?.createOpts?.alias ?? `${IdentifierAliasEnum.PRIMARY}-${opts?.method}-${opts?.createOpts?.options?.type}-${new Date().toUTCString()}`,
|
|
212
|
+
options: opts?.createOpts?.options,
|
|
213
|
+
})
|
|
204
214
|
}
|
|
205
215
|
|
|
206
216
|
export const getFirstKeyWithRelationFromDIDDoc = async (
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
217
|
+
{
|
|
218
|
+
identifier,
|
|
219
|
+
vmRelationship = 'verificationMethod',
|
|
220
|
+
keyType,
|
|
221
|
+
errorOnNotFound = false,
|
|
222
|
+
didDocument,
|
|
223
|
+
controllerKey,
|
|
224
|
+
}: {
|
|
225
|
+
identifier: IIdentifier
|
|
226
|
+
controllerKey?: boolean
|
|
227
|
+
vmRelationship?: DIDDocumentSection
|
|
228
|
+
keyType?: TKeyType
|
|
229
|
+
errorOnNotFound?: boolean
|
|
230
|
+
didDocument?: DIDDocument
|
|
231
|
+
},
|
|
232
|
+
context: IAgentContext<IResolver & IDIDManager>
|
|
223
233
|
): Promise<_ExtendedIKey | undefined> => {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
234
|
+
const matchedKeys = await mapIdentifierKeysToDocWithJwkSupport({identifier, vmRelationship, didDocument}, context)
|
|
235
|
+
if (Array.isArray(matchedKeys) && matchedKeys.length > 0) {
|
|
236
|
+
const result = matchedKeys.find(
|
|
237
|
+
(key) => keyType === undefined || key.type === keyType || (controllerKey && key.kid === identifier.controllerKeyId)
|
|
238
|
+
)
|
|
239
|
+
if (result) {
|
|
240
|
+
return result
|
|
241
|
+
}
|
|
231
242
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
return undefined
|
|
243
|
+
if (errorOnNotFound) {
|
|
244
|
+
throw new Error(
|
|
245
|
+
`Could not find key with relationship ${vmRelationship} in DID document for ${identifier.did}${keyType ? ' and key type: ' + keyType : ''}`
|
|
246
|
+
)
|
|
247
|
+
}
|
|
248
|
+
return undefined
|
|
239
249
|
}
|
|
240
250
|
|
|
241
|
-
export const getEthereumAddressFromKey = ({
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
251
|
+
export const getEthereumAddressFromKey = ({key}: { key: IKey }) => {
|
|
252
|
+
if (key.type !== 'Secp256k1') {
|
|
253
|
+
throw Error(`Can only get ethereum address from a Secp256k1 key. Type is ${key.type} for keyRef: ${key.kid}`)
|
|
254
|
+
}
|
|
255
|
+
const ethereumAddress = key.meta?.ethereumAddress ?? key.meta?.account?.toLowerCase() ?? computeAddress(`0x${key.publicKeyHex}`).toLowerCase()
|
|
256
|
+
if (!ethereumAddress) {
|
|
257
|
+
throw Error(`Could not get or generate ethereum address from key with keyRef ${key.kid}`)
|
|
258
|
+
}
|
|
259
|
+
return ethereumAddress
|
|
250
260
|
}
|
|
251
261
|
|
|
252
|
-
export const getControllerKey = ({
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
262
|
+
export const getControllerKey = ({identifier}: { identifier: IIdentifier }) => {
|
|
263
|
+
const key = identifier.keys.find((key) => key.kid === identifier.controllerKeyId)
|
|
264
|
+
if (!key) {
|
|
265
|
+
throw Error(`Could not get controller key for identifier ${identifier}`)
|
|
266
|
+
}
|
|
267
|
+
return key
|
|
258
268
|
}
|
|
259
269
|
|
|
260
270
|
export const getKeys = ({
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
}: {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
271
|
+
jwkThumbprint,
|
|
272
|
+
kms,
|
|
273
|
+
identifier,
|
|
274
|
+
kmsKeyRef,
|
|
275
|
+
keyType,
|
|
276
|
+
controllerKey,
|
|
277
|
+
}: {
|
|
278
|
+
identifier: IIdentifier
|
|
279
|
+
kmsKeyRef?: string
|
|
280
|
+
keyType?: TKeyType
|
|
281
|
+
kms?: string
|
|
282
|
+
jwkThumbprint?: string
|
|
283
|
+
controllerKey?: boolean
|
|
274
284
|
}) => {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
285
|
+
return identifier.keys
|
|
286
|
+
.filter((key) => !keyType || key.type === keyType)
|
|
287
|
+
.filter((key) => !kms || key.kms === kms)
|
|
288
|
+
.filter((key) => !kmsKeyRef || key.kid === kmsKeyRef)
|
|
289
|
+
.filter((key) => !jwkThumbprint || key.meta?.jwkThumbprint === jwkThumbprint)
|
|
290
|
+
.filter((key) => !controllerKey || identifier.controllerKeyId === key.kid)
|
|
281
291
|
}
|
|
282
292
|
|
|
283
293
|
//TODO: Move to ssi-sdk/core and create PR upstream
|
|
@@ -292,52 +302,52 @@ export const getKeys = ({
|
|
|
292
302
|
* @beta This API may change without a BREAKING CHANGE notice.
|
|
293
303
|
*/
|
|
294
304
|
export async function dereferenceDidKeysWithJwkSupport(
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
305
|
+
didDocument: DIDDocument,
|
|
306
|
+
section: DIDDocumentSection = 'keyAgreement',
|
|
307
|
+
context: IAgentContext<IResolver>
|
|
298
308
|
): Promise<_NormalizedVerificationMethod[]> {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
309
|
+
const convert = section === 'keyAgreement'
|
|
310
|
+
if (section === 'service') {
|
|
311
|
+
return []
|
|
312
|
+
}
|
|
313
|
+
return (
|
|
314
|
+
await Promise.all(
|
|
315
|
+
(didDocument[section] || []).map(async (key: string | VerificationMethod) => {
|
|
316
|
+
if (typeof key === 'string') {
|
|
317
|
+
try {
|
|
318
|
+
return (await context.agent.getDIDComponentById({
|
|
319
|
+
didDocument,
|
|
320
|
+
didUrl: key,
|
|
321
|
+
section,
|
|
322
|
+
})) as _ExtendedVerificationMethod
|
|
323
|
+
} catch (e) {
|
|
324
|
+
return null
|
|
325
|
+
}
|
|
326
|
+
} else {
|
|
327
|
+
return key as _ExtendedVerificationMethod
|
|
328
|
+
}
|
|
329
|
+
})
|
|
330
|
+
)
|
|
320
331
|
)
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
})
|
|
332
|
+
.filter(isDefined)
|
|
333
|
+
.map((key) => {
|
|
334
|
+
const hexKey = extractPublicKeyHexWithJwkSupport(key, convert)
|
|
335
|
+
const {publicKeyHex, publicKeyBase58, publicKeyBase64, publicKeyJwk, ...keyProps} = key
|
|
336
|
+
const newKey = {...keyProps, publicKeyHex: hexKey}
|
|
337
|
+
if (convert && 'Ed25519VerificationKey2018' === newKey.type) {
|
|
338
|
+
newKey.type = 'X25519KeyAgreementKey2019'
|
|
339
|
+
}
|
|
340
|
+
return newKey
|
|
341
|
+
})
|
|
332
342
|
}
|
|
333
343
|
|
|
334
344
|
export function jwkTtoPublicKeyHex(jwk: JWK): string {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
345
|
+
// todo: Hacky way to convert this to a VM. Should extract the logic from the below methods
|
|
346
|
+
// @ts-ignore
|
|
347
|
+
const vm: _ExtendedVerificationMethod = {
|
|
348
|
+
publicKeyJwk: sanitizedJwk(jwk),
|
|
349
|
+
}
|
|
350
|
+
return extractPublicKeyHexWithJwkSupport(vm)
|
|
341
351
|
}
|
|
342
352
|
|
|
343
353
|
/**
|
|
@@ -350,38 +360,42 @@ export function jwkTtoPublicKeyHex(jwk: JWK): string {
|
|
|
350
360
|
* @beta This API may change without a BREAKING CHANGE notice.
|
|
351
361
|
*/
|
|
352
362
|
export function extractPublicKeyHexWithJwkSupport(pk: _ExtendedVerificationMethod, convert = false): string {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
363
|
+
if (pk.publicKeyJwk) {
|
|
364
|
+
const jwk = sanitizedJwk(pk.publicKeyJwk)
|
|
365
|
+
if (jwk.kty === 'EC') {
|
|
366
|
+
const curve = jwk.crv ? toEcLibCurve(jwk.crv) : 'p256'
|
|
367
|
+
const xHex = base64ToHex(jwk.x!, 'base64url')
|
|
368
|
+
const yHex = base64ToHex(jwk.y!, 'base64url')
|
|
369
|
+
const prefix = '04' // isEven(yHex) ? '02' : '03'
|
|
370
|
+
// Uncompressed Hex format: 04<x><y>
|
|
371
|
+
// Compressed Hex format: 02<x> (for even y) or 03<x> (for uneven y)
|
|
372
|
+
const hex = `${prefix}${xHex}${yHex}`
|
|
373
|
+
try {
|
|
374
|
+
const ec = new elliptic.ec(curve)
|
|
375
|
+
// We return directly as we don't want to convert the result back into Uint8Array and then convert again to hex as the elliptic lib already returns hex strings
|
|
376
|
+
const publicKeyHex = ec.keyFromPublic(hex, 'hex').getPublic(true, 'hex')
|
|
377
|
+
// This returns a short form (x) with 02 or 03 prefix
|
|
378
|
+
return publicKeyHex
|
|
379
|
+
} catch (error: any) {
|
|
380
|
+
console.error(`Error converting EC with elliptic lib curve ${curve} from JWK to hex. x: ${jwk.x}, y: ${jwk.y}, error: ${error}`, error)
|
|
381
|
+
}
|
|
382
|
+
} else if (jwk.crv === 'Ed25519') {
|
|
383
|
+
return u8a.toString(u8a.fromString(jwk.x!, 'base64url'), 'base16')
|
|
384
|
+
} else if (jwk.kty === 'RSA') {
|
|
385
|
+
return hexKeyFromPEMBasedJwk(jwk, 'public')
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
// delegate the other types to the original Veramo function
|
|
389
|
+
return extractPublicKeyHex(pk, convert)
|
|
376
390
|
}
|
|
377
391
|
|
|
378
392
|
export function isEvenHexString(hex: string) {
|
|
379
|
-
|
|
380
|
-
|
|
393
|
+
const lastChar = hex[hex.length - 1].toLowerCase()
|
|
394
|
+
return ['0', '2', '4', '6', '8', 'a', 'c', 'e'].includes(lastChar)
|
|
381
395
|
}
|
|
382
396
|
|
|
383
397
|
interface LegacyVerificationMethod extends VerificationMethod {
|
|
384
|
-
|
|
398
|
+
publicKeyBase64: string
|
|
385
399
|
}
|
|
386
400
|
|
|
387
401
|
/**
|
|
@@ -394,91 +408,86 @@ interface LegacyVerificationMethod extends VerificationMethod {
|
|
|
394
408
|
* @beta This API may change without a BREAKING CHANGE notice.
|
|
395
409
|
*/
|
|
396
410
|
export function extractPublicKeyHex(pk: _ExtendedVerificationMethod, convert: boolean = false): string {
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
if (
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
411
|
+
let keyBytes = extractPublicKeyBytes(pk)
|
|
412
|
+
const jwk = pk.publicKeyJwk ? sanitizedJwk(pk.publicKeyJwk) : undefined
|
|
413
|
+
if (convert) {
|
|
414
|
+
if (
|
|
415
|
+
['Ed25519', 'Ed25519VerificationKey2018', 'Ed25519VerificationKey2020'].includes(pk.type) ||
|
|
416
|
+
(pk.type === 'JsonWebKey2020' && jwk?.crv === 'Ed25519')
|
|
417
|
+
) {
|
|
418
|
+
keyBytes = convertPublicKeyToX25519(keyBytes)
|
|
419
|
+
} else if (
|
|
420
|
+
!['X25519', 'X25519KeyAgreementKey2019', 'X25519KeyAgreementKey2020'].includes(pk.type) &&
|
|
421
|
+
!(pk.type === 'JsonWebKey2020' && jwk?.crv === 'X25519')
|
|
422
|
+
) {
|
|
423
|
+
return ''
|
|
424
|
+
}
|
|
409
425
|
}
|
|
410
|
-
|
|
411
|
-
return bytesToHex(keyBytes)
|
|
426
|
+
return bytesToHex(keyBytes)
|
|
412
427
|
}
|
|
413
428
|
|
|
414
429
|
function toEcLibCurve(input: string) {
|
|
415
|
-
|
|
430
|
+
return input.toLowerCase().replace('-', '').replace('_', '')
|
|
416
431
|
}
|
|
417
432
|
|
|
418
433
|
function extractPublicKeyBytes(pk: VerificationMethod): Uint8Array {
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
.getPublic('hex')
|
|
436
|
-
)
|
|
437
|
-
} else if (pk.publicKeyJwk && (pk.publicKeyJwk.crv === 'Ed25519' || pk.publicKeyJwk.crv === 'X25519') && pk.publicKeyJwk.x) {
|
|
438
|
-
return base64ToBytes(pk.publicKeyJwk.x)
|
|
439
|
-
}
|
|
440
|
-
return new Uint8Array()
|
|
434
|
+
if (pk.publicKeyBase58) {
|
|
435
|
+
return base58ToBytes(pk.publicKeyBase58)
|
|
436
|
+
} else if (pk.publicKeyMultibase) {
|
|
437
|
+
return multibaseKeyToBytes(pk.publicKeyMultibase)
|
|
438
|
+
} else if ((<LegacyVerificationMethod>pk).publicKeyBase64) {
|
|
439
|
+
return base64ToBytes((<LegacyVerificationMethod>pk).publicKeyBase64)
|
|
440
|
+
} else if (pk.publicKeyHex) {
|
|
441
|
+
return hexToBytes(pk.publicKeyHex)
|
|
442
|
+
} else if (pk.publicKeyJwk?.crv && pk.publicKeyJwk.x && pk.publicKeyJwk.y) {
|
|
443
|
+
return hexToBytes(
|
|
444
|
+
extractPublicKeyHexWithJwkSupport(pk)
|
|
445
|
+
)
|
|
446
|
+
} else if (pk.publicKeyJwk && (pk.publicKeyJwk.crv === 'Ed25519' || pk.publicKeyJwk.crv === 'X25519') && pk.publicKeyJwk.x) {
|
|
447
|
+
return base64ToBytes(pk.publicKeyJwk.x)
|
|
448
|
+
}
|
|
449
|
+
return new Uint8Array()
|
|
441
450
|
}
|
|
442
451
|
|
|
443
452
|
export function verificationMethodToJwk(vm: VerificationMethod): JWK {
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
453
|
+
let jwk: JWK | undefined = vm.publicKeyJwk as JWK
|
|
454
|
+
if (!jwk) {
|
|
455
|
+
let publicKeyHex = vm.publicKeyHex ?? u8a.toString(extractPublicKeyBytes(vm), 'hex')
|
|
456
|
+
jwk = toJwk(publicKeyHex, keyTypeFromCryptographicSuite({crv: vm.type}))
|
|
457
|
+
}
|
|
458
|
+
if (!jwk) {
|
|
459
|
+
throw Error(`Could not convert verification method to jwk`)
|
|
460
|
+
}
|
|
461
|
+
jwk.kid = vm.id
|
|
462
|
+
return sanitizedJwk(jwk)
|
|
454
463
|
}
|
|
455
464
|
|
|
456
465
|
function didDocumentSectionToJwks(
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
466
|
+
didDocumentSection: DIDDocumentSection,
|
|
467
|
+
searchForVerificationMethods?: (VerificationMethod | string)[],
|
|
468
|
+
verificationMethods?: VerificationMethod[]
|
|
460
469
|
) {
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
470
|
+
const jwks = new Set((searchForVerificationMethods ?? [])
|
|
471
|
+
.map((vmOrId) => (typeof vmOrId === 'object' ? vmOrId : verificationMethods?.find((vm) => vm.id === vmOrId)))
|
|
472
|
+
.filter(isDefined)
|
|
473
|
+
.map((vm) => verificationMethodToJwk(vm)))
|
|
474
|
+
return {didDocumentSection, jwks: Array.from(jwks)}
|
|
466
475
|
}
|
|
467
476
|
|
|
468
477
|
export type DidDocumentJwks = Record<Exclude<DIDDocumentSection, 'publicKey' | 'service'>, Array<JWK>>
|
|
469
478
|
|
|
470
479
|
export function didDocumentToJwks(didDocument: DIDDocument): DidDocumentJwks {
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
480
|
+
return {
|
|
481
|
+
verificationMethod: [
|
|
482
|
+
...didDocumentSectionToJwks('publicKey', didDocument.publicKey, didDocument.verificationMethod).jwks, // legacy support
|
|
483
|
+
...didDocumentSectionToJwks('verificationMethod', didDocument.verificationMethod, didDocument.verificationMethod).jwks,
|
|
484
|
+
],
|
|
485
|
+
assertionMethod: didDocumentSectionToJwks('assertionMethod', didDocument.assertionMethod, didDocument.verificationMethod).jwks,
|
|
486
|
+
authentication: didDocumentSectionToJwks('authentication', didDocument.authentication, didDocument.verificationMethod).jwks,
|
|
487
|
+
keyAgreement: didDocumentSectionToJwks('keyAgreement', didDocument.keyAgreement, didDocument.verificationMethod).jwks,
|
|
488
|
+
capabilityInvocation: didDocumentSectionToJwks('capabilityInvocation', didDocument.capabilityInvocation, didDocument.verificationMethod).jwks,
|
|
489
|
+
capabilityDelegation: didDocumentSectionToJwks('capabilityDelegation', didDocument.capabilityDelegation, didDocument.verificationMethod).jwks,
|
|
490
|
+
}
|
|
482
491
|
}
|
|
483
492
|
|
|
484
493
|
/**
|
|
@@ -499,58 +508,58 @@ export function didDocumentToJwks(didDocument: DIDDocument): DidDocumentJwks {
|
|
|
499
508
|
* @beta This API may change without a BREAKING CHANGE notice.
|
|
500
509
|
*/
|
|
501
510
|
export async function mapIdentifierKeysToDocWithJwkSupport(
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
511
|
+
{
|
|
512
|
+
identifier,
|
|
513
|
+
vmRelationship = 'verificationMethod',
|
|
514
|
+
didDocument,
|
|
515
|
+
}: {
|
|
516
|
+
identifier: IIdentifier
|
|
517
|
+
vmRelationship?: DIDDocumentSection
|
|
518
|
+
didDocument?: DIDDocument
|
|
519
|
+
},
|
|
520
|
+
context: IAgentContext<IResolver & IDIDManager>
|
|
512
521
|
): Promise<_ExtendedIKey[]> {
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
522
|
+
const didDoc =
|
|
523
|
+
didDocument ??
|
|
524
|
+
(await getAgentResolver(context)
|
|
525
|
+
.resolve(identifier.did)
|
|
526
|
+
.then((result) => result.didDocument))
|
|
527
|
+
if (!didDoc) {
|
|
528
|
+
throw Error(`Could not resolve DID ${identifier.did}`)
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// const rsaDidWeb = identifier.keys && identifier.keys.length > 0 && identifier.keys.find((key) => key.type === 'RSA') && didDocument
|
|
532
|
+
|
|
533
|
+
// We skip mapping in case the identifier is RSA and a did document is supplied.
|
|
534
|
+
const keys = didDoc ? [] : await mapIdentifierKeysToDoc(identifier, vmRelationship, context)
|
|
535
|
+
|
|
536
|
+
// dereference all key agreement keys from DID document and normalize
|
|
537
|
+
const documentKeys: VerificationMethod[] = await dereferenceDidKeysWithJwkSupport(didDoc, vmRelationship, context)
|
|
538
|
+
|
|
539
|
+
const localKeys = vmRelationship === 'keyAgreement' ? convertIdentifierEncryptionKeys(identifier) : compressIdentifierSecp256k1Keys(identifier)
|
|
540
|
+
|
|
541
|
+
// finally map the didDocument keys to the identifier keys by comparing `publicKeyHex`
|
|
542
|
+
const extendedKeys: _ExtendedIKey[] = documentKeys
|
|
543
|
+
.map((verificationMethod) => {
|
|
544
|
+
/*if (verificationMethod.type !== 'JsonWebKey2020') {
|
|
545
|
+
return null
|
|
546
|
+
}*/
|
|
547
|
+
const localKey = localKeys.find(
|
|
548
|
+
(localKey) =>
|
|
549
|
+
localKey.publicKeyHex === verificationMethod.publicKeyHex ||
|
|
550
|
+
verificationMethod.publicKeyHex?.startsWith(localKey.publicKeyHex) ||
|
|
551
|
+
compareBlockchainAccountId(localKey, verificationMethod)
|
|
552
|
+
)
|
|
553
|
+
if (localKey) {
|
|
554
|
+
const {meta, ...localProps} = localKey
|
|
555
|
+
return {...localProps, meta: {...meta, verificationMethod}}
|
|
556
|
+
} else {
|
|
557
|
+
return null
|
|
558
|
+
}
|
|
559
|
+
})
|
|
560
|
+
.filter(isDefined)
|
|
552
561
|
|
|
553
|
-
|
|
562
|
+
return keys.concat(extendedKeys)
|
|
554
563
|
}
|
|
555
564
|
|
|
556
565
|
/**
|
|
@@ -566,96 +575,96 @@ export async function mapIdentifierKeysToDocWithJwkSupport(
|
|
|
566
575
|
* @beta This API may change without a BREAKING CHANGE notice.
|
|
567
576
|
*/
|
|
568
577
|
function compareBlockchainAccountId(localKey: IKey, verificationMethod: VerificationMethod): boolean {
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
578
|
+
if (
|
|
579
|
+
(verificationMethod.type !== 'EcdsaSecp256k1RecoveryMethod2020' && verificationMethod.type !== 'EcdsaSecp256k1VerificationKey2019') ||
|
|
580
|
+
localKey.type !== 'Secp256k1'
|
|
581
|
+
) {
|
|
582
|
+
return false
|
|
583
|
+
}
|
|
584
|
+
let vmEthAddr = getEthereumAddress(verificationMethod)
|
|
585
|
+
if (localKey.meta?.account) {
|
|
586
|
+
return vmEthAddr === localKey.meta?.account.toLowerCase()
|
|
587
|
+
}
|
|
588
|
+
const computedAddr = computeAddress('0x' + localKey.publicKeyHex).toLowerCase()
|
|
589
|
+
return computedAddr === vmEthAddr
|
|
581
590
|
}
|
|
582
591
|
|
|
583
592
|
export async function getAgentDIDMethods(context: IAgentContext<IDIDManager>) {
|
|
584
|
-
|
|
593
|
+
return (await context.agent.didManagerGetProviders()).map((provider) => provider.toLowerCase().replace('did:', ''))
|
|
585
594
|
}
|
|
586
595
|
|
|
587
596
|
export function getDID(idOpts: { identifier: IIdentifier | string }): string {
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
597
|
+
if (typeof idOpts.identifier === 'string') {
|
|
598
|
+
return idOpts.identifier
|
|
599
|
+
} else if (typeof idOpts.identifier === 'object') {
|
|
600
|
+
return idOpts.identifier.did
|
|
601
|
+
}
|
|
602
|
+
throw Error(`Cannot get DID from identifier value`)
|
|
594
603
|
}
|
|
595
604
|
|
|
596
605
|
export function toDID(identifier: string | IIdentifier | Partial<IIdentifier>): string {
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
606
|
+
if (typeof identifier === 'string') {
|
|
607
|
+
return identifier
|
|
608
|
+
}
|
|
609
|
+
if (identifier.did) {
|
|
610
|
+
return identifier.did
|
|
611
|
+
}
|
|
612
|
+
throw Error(`No DID value present in identifier`)
|
|
604
613
|
}
|
|
605
614
|
|
|
606
615
|
export function toDIDs(identifiers?: (string | IIdentifier | Partial<IIdentifier>)[]): string[] {
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
616
|
+
if (!identifiers) {
|
|
617
|
+
return []
|
|
618
|
+
}
|
|
619
|
+
return identifiers.map(toDID)
|
|
611
620
|
}
|
|
612
621
|
|
|
613
622
|
export async function getKey(
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
623
|
+
{
|
|
624
|
+
identifier,
|
|
625
|
+
vmRelationship = 'authentication',
|
|
626
|
+
kmsKeyRef,
|
|
627
|
+
}: {
|
|
628
|
+
identifier: IIdentifier
|
|
629
|
+
vmRelationship?: DIDDocumentSection
|
|
630
|
+
kmsKeyRef?: string
|
|
631
|
+
},
|
|
632
|
+
context: IAgentContext<IResolver & IDIDManager>
|
|
624
633
|
): Promise<IKey> {
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
}
|
|
628
|
-
// normalize to kid, in case keyId was passed in as did#vm or #vm
|
|
629
|
-
const kmsKeyRefParts = kmsKeyRef?.split(`#`)
|
|
630
|
-
const kid = kmsKeyRefParts ? (kmsKeyRefParts?.length === 2 ? kmsKeyRefParts[1] : kmsKeyRefParts[0]) : undefined
|
|
631
|
-
// todo: We really should do a keyRef and external kid here
|
|
632
|
-
let identifierKey = kmsKeyRef ? identifier.keys.find((key: IKey) => key.kid === kid || key?.meta?.jwkThumbprint === kid) : undefined
|
|
633
|
-
if (!identifierKey) {
|
|
634
|
-
const keys = await mapIdentifierKeysToDocWithJwkSupport({ identifier, vmRelationship: vmRelationship }, context)
|
|
635
|
-
if (!keys || keys.length === 0) {
|
|
636
|
-
throw new Error(`No keys found for verificationMethodSection: ${vmRelationship} and did ${identifier.did}`)
|
|
637
|
-
}
|
|
638
|
-
if (kmsKeyRef) {
|
|
639
|
-
identifierKey = keys.find(
|
|
640
|
-
(key: _ExtendedIKey) => key.meta.verificationMethod?.id === kmsKeyRef || (kid && key.meta.verificationMethod?.id?.includes(kid))
|
|
641
|
-
)
|
|
634
|
+
if (!identifier) {
|
|
635
|
+
return Promise.reject(new Error(`No identifier provided to getKey method!`))
|
|
642
636
|
}
|
|
637
|
+
// normalize to kid, in case keyId was passed in as did#vm or #vm
|
|
638
|
+
const kmsKeyRefParts = kmsKeyRef?.split(`#`)
|
|
639
|
+
const kid = kmsKeyRefParts ? (kmsKeyRefParts?.length === 2 ? kmsKeyRefParts[1] : kmsKeyRefParts[0]) : undefined
|
|
640
|
+
// todo: We really should do a keyRef and external kid here
|
|
641
|
+
let identifierKey = kmsKeyRef ? identifier.keys.find((key: IKey) => key.kid === kid || key?.meta?.jwkThumbprint === kid) : undefined
|
|
643
642
|
if (!identifierKey) {
|
|
644
|
-
|
|
645
|
-
(
|
|
646
|
-
|
|
643
|
+
const keys = await mapIdentifierKeysToDocWithJwkSupport({identifier, vmRelationship: vmRelationship}, context)
|
|
644
|
+
if (!keys || keys.length === 0) {
|
|
645
|
+
throw new Error(`No keys found for verificationMethodSection: ${vmRelationship} and did ${identifier.did}`)
|
|
646
|
+
}
|
|
647
|
+
if (kmsKeyRef) {
|
|
648
|
+
identifierKey = keys.find(
|
|
649
|
+
(key: _ExtendedIKey) => key.meta.verificationMethod?.id === kmsKeyRef || (kid && key.meta.verificationMethod?.id?.includes(kid))
|
|
650
|
+
)
|
|
651
|
+
}
|
|
652
|
+
if (!identifierKey) {
|
|
653
|
+
identifierKey = keys.find(
|
|
654
|
+
(key: _ExtendedIKey) => key.meta.verificationMethod?.type === vmRelationship || key.meta.purposes?.includes(vmRelationship)
|
|
655
|
+
)
|
|
656
|
+
}
|
|
657
|
+
if (!identifierKey) {
|
|
658
|
+
identifierKey = keys[0]
|
|
659
|
+
}
|
|
647
660
|
}
|
|
648
661
|
if (!identifierKey) {
|
|
649
|
-
|
|
662
|
+
throw new Error(
|
|
663
|
+
`No matching verificationMethodSection key found for keyId: ${kmsKeyRef} and vmSection: ${vmRelationship} for id ${identifier.did}`
|
|
664
|
+
)
|
|
650
665
|
}
|
|
651
|
-
}
|
|
652
|
-
if (!identifierKey) {
|
|
653
|
-
throw new Error(
|
|
654
|
-
`No matching verificationMethodSection key found for keyId: ${kmsKeyRef} and vmSection: ${vmRelationship} for id ${identifier.did}`
|
|
655
|
-
)
|
|
656
|
-
}
|
|
657
666
|
|
|
658
|
-
|
|
667
|
+
return identifierKey
|
|
659
668
|
}
|
|
660
669
|
|
|
661
670
|
/**
|
|
@@ -666,17 +675,17 @@ export async function getKey(
|
|
|
666
675
|
* @deprecated Replaced by the identfier resolution plugin
|
|
667
676
|
*/
|
|
668
677
|
async function legacyGetIdentifier(
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
678
|
+
{
|
|
679
|
+
identifier,
|
|
680
|
+
}: {
|
|
681
|
+
identifier: string | IIdentifier
|
|
682
|
+
},
|
|
683
|
+
context: IAgentContext<IDIDManager>
|
|
675
684
|
): Promise<IIdentifier> {
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
685
|
+
if (typeof identifier === 'string') {
|
|
686
|
+
return await context.agent.didManagerGet({did: identifier})
|
|
687
|
+
}
|
|
688
|
+
return identifier
|
|
680
689
|
}
|
|
681
690
|
|
|
682
691
|
/**
|
|
@@ -686,132 +695,132 @@ async function legacyGetIdentifier(
|
|
|
686
695
|
* @param context
|
|
687
696
|
*/
|
|
688
697
|
export async function determineKid(
|
|
689
|
-
{
|
|
690
|
-
key,
|
|
691
|
-
idOpts,
|
|
692
|
-
}: {
|
|
693
|
-
key: IKey
|
|
694
|
-
idOpts: { identifier: IIdentifier | string; kmsKeyRef?: string }
|
|
695
|
-
},
|
|
696
|
-
context: IAgentContext<IResolver & IDIDManager>
|
|
697
|
-
): Promise<string> {
|
|
698
|
-
if (key.meta?.verificationMethod?.id) {
|
|
699
|
-
return key.meta?.verificationMethod?.id
|
|
700
|
-
}
|
|
701
|
-
const identifier = await legacyGetIdentifier(idOpts, context)
|
|
702
|
-
const mappedKeys = await mapIdentifierKeysToDocWithJwkSupport(
|
|
703
698
|
{
|
|
704
|
-
|
|
705
|
-
|
|
699
|
+
key,
|
|
700
|
+
idOpts,
|
|
701
|
+
}: {
|
|
702
|
+
key: IKey
|
|
703
|
+
idOpts: { identifier: IIdentifier | string; kmsKeyRef?: string }
|
|
706
704
|
},
|
|
707
|
-
context
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
705
|
+
context: IAgentContext<IResolver & IDIDManager>
|
|
706
|
+
): Promise<string> {
|
|
707
|
+
if (key.meta?.verificationMethod?.id) {
|
|
708
|
+
return key.meta?.verificationMethod?.id
|
|
709
|
+
}
|
|
710
|
+
const identifier = await legacyGetIdentifier(idOpts, context)
|
|
711
|
+
const mappedKeys = await mapIdentifierKeysToDocWithJwkSupport(
|
|
712
|
+
{
|
|
713
|
+
identifier,
|
|
714
|
+
vmRelationship: 'verificationMethod',
|
|
715
|
+
},
|
|
716
|
+
context
|
|
717
|
+
)
|
|
718
|
+
const vmKey = mappedKeys.find((extendedKey) => extendedKey.kid === key.kid)
|
|
719
|
+
if (vmKey) {
|
|
720
|
+
return vmKey.meta?.verificationMethod?.id ?? vmKey.meta?.jwkThumbprint ?? idOpts.kmsKeyRef ?? vmKey.kid
|
|
721
|
+
}
|
|
713
722
|
|
|
714
|
-
|
|
723
|
+
return key.meta?.jwkThumbprint ?? idOpts.kmsKeyRef ?? key.kid
|
|
715
724
|
}
|
|
716
725
|
|
|
717
726
|
export async function getSupportedDIDMethods(didOpts: IDIDOptions, context: IAgentContext<IDIDManager>) {
|
|
718
|
-
|
|
727
|
+
return didOpts.supportedDIDMethods ?? (await getAgentDIDMethods(context))
|
|
719
728
|
}
|
|
720
729
|
|
|
721
730
|
export function getAgentResolver(
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
731
|
+
context: IAgentContext<IResolver & IDIDManager>,
|
|
732
|
+
opts?: {
|
|
733
|
+
localResolution?: boolean // Resolve identifiers hosted by the agent
|
|
734
|
+
uniresolverResolution?: boolean // Resolve identifiers using universal resolver
|
|
735
|
+
resolverResolution?: boolean // Use registered drivers
|
|
736
|
+
}
|
|
728
737
|
): Resolvable {
|
|
729
|
-
|
|
738
|
+
return new AgentDIDResolver(context, opts)
|
|
730
739
|
}
|
|
731
740
|
|
|
732
741
|
export class AgentDIDResolver implements Resolvable {
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
742
|
+
private readonly context: IAgentContext<IResolver & IDIDManager>
|
|
743
|
+
private readonly resolverResolution: boolean
|
|
744
|
+
private readonly uniresolverResolution: boolean
|
|
745
|
+
private readonly localResolution: boolean
|
|
746
|
+
|
|
747
|
+
constructor(
|
|
748
|
+
context: IAgentContext<IResolver & IDIDManager>,
|
|
749
|
+
opts?: { uniresolverResolution?: boolean; localResolution?: boolean; resolverResolution?: boolean }
|
|
750
|
+
) {
|
|
751
|
+
this.context = context
|
|
752
|
+
this.resolverResolution = opts?.resolverResolution !== false
|
|
753
|
+
this.uniresolverResolution = opts?.uniresolverResolution !== false
|
|
754
|
+
this.localResolution = opts?.localResolution !== false
|
|
755
|
+
}
|
|
737
756
|
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
resolutionResult = await this.context.agent.resolveDid({ didUrl, options })
|
|
758
|
-
} catch (error: unknown) {
|
|
759
|
-
err = error
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
if (resolutionResult) {
|
|
763
|
-
origResolutionResult = resolutionResult
|
|
764
|
-
if (resolutionResult.didDocument === null) {
|
|
765
|
-
resolutionResult = undefined
|
|
766
|
-
}
|
|
767
|
-
} else {
|
|
768
|
-
console.log(`Agent resolver resolution is disabled. This typically isn't desirable!`)
|
|
769
|
-
}
|
|
770
|
-
if (!resolutionResult && this.localResolution) {
|
|
771
|
-
console.log(`Using local DID resolution, looking at DIDs hosted by the agent.`)
|
|
772
|
-
try {
|
|
773
|
-
const did = didUrl.split('#')[0]
|
|
774
|
-
const iIdentifier = await this.context.agent.didManagerGet({ did })
|
|
775
|
-
resolutionResult = toDidResolutionResult(iIdentifier, { did })
|
|
776
|
-
if (resolutionResult.didDocument) {
|
|
777
|
-
err = undefined
|
|
757
|
+
async resolve(didUrl: string, options?: DIDResolutionOptions): Promise<DIDResolutionResult> {
|
|
758
|
+
let resolutionResult: DIDResolutionResult | undefined
|
|
759
|
+
let origResolutionResult: DIDResolutionResult | undefined
|
|
760
|
+
let err: any
|
|
761
|
+
if (!this.resolverResolution && !this.localResolution && !this.uniresolverResolution) {
|
|
762
|
+
throw Error(`No agent hosted DID resolution, regular agent resolution nor universal resolver resolution is enabled. Cannot resolve DIDs.`)
|
|
763
|
+
}
|
|
764
|
+
if (this.resolverResolution) {
|
|
765
|
+
try {
|
|
766
|
+
resolutionResult = await this.context.agent.resolveDid({didUrl, options})
|
|
767
|
+
} catch (error: unknown) {
|
|
768
|
+
err = error
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
if (resolutionResult) {
|
|
772
|
+
origResolutionResult = resolutionResult
|
|
773
|
+
if (resolutionResult.didDocument === null) {
|
|
774
|
+
resolutionResult = undefined
|
|
775
|
+
}
|
|
778
776
|
} else {
|
|
779
|
-
|
|
777
|
+
console.log(`Agent resolver resolution is disabled. This typically isn't desirable!`)
|
|
780
778
|
}
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
779
|
+
if (!resolutionResult && this.localResolution) {
|
|
780
|
+
console.log(`Using local DID resolution, looking at DIDs hosted by the agent.`)
|
|
781
|
+
try {
|
|
782
|
+
const did = didUrl.split('#')[0]
|
|
783
|
+
const iIdentifier = await this.context.agent.didManagerGet({did})
|
|
784
|
+
resolutionResult = toDidResolutionResult(iIdentifier, {did})
|
|
785
|
+
if (resolutionResult.didDocument) {
|
|
786
|
+
err = undefined
|
|
787
|
+
} else {
|
|
788
|
+
console.log(`Local resolution resulted in a DID Document for ${did}`)
|
|
789
|
+
}
|
|
790
|
+
} catch (error: unknown) {
|
|
791
|
+
if (!err) {
|
|
792
|
+
err = error
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
if (resolutionResult) {
|
|
797
|
+
if (!origResolutionResult) {
|
|
798
|
+
origResolutionResult = resolutionResult
|
|
799
|
+
}
|
|
800
|
+
if (!resolutionResult.didDocument) {
|
|
801
|
+
resolutionResult = undefined
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
if (!resolutionResult && this.uniresolverResolution) {
|
|
805
|
+
console.log(`Using universal resolver resolution for did ${didUrl} `)
|
|
806
|
+
resolutionResult = await new UniResolver().resolve(didUrl, options)
|
|
807
|
+
if (!origResolutionResult) {
|
|
808
|
+
origResolutionResult = resolutionResult
|
|
809
|
+
}
|
|
810
|
+
if (resolutionResult.didDocument) {
|
|
811
|
+
err = undefined
|
|
812
|
+
}
|
|
784
813
|
}
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
if (resolutionResult) {
|
|
788
|
-
if (!origResolutionResult) {
|
|
789
|
-
origResolutionResult = resolutionResult
|
|
790
|
-
}
|
|
791
|
-
if (!resolutionResult.didDocument) {
|
|
792
|
-
resolutionResult = undefined
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
if (!resolutionResult && this.uniresolverResolution) {
|
|
796
|
-
console.log(`Using universal resolver resolution for did ${didUrl} `)
|
|
797
|
-
resolutionResult = await new UniResolver().resolve(didUrl, options)
|
|
798
|
-
if (!origResolutionResult) {
|
|
799
|
-
origResolutionResult = resolutionResult
|
|
800
|
-
}
|
|
801
|
-
if (resolutionResult.didDocument) {
|
|
802
|
-
err = undefined
|
|
803
|
-
}
|
|
804
|
-
}
|
|
805
814
|
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
815
|
+
if (err) {
|
|
816
|
+
// throw original error
|
|
817
|
+
throw err
|
|
818
|
+
}
|
|
819
|
+
if (!resolutionResult && !origResolutionResult) {
|
|
820
|
+
throw `Could not resolve ${didUrl}. Resolutions tried: online: ${this.resolverResolution}, local: ${this.localResolution}, uni resolver: ${this.uniresolverResolution}`
|
|
821
|
+
}
|
|
822
|
+
return resolutionResult ?? origResolutionResult!
|
|
812
823
|
}
|
|
813
|
-
return resolutionResult ?? origResolutionResult!
|
|
814
|
-
}
|
|
815
824
|
}
|
|
816
825
|
|
|
817
826
|
/**
|
|
@@ -825,190 +834,190 @@ export class AgentDIDResolver implements Resolvable {
|
|
|
825
834
|
* @param opts
|
|
826
835
|
*/
|
|
827
836
|
export function toDidDocument(
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
837
|
+
identifier?: IIdentifier,
|
|
838
|
+
opts?: {
|
|
839
|
+
did?: string
|
|
840
|
+
use?: JwkKeyUse[]
|
|
841
|
+
}
|
|
833
842
|
): DIDDocument | undefined {
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
}),
|
|
853
|
-
...((opts?.use === undefined || opts?.use?.includes(JwkKeyUse.Signature)) &&
|
|
854
|
-
identifier.keys && {
|
|
855
|
-
assertionMethod: identifier.keys
|
|
856
|
-
.filter(
|
|
857
|
-
(key) =>
|
|
858
|
-
key?.meta?.purpose === undefined || key?.meta?.purpose === 'assertionMethod' || key?.meta?.purposes?.includes('assertionMethod')
|
|
859
|
-
)
|
|
860
|
-
.map((key) => {
|
|
861
|
-
if (key.kid.startsWith(did) && key.kid.includes('#')) {
|
|
862
|
-
return key.kid
|
|
863
|
-
}
|
|
864
|
-
return `${did}#${key.kid}`
|
|
865
|
-
}),
|
|
866
|
-
}),
|
|
867
|
-
...((opts?.use === undefined || opts?.use?.includes(JwkKeyUse.Signature)) &&
|
|
868
|
-
identifier.keys && {
|
|
869
|
-
authentication: identifier.keys
|
|
870
|
-
.filter(
|
|
871
|
-
(key) => key?.meta?.purpose === undefined || key?.meta?.purpose === 'authentication' || key?.meta?.purposes?.includes('authentication')
|
|
872
|
-
)
|
|
873
|
-
.map((key) => {
|
|
874
|
-
if (key.kid.startsWith(did) && key.kid.includes('#')) {
|
|
875
|
-
return key.kid
|
|
876
|
-
}
|
|
877
|
-
return `${did}#${key.kid}`
|
|
878
|
-
}),
|
|
879
|
-
}),
|
|
880
|
-
...((opts?.use === undefined || opts?.use?.includes(JwkKeyUse.Encryption)) &&
|
|
881
|
-
identifier.keys && {
|
|
882
|
-
keyAgreement: identifier.keys
|
|
883
|
-
.filter((key) => key.type === 'X25519' || key?.meta?.purpose === 'keyAgreement' || key?.meta?.purposes?.includes('keyAgreement'))
|
|
884
|
-
.map((key) => {
|
|
885
|
-
if (key.kid.startsWith(did) && key.kid.includes('#')) {
|
|
886
|
-
return key.kid
|
|
887
|
-
}
|
|
888
|
-
return `${did}#${key.kid}`
|
|
889
|
-
}),
|
|
890
|
-
}),
|
|
891
|
-
...((opts?.use === undefined || opts?.use?.includes(JwkKeyUse.Encryption)) &&
|
|
892
|
-
identifier.keys && {
|
|
893
|
-
capabilityInvocation: identifier.keys
|
|
894
|
-
.filter(
|
|
895
|
-
(key) => key.type === 'X25519' || key?.meta?.purpose === 'capabilityInvocation' || key?.meta?.purposes?.includes('capabilityInvocation')
|
|
896
|
-
)
|
|
897
|
-
.map((key) => {
|
|
898
|
-
if (key.kid.startsWith(did) && key.kid.includes('#')) {
|
|
899
|
-
return key.kid
|
|
900
|
-
}
|
|
901
|
-
return `${did}#${key.kid}`
|
|
902
|
-
}),
|
|
903
|
-
}),
|
|
904
|
-
...((opts?.use === undefined || opts?.use?.includes(JwkKeyUse.Encryption)) &&
|
|
905
|
-
identifier.keys && {
|
|
906
|
-
capabilityDelegation: identifier.keys
|
|
907
|
-
.filter(
|
|
908
|
-
(key) => key.type === 'X25519' || key?.meta?.purpose === 'capabilityDelegation' || key?.meta?.purposes?.includes('capabilityDelegation')
|
|
909
|
-
)
|
|
910
|
-
.map((key) => {
|
|
911
|
-
if (key.kid.startsWith(did) && key.kid.includes('#')) {
|
|
912
|
-
return key.kid
|
|
913
|
-
}
|
|
914
|
-
return `${did}#${key.kid}`
|
|
843
|
+
let didDocument: DIDDocument | undefined = undefined
|
|
844
|
+
// TODO: Introduce jwk thumbprints here
|
|
845
|
+
if (identifier) {
|
|
846
|
+
const did = identifier.did ?? opts?.did
|
|
847
|
+
didDocument = {
|
|
848
|
+
'@context': 'https://www.w3.org/ns/did/v1',
|
|
849
|
+
id: did,
|
|
850
|
+
verificationMethod: identifier.keys.map((key) => {
|
|
851
|
+
const vm: VerificationMethod = {
|
|
852
|
+
controller: did,
|
|
853
|
+
id: key.kid.startsWith(did) && key.kid.includes('#') ? key.kid : `${did}#${key.kid}`,
|
|
854
|
+
publicKeyJwk: toJwk(key.publicKeyHex, key.type, {
|
|
855
|
+
use: ENC_KEY_ALGS.includes(key.type) ? JwkKeyUse.Encryption : JwkKeyUse.Signature,
|
|
856
|
+
key,
|
|
857
|
+
}) as JsonWebKey,
|
|
858
|
+
type: 'JsonWebKey2020',
|
|
859
|
+
}
|
|
860
|
+
return vm
|
|
915
861
|
}),
|
|
916
|
-
|
|
917
|
-
|
|
862
|
+
...((opts?.use === undefined || opts?.use?.includes(JwkKeyUse.Signature)) &&
|
|
863
|
+
identifier.keys && {
|
|
864
|
+
assertionMethod: identifier.keys
|
|
865
|
+
.filter(
|
|
866
|
+
(key) =>
|
|
867
|
+
key?.meta?.purpose === undefined || key?.meta?.purpose === 'assertionMethod' || key?.meta?.purposes?.includes('assertionMethod')
|
|
868
|
+
)
|
|
869
|
+
.map((key) => {
|
|
870
|
+
if (key.kid.startsWith(did) && key.kid.includes('#')) {
|
|
871
|
+
return key.kid
|
|
872
|
+
}
|
|
873
|
+
return `${did}#${key.kid}`
|
|
874
|
+
}),
|
|
875
|
+
}),
|
|
876
|
+
...((opts?.use === undefined || opts?.use?.includes(JwkKeyUse.Signature)) &&
|
|
877
|
+
identifier.keys && {
|
|
878
|
+
authentication: identifier.keys
|
|
879
|
+
.filter(
|
|
880
|
+
(key) => key?.meta?.purpose === undefined || key?.meta?.purpose === 'authentication' || key?.meta?.purposes?.includes('authentication')
|
|
881
|
+
)
|
|
882
|
+
.map((key) => {
|
|
883
|
+
if (key.kid.startsWith(did) && key.kid.includes('#')) {
|
|
884
|
+
return key.kid
|
|
885
|
+
}
|
|
886
|
+
return `${did}#${key.kid}`
|
|
887
|
+
}),
|
|
888
|
+
}),
|
|
889
|
+
...((opts?.use === undefined || opts?.use?.includes(JwkKeyUse.Encryption)) &&
|
|
890
|
+
identifier.keys && {
|
|
891
|
+
keyAgreement: identifier.keys
|
|
892
|
+
.filter((key) => key.type === 'X25519' || key?.meta?.purpose === 'keyAgreement' || key?.meta?.purposes?.includes('keyAgreement'))
|
|
893
|
+
.map((key) => {
|
|
894
|
+
if (key.kid.startsWith(did) && key.kid.includes('#')) {
|
|
895
|
+
return key.kid
|
|
896
|
+
}
|
|
897
|
+
return `${did}#${key.kid}`
|
|
898
|
+
}),
|
|
899
|
+
}),
|
|
900
|
+
...((opts?.use === undefined || opts?.use?.includes(JwkKeyUse.Encryption)) &&
|
|
901
|
+
identifier.keys && {
|
|
902
|
+
capabilityInvocation: identifier.keys
|
|
903
|
+
.filter(
|
|
904
|
+
(key) => key.type === 'X25519' || key?.meta?.purpose === 'capabilityInvocation' || key?.meta?.purposes?.includes('capabilityInvocation')
|
|
905
|
+
)
|
|
906
|
+
.map((key) => {
|
|
907
|
+
if (key.kid.startsWith(did) && key.kid.includes('#')) {
|
|
908
|
+
return key.kid
|
|
909
|
+
}
|
|
910
|
+
return `${did}#${key.kid}`
|
|
911
|
+
}),
|
|
912
|
+
}),
|
|
913
|
+
...((opts?.use === undefined || opts?.use?.includes(JwkKeyUse.Encryption)) &&
|
|
914
|
+
identifier.keys && {
|
|
915
|
+
capabilityDelegation: identifier.keys
|
|
916
|
+
.filter(
|
|
917
|
+
(key) => key.type === 'X25519' || key?.meta?.purpose === 'capabilityDelegation' || key?.meta?.purposes?.includes('capabilityDelegation')
|
|
918
|
+
)
|
|
919
|
+
.map((key) => {
|
|
920
|
+
if (key.kid.startsWith(did) && key.kid.includes('#')) {
|
|
921
|
+
return key.kid
|
|
922
|
+
}
|
|
923
|
+
return `${did}#${key.kid}`
|
|
924
|
+
}),
|
|
925
|
+
}),
|
|
926
|
+
...(identifier.services && identifier.services.length > 0 && {service: identifier.services}),
|
|
927
|
+
}
|
|
918
928
|
}
|
|
919
|
-
|
|
920
|
-
return didDocument
|
|
929
|
+
return didDocument
|
|
921
930
|
}
|
|
922
931
|
|
|
923
932
|
export function toDidResolutionResult(
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
933
|
+
identifier?: IIdentifier,
|
|
934
|
+
opts?: {
|
|
935
|
+
did?: string
|
|
936
|
+
supportedMethods?: string[]
|
|
937
|
+
}
|
|
929
938
|
): DIDResolutionResult {
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
939
|
+
const didDocument = toDidDocument(identifier, opts) ?? null // null is used in case of errors and required by the did resolution spec
|
|
940
|
+
|
|
941
|
+
const resolutionResult: DIDResolutionResult = {
|
|
942
|
+
'@context': 'https://w3id.org/did-resolution/v1',
|
|
943
|
+
didDocument,
|
|
944
|
+
didResolutionMetadata: {
|
|
945
|
+
...(!didDocument && {error: 'notFound'}),
|
|
946
|
+
...(Array.isArray(opts?.supportedMethods) &&
|
|
947
|
+
identifier &&
|
|
948
|
+
!opts?.supportedMethods.includes(identifier.provider.replace('did:', '')) && {error: 'unsupportedDidMethod'}),
|
|
949
|
+
},
|
|
950
|
+
didDocumentMetadata: {
|
|
951
|
+
...(identifier?.alias && {equivalentId: identifier?.alias}),
|
|
952
|
+
},
|
|
953
|
+
}
|
|
954
|
+
return resolutionResult
|
|
946
955
|
}
|
|
947
956
|
|
|
948
957
|
export async function asDidWeb(hostnameOrDID: string): Promise<string> {
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
958
|
+
let did = hostnameOrDID
|
|
959
|
+
if (!did) {
|
|
960
|
+
throw Error('Domain or DID expected, but received nothing.')
|
|
961
|
+
}
|
|
962
|
+
if (did.startsWith('did:web:')) {
|
|
963
|
+
return did
|
|
964
|
+
}
|
|
965
|
+
return `did:web:${did.replace(/https?:\/\/([^/?#]+).*/i, '$1').toLowerCase()}`
|
|
957
966
|
}
|
|
958
967
|
|
|
959
968
|
/**
|
|
960
969
|
* @deprecated Replaced by the new signer service
|
|
961
970
|
*/
|
|
962
971
|
export const signDidJWT = async (args: SignJwtArgs): Promise<string> => {
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
972
|
+
const {idOpts, header, payload, context, options} = args
|
|
973
|
+
const jwtOptions = {
|
|
974
|
+
...options,
|
|
975
|
+
signer: await getDidSigner({idOpts, context}),
|
|
976
|
+
}
|
|
968
977
|
|
|
969
|
-
|
|
978
|
+
return createJWT(payload, jwtOptions, header)
|
|
970
979
|
}
|
|
971
980
|
|
|
972
981
|
/**
|
|
973
982
|
* @deprecated Replaced by the new signer service
|
|
974
983
|
*/
|
|
975
984
|
export const getDidSigner = async (
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
985
|
+
args: GetSignerArgs & {
|
|
986
|
+
idOpts: {
|
|
987
|
+
/**
|
|
988
|
+
* @deprecated
|
|
989
|
+
*/
|
|
990
|
+
identifier: IIdentifier | string
|
|
991
|
+
/**
|
|
992
|
+
* @deprecated
|
|
993
|
+
*/
|
|
994
|
+
verificationMethodSection?: DIDDocumentSection
|
|
995
|
+
/**
|
|
996
|
+
* @deprecated
|
|
997
|
+
*/
|
|
998
|
+
kmsKeyRef?: string
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
992
1001
|
): Promise<Signer> => {
|
|
993
|
-
|
|
1002
|
+
const {idOpts, context} = args
|
|
994
1003
|
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1004
|
+
const identifier = await legacyGetIdentifier(idOpts, context)
|
|
1005
|
+
const key = await getKey(
|
|
1006
|
+
{
|
|
1007
|
+
identifier,
|
|
1008
|
+
vmRelationship: idOpts.verificationMethodSection,
|
|
1009
|
+
kmsKeyRef: idOpts.kmsKeyRef,
|
|
1010
|
+
},
|
|
1011
|
+
context
|
|
1012
|
+
)
|
|
1013
|
+
const algorithm = await signatureAlgorithmFromKey({key})
|
|
1014
|
+
|
|
1015
|
+
return async (data: string | Uint8Array): Promise<string> => {
|
|
1016
|
+
const input = data instanceof Object.getPrototypeOf(Uint8Array) ? new TextDecoder().decode(data as Uint8Array) : (data as string)
|
|
1017
|
+
return await context.agent.keyManagerSign({
|
|
1018
|
+
keyRef: key.kid,
|
|
1019
|
+
algorithm,
|
|
1020
|
+
data: input,
|
|
1021
|
+
})
|
|
1022
|
+
}
|
|
1014
1023
|
}
|