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