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