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