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