|
4 | 4 | CheqdNetwork, |
5 | 5 | DIDDocument, |
6 | 6 | MethodSpecificIdAlgo, |
7 | | - Service, |
8 | 7 | VerificationMethods, |
9 | 8 | createDidVerificationMethod, |
10 | 9 | } from '@cheqd/sdk'; |
@@ -32,6 +31,7 @@ import type { |
32 | 31 | GetDIDRequestParams, |
33 | 32 | ResolveDIDRequestParams, |
34 | 33 | DeactivateDIDRequestBody, |
| 34 | + ExportDidResponse, |
35 | 35 | } from '../../types/did.js'; |
36 | 36 | import { check, param } from '../validator/index.js'; |
37 | 37 | import type { IIdentifier, IKey, RequireOnly } from '@veramo/core'; |
@@ -124,7 +124,7 @@ export class DIDController { |
124 | 124 | check('publicKeyHexs').optional().isArray().withMessage('publicKeyHexs should be an array of strings').bail(), |
125 | 125 | ]; |
126 | 126 |
|
127 | | - public static deactivateDIDValidator = [param('did').exists().isString().isDID().bail()]; |
| 127 | + public static didPathValidator = [param('did').exists().isString().isDID().bail()]; |
128 | 128 |
|
129 | 129 | public static importDIDValidator = [ |
130 | 130 | check('did').isDID().bail(), |
@@ -211,112 +211,109 @@ export class DIDController { |
211 | 211 | // Get strategy e.g. postgres or local |
212 | 212 | const identityServiceStrategySetup = new IdentityServiceStrategySetup(response.locals.customer.customerId); |
213 | 213 | try { |
214 | | - if (request.body.didDocument) { |
215 | | - didDocument = request.body.didDocument; |
216 | | - if (verificationMethodType) { |
217 | | - const publicKeyHex = |
218 | | - key || |
219 | | - ( |
220 | | - await identityServiceStrategySetup.agent.createKey( |
221 | | - SupportedKeyTypes.Ed25519, |
222 | | - response.locals.customer |
223 | | - ) |
224 | | - ).publicKeyHex; |
225 | | - |
226 | | - const pkBase64 = toString(fromString(publicKeyHex, 'hex'), 'base64'); |
227 | | - didDocument.verificationMethod = createDidVerificationMethod( |
228 | | - [verificationMethodType], |
229 | | - [ |
230 | | - { |
231 | | - methodSpecificId: bases['base58btc'].encode(base64ToBytes(pkBase64)), |
232 | | - didUrl: didDocument.id, |
233 | | - keyId: `${didDocument.id}#key-1`, |
234 | | - publicKey: pkBase64, |
235 | | - }, |
236 | | - ] |
237 | | - ); |
238 | | - } else { |
239 | | - return response.status(StatusCodes.BAD_REQUEST).json({ |
240 | | - error: 'Provide options section to create a DID', |
241 | | - } satisfies UnsuccessfulCreateDidResponseBody); |
242 | | - } |
243 | | - } else if (verificationMethodType) { |
244 | | - const publicKeyHex = |
245 | | - key || |
246 | | - ( |
247 | | - await identityServiceStrategySetup.agent.createKey( |
248 | | - SupportedKeyTypes.Ed25519, |
249 | | - response.locals.customer |
250 | | - ) |
251 | | - ).publicKeyHex; |
252 | | - didDocument = generateDidDoc({ |
253 | | - verificationMethod: verificationMethodType, |
254 | | - verificationMethodId: 'key-1', |
255 | | - methodSpecificIdAlgo: identifierFormatType || MethodSpecificIdAlgo.Uuid, |
256 | | - network, |
257 | | - publicKey: publicKeyHex, |
258 | | - }); |
259 | | - |
260 | | - if (Array.isArray(request.body['@context'])) { |
261 | | - didDocument['@context'] = request.body['@context']; |
262 | | - } |
263 | | - if (typeof request.body['@context'] === 'string') { |
264 | | - didDocument['@context'] = [request.body['@context']]; |
265 | | - } |
266 | | - |
267 | | - if (service) { |
268 | | - if (Array.isArray(service)) { |
269 | | - try { |
270 | | - const services = service as Service[]; |
271 | | - didDocument.service = []; |
272 | | - for (const service of services) { |
273 | | - didDocument.service.push({ |
274 | | - id: `${didDocument.id}#${service.idFragment}`, |
275 | | - type: service.type, |
276 | | - serviceEndpoint: service.serviceEndpoint, |
277 | | - recipientKeys: service.recipientKeys, |
278 | | - routingKeys: service.routingKeys, |
279 | | - priority: service.priority, |
280 | | - accept: service.accept, |
281 | | - }); |
282 | | - } |
283 | | - } catch (e) { |
284 | | - return response.status(StatusCodes.BAD_REQUEST).json({ |
285 | | - error: 'Provide the correct service section to create a DID', |
286 | | - } satisfies UnsuccessfulCreateDidResponseBody); |
287 | | - } |
288 | | - } else { |
289 | | - didDocument.service = [ |
290 | | - { |
291 | | - id: `${didDocument.id}#${service.idFragment}`, |
| 214 | + let did: IIdentifier; |
| 215 | + switch (providerId) { |
| 216 | + case 'dock': |
| 217 | + did = await new DockIdentityService().createDid(network, { id: '' }, response.locals.customer); |
| 218 | + const { didDocument: didDoc } = await identityServiceStrategySetup.agent.resolveDid(did.did); |
| 219 | + console.log(didDoc); |
| 220 | + if (didDoc && service) { |
| 221 | + const services = Array.isArray(service) ? service : [service]; |
| 222 | + didDoc.service = didDoc.service || []; |
| 223 | + // handle overriding |
| 224 | + const filteredServices = services.filter((s) => |
| 225 | + didDoc.service?.every((ds) => s.idFragment != ds.id) |
| 226 | + ); |
| 227 | + for (const service of filteredServices) { |
| 228 | + didDoc.service.push({ |
| 229 | + id: `${didDoc.id}#${service.idFragment}`, |
292 | 230 | type: service.type, |
293 | 231 | serviceEndpoint: service.serviceEndpoint, |
294 | 232 | recipientKeys: service.recipientKeys, |
295 | 233 | routingKeys: service.routingKeys, |
296 | 234 | priority: service.priority, |
297 | 235 | accept: service.accept, |
298 | | - }, |
299 | | - ]; |
| 236 | + }); |
| 237 | + } |
| 238 | + did = await identityServiceStrategySetup.agent.updateDid(didDoc, response.locals.customer); |
300 | 239 | } |
301 | | - } |
302 | | - } else { |
303 | | - return response.status(StatusCodes.BAD_REQUEST).json({ |
304 | | - error: 'Provide a DID Document or the VerificationMethodType to create a DID', |
305 | | - } satisfies UnsuccessfulCreateDidResponseBody); |
306 | | - } |
307 | | - |
308 | | - let did: IIdentifier; |
309 | | - switch (providerId) { |
310 | | - case 'dock': |
311 | | - did = await new DockIdentityService().createDid( |
312 | | - network || didDocument.id.split(':')[2], |
313 | | - didDocument, |
314 | | - response.locals.customer |
315 | | - ); |
316 | 240 | break; |
317 | 241 | case 'studio': |
318 | 242 | case undefined: |
319 | | - did = await new IdentityServiceStrategySetup(response.locals.customer.customerId).agent.createDid( |
| 243 | + if (request.body.didDocument) { |
| 244 | + didDocument = request.body.didDocument; |
| 245 | + if (verificationMethodType) { |
| 246 | + const publicKeyHex = |
| 247 | + key || |
| 248 | + ( |
| 249 | + await identityServiceStrategySetup.agent.createKey( |
| 250 | + SupportedKeyTypes.Ed25519, |
| 251 | + response.locals.customer |
| 252 | + ) |
| 253 | + ).publicKeyHex; |
| 254 | + |
| 255 | + const pkBase64 = toString(fromString(publicKeyHex, 'hex'), 'base64'); |
| 256 | + didDocument.verificationMethod = createDidVerificationMethod( |
| 257 | + [verificationMethodType], |
| 258 | + [ |
| 259 | + { |
| 260 | + methodSpecificId: bases['base58btc'].encode(base64ToBytes(pkBase64)), |
| 261 | + didUrl: didDocument.id, |
| 262 | + keyId: `${didDocument.id}#key-1`, |
| 263 | + publicKey: pkBase64, |
| 264 | + }, |
| 265 | + ] |
| 266 | + ); |
| 267 | + } else { |
| 268 | + return response.status(StatusCodes.BAD_REQUEST).json({ |
| 269 | + error: 'Provide options section to create a DID', |
| 270 | + } satisfies UnsuccessfulCreateDidResponseBody); |
| 271 | + } |
| 272 | + } else if (verificationMethodType) { |
| 273 | + const publicKeyHex = |
| 274 | + key || |
| 275 | + ( |
| 276 | + await identityServiceStrategySetup.agent.createKey( |
| 277 | + SupportedKeyTypes.Ed25519, |
| 278 | + response.locals.customer |
| 279 | + ) |
| 280 | + ).publicKeyHex; |
| 281 | + |
| 282 | + didDocument = generateDidDoc({ |
| 283 | + verificationMethod: verificationMethodType, |
| 284 | + verificationMethodId: 'key-1', |
| 285 | + methodSpecificIdAlgo: identifierFormatType || MethodSpecificIdAlgo.Uuid, |
| 286 | + network, |
| 287 | + publicKey: publicKeyHex, |
| 288 | + }); |
| 289 | + |
| 290 | + // populate default assertionMethod to support JSON-LD |
| 291 | + didDocument.assertionMethod = didDocument.authentication; |
| 292 | + |
| 293 | + if (request.body['@context']) { |
| 294 | + didDocument['@context'] = Array.isArray(request.body['@context']) |
| 295 | + ? request.body['@context'] |
| 296 | + : [request.body['@context']]; |
| 297 | + } |
| 298 | + |
| 299 | + if (service) { |
| 300 | + const services = Array.isArray(service) ? service : [service]; |
| 301 | + didDocument.service = services.map((s) => ({ |
| 302 | + id: `${didDocument.id}#${s.idFragment}`, |
| 303 | + type: s.type, |
| 304 | + serviceEndpoint: s.serviceEndpoint, |
| 305 | + recipientKeys: s.recipientKeys, |
| 306 | + routingKeys: s.routingKeys, |
| 307 | + priority: s.priority, |
| 308 | + accept: s.accept, |
| 309 | + })); |
| 310 | + } |
| 311 | + } else { |
| 312 | + return response.status(StatusCodes.BAD_REQUEST).json({ |
| 313 | + error: 'Provide a DID Document or the VerificationMethodType to create a DID', |
| 314 | + } satisfies UnsuccessfulCreateDidResponseBody); |
| 315 | + } |
| 316 | + did = await identityServiceStrategySetup.agent.createDid( |
320 | 317 | network || didDocument.id.split(':')[2], |
321 | 318 | didDocument, |
322 | 319 | response.locals.customer |
@@ -861,4 +858,104 @@ export class DIDController { |
861 | 858 | } satisfies UnsuccessfulResolveDidResponseBody); |
862 | 859 | } |
863 | 860 | } |
| 861 | + |
| 862 | + /** |
| 863 | + * @openapi |
| 864 | + * |
| 865 | + * /did/export/{did}: |
| 866 | + * post: |
| 867 | + * tags: [ Decentralized Identifiers (DIDs) ] |
| 868 | + * summary: Export a DID Document. |
| 869 | + * description: This endpoint exports a decentralized identifier associated with the user's account with the custodied keys. |
| 870 | + * parameters: |
| 871 | + * - in: path |
| 872 | + * name: did |
| 873 | + * description: DID identifier to resolve. |
| 874 | + * schema: |
| 875 | + * type: string |
| 876 | + * required: true |
| 877 | + * requestBody: |
| 878 | + * content: |
| 879 | + * application/x-www-form-urlencoded: |
| 880 | + * schema: |
| 881 | + * type: object |
| 882 | + * properties: |
| 883 | + * password: |
| 884 | + * type: string |
| 885 | + * required: false |
| 886 | + * providerId: |
| 887 | + * type: string |
| 888 | + * required: false |
| 889 | + * application/json: |
| 890 | + * schema: |
| 891 | + * type: object |
| 892 | + * properties: |
| 893 | + * password: |
| 894 | + * type: string |
| 895 | + * required: false |
| 896 | + * providerId: |
| 897 | + * type: string |
| 898 | + * required: false |
| 899 | + * responses: |
| 900 | + * 200: |
| 901 | + * description: The request was successful. |
| 902 | + * content: |
| 903 | + * application/json: |
| 904 | + * schema: |
| 905 | + * $ref: '#/components/schemas/DidResult' |
| 906 | + * 400: |
| 907 | + * description: A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body. |
| 908 | + * content: |
| 909 | + * application/json: |
| 910 | + * schema: |
| 911 | + * $ref: '#/components/schemas/InvalidRequest' |
| 912 | + * example: |
| 913 | + * error: InvalidRequest |
| 914 | + * 401: |
| 915 | + * $ref: '#/components/schemas/UnauthorizedError' |
| 916 | + * 500: |
| 917 | + * description: An internal error has occurred. Additional state information plus metadata may be available in the response body. |
| 918 | + * content: |
| 919 | + * application/json: |
| 920 | + * schema: |
| 921 | + * $ref: '#/components/schemas/InvalidRequest' |
| 922 | + * example: |
| 923 | + * error: Internal Error |
| 924 | + */ |
| 925 | + @validate |
| 926 | + public async exportDid(request: Request, response: Response) { |
| 927 | + try { |
| 928 | + // Get the params from body |
| 929 | + const { did } = request.params as ResolveDIDRequestParams; |
| 930 | + |
| 931 | + const { providerId, password } = request.body; |
| 932 | + let result: ExportDidResponse; |
| 933 | + switch (providerId) { |
| 934 | + case 'dock': |
| 935 | + result = await new DockIdentityService().exportDid(did, password || '', response.locals.customer); |
| 936 | + break; |
| 937 | + case 'studio': |
| 938 | + default: |
| 939 | + result = await new IdentityServiceStrategySetup( |
| 940 | + response.locals.customer.customerId |
| 941 | + ).agent.exportDid(did, '', response.locals.customer); |
| 942 | + } |
| 943 | + // Track the operation |
| 944 | + eventTracker.emit('track', { |
| 945 | + category: OperationCategoryNameEnum.DID, |
| 946 | + name: OperationNameEnum.DID_EXPORT, |
| 947 | + data: { |
| 948 | + did: did, |
| 949 | + } satisfies IDIDTrack, |
| 950 | + customer: response.locals.customer, |
| 951 | + user: response.locals.user, |
| 952 | + } satisfies ITrackOperation); |
| 953 | + |
| 954 | + return response.status(StatusCodes.OK).json(result); |
| 955 | + } catch (error) { |
| 956 | + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ |
| 957 | + error: `Internal error: ${(error as Error)?.message || error}`, |
| 958 | + }); |
| 959 | + } |
| 960 | + } |
864 | 961 | } |
0 commit comments