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