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