From 4ce11e23400cbdad4183f19622932357079fb01e Mon Sep 17 00:00:00 2001 From: pranalidhanavade Date: Thu, 6 Mar 2025 12:18:53 +0530 Subject: [PATCH 01/15] Resolve linting issues Signed-off-by: pranalidhanavade Signed-off-by: Krishna Waske --- jest.config.ts | 2 +- src/cli.ts | 2 +- src/cliAgent.ts | 9 ++++++--- src/controllers/agent/AgentController.ts | 2 +- src/controllers/basic-messages/BasicMessageController.ts | 2 +- src/controllers/connections/ConnectionController.ts | 2 +- .../EndorserTransactionController.ts | 2 +- src/controllers/examples.ts | 2 +- src/controllers/outofband/OutOfBandController.ts | 2 +- src/controllers/polygon/PolygonController.ts | 2 +- .../question-answer/QuestionAnswerController.ts | 2 +- src/enums/enum.ts | 2 +- src/errorHandlingService.ts | 2 +- src/events/ReuseConnectionEvents.ts | 2 +- src/server.ts | 2 +- src/utils/agent.ts | 2 +- 16 files changed, 21 insertions(+), 18 deletions(-) diff --git a/jest.config.ts b/jest.config.ts index 2051b80d..93e994ce 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -9,4 +9,4 @@ const config: Config.InitialOptions = { testTimeout: 120000, } -export default config \ No newline at end of file +export default config diff --git a/src/cli.ts b/src/cli.ts index 1541dc39..f352694f 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -253,4 +253,4 @@ export async function runCliServer() { fileServerUrl: parsed.fileServerUrl, fileServerToken: parsed.fileServerToken, } as AriesRestConfig) -} \ No newline at end of file +} diff --git a/src/cliAgent.ts b/src/cliAgent.ts index 73dcd825..1db8a874 100644 --- a/src/cliAgent.ts +++ b/src/cliAgent.ts @@ -189,8 +189,11 @@ const getModules = ( questionAnswer: new QuestionAnswerModule(), polygon: new PolygonModule({ - didContractAddress: didRegistryContractAddress ? didRegistryContractAddress : (process.env.DID_CONTRACT_ADDRESS as string), - schemaManagerContractAddress: schemaManagerContractAddress || (process.env.SCHEMA_MANAGER_CONTRACT_ADDRESS as string), + didContractAddress: didRegistryContractAddress + ? didRegistryContractAddress + : (process.env.DID_CONTRACT_ADDRESS as string), + schemaManagerContractAddress: + schemaManagerContractAddress || (process.env.SCHEMA_MANAGER_CONTRACT_ADDRESS as string), fileServerToken: fileServerToken ? fileServerToken : (process.env.FILE_SERVER_TOKEN as string), rpcUrl: rpcUrl ? rpcUrl : (process.env.RPC_URL as string), serverUrl: fileServerUrl ? fileServerUrl : (process.env.SERVER_URL as string), @@ -440,4 +443,4 @@ export async function runRestAgent(restConfig: AriesRestConfig) { app.listen(adminPort, () => { logger.info(`Successfully started server on port ${adminPort}`) }) -} \ No newline at end of file +} diff --git a/src/controllers/agent/AgentController.ts b/src/controllers/agent/AgentController.ts index e06053bc..aad7d02b 100644 --- a/src/controllers/agent/AgentController.ts +++ b/src/controllers/agent/AgentController.ts @@ -49,4 +49,4 @@ export class AgentController extends Controller { throw ErrorHandlingService.handle(error) } } -} \ No newline at end of file +} diff --git a/src/controllers/basic-messages/BasicMessageController.ts b/src/controllers/basic-messages/BasicMessageController.ts index 1d97353c..c4b9cbd1 100644 --- a/src/controllers/basic-messages/BasicMessageController.ts +++ b/src/controllers/basic-messages/BasicMessageController.ts @@ -56,4 +56,4 @@ export class BasicMessageController extends Controller { throw ErrorHandlingService.handle(error) } } -} \ No newline at end of file +} diff --git a/src/controllers/connections/ConnectionController.ts b/src/controllers/connections/ConnectionController.ts index 247d0754..eeae789b 100644 --- a/src/controllers/connections/ConnectionController.ts +++ b/src/controllers/connections/ConnectionController.ts @@ -149,4 +149,4 @@ export class ConnectionController extends Controller { throw ErrorHandlingService.handle(error) } } -} \ No newline at end of file +} diff --git a/src/controllers/endorser-transaction/EndorserTransactionController.ts b/src/controllers/endorser-transaction/EndorserTransactionController.ts index 0d935258..6bbdfade 100644 --- a/src/controllers/endorser-transaction/EndorserTransactionController.ts +++ b/src/controllers/endorser-transaction/EndorserTransactionController.ts @@ -188,4 +188,4 @@ export class EndorserTransactionController extends Controller { } return credentialDefinitionState } -} \ No newline at end of file +} diff --git a/src/controllers/examples.ts b/src/controllers/examples.ts index db9507bc..7a125b4c 100644 --- a/src/controllers/examples.ts +++ b/src/controllers/examples.ts @@ -301,4 +301,4 @@ export const CredentialDefinitionExample = { y: 'string', }, }, -} \ No newline at end of file +} diff --git a/src/controllers/outofband/OutOfBandController.ts b/src/controllers/outofband/OutOfBandController.ts index 306ff3a7..4450bd92 100644 --- a/src/controllers/outofband/OutOfBandController.ts +++ b/src/controllers/outofband/OutOfBandController.ts @@ -321,4 +321,4 @@ export class OutOfBandController extends Controller { throw ErrorHandlingService.handle(error) } } -} \ No newline at end of file +} diff --git a/src/controllers/polygon/PolygonController.ts b/src/controllers/polygon/PolygonController.ts index 9f9abf26..c028ab4d 100644 --- a/src/controllers/polygon/PolygonController.ts +++ b/src/controllers/polygon/PolygonController.ts @@ -141,4 +141,4 @@ export class Polygon extends Controller { throw ErrorHandlingService.handle(error) } } -} \ No newline at end of file +} diff --git a/src/controllers/question-answer/QuestionAnswerController.ts b/src/controllers/question-answer/QuestionAnswerController.ts index 0cef175c..e4ae9881 100644 --- a/src/controllers/question-answer/QuestionAnswerController.ts +++ b/src/controllers/question-answer/QuestionAnswerController.ts @@ -117,4 +117,4 @@ export class QuestionAnswerController extends Controller { throw ErrorHandlingService.handle(error) } } -} \ No newline at end of file +} diff --git a/src/enums/enum.ts b/src/enums/enum.ts index 49f9e74f..6468e3af 100644 --- a/src/enums/enum.ts +++ b/src/enums/enum.ts @@ -70,4 +70,4 @@ export enum HttpStatusCode { export declare enum CustomHandshakeProtocol { DidExchange = 'https://didcomm.org/didexchange/1.1', Connections = 'https://didcomm.org/connections/1.0', -} \ No newline at end of file +} diff --git a/src/errorHandlingService.ts b/src/errorHandlingService.ts index 8c3651f3..5fa11a21 100644 --- a/src/errorHandlingService.ts +++ b/src/errorHandlingService.ts @@ -76,4 +76,4 @@ class ErrorHandlingService { } } -export default ErrorHandlingService \ No newline at end of file +export default ErrorHandlingService diff --git a/src/events/ReuseConnectionEvents.ts b/src/events/ReuseConnectionEvents.ts index aeb088b2..c4ee435f 100644 --- a/src/events/ReuseConnectionEvents.ts +++ b/src/events/ReuseConnectionEvents.ts @@ -31,4 +31,4 @@ export const reuseConnectionEvents = async (agent: Agent, config: ServerConfig) }) } }) -} \ No newline at end of file +} diff --git a/src/server.ts b/src/server.ts index e82eeaa9..e9a06f31 100644 --- a/src/server.ts +++ b/src/server.ts @@ -103,4 +103,4 @@ export const setupServer = async (agent: Agent, config: ServerConfig, apiKey?: s }) return app -} \ No newline at end of file +} diff --git a/src/utils/agent.ts b/src/utils/agent.ts index 9568b53c..b01aecf1 100644 --- a/src/utils/agent.ts +++ b/src/utils/agent.ts @@ -146,4 +146,4 @@ export const setupAgent = async ({ name, endpoints, port }: { name: string; endp await agent.initialize() return agent -} \ No newline at end of file +} From c6b0a64e18022ccd668570718cf3428caed9b5db Mon Sep 17 00:00:00 2001 From: pranalidhanavade Date: Thu, 6 Mar 2025 12:37:21 +0530 Subject: [PATCH 02/15] fix: resolved prettier errors * Resolve linting issues Signed-off-by: pranalidhanavade * Resolve prettier issues Signed-off-by: pranalidhanavade --------- Signed-off-by: pranalidhanavade Signed-off-by: KambleSahil3 Signed-off-by: Krishna Waske --- package.json | 2 +- samples/cliConfig.json | 2 +- scripts/taskdef/credo-ecs-taskdef.json | 115 +++++++++--------- scripts/taskdef/credo-fargate-taskdef.json | 135 ++++++++++----------- tsconfig.json | 2 +- 5 files changed, 121 insertions(+), 135 deletions(-) diff --git a/package.json b/package.json index 50e487f1..4c32c3e2 100644 --- a/package.json +++ b/package.json @@ -105,4 +105,4 @@ "engines": { "node": "18.19.0" } -} \ No newline at end of file +} diff --git a/samples/cliConfig.json b/samples/cliConfig.json index 7d2a40e1..b5ff24c9 100644 --- a/samples/cliConfig.json +++ b/samples/cliConfig.json @@ -43,4 +43,4 @@ "rpcUrl": "https://rpc-amoy.polygon.technology", "fileServerUrl": "https://schema.credebl.id", "fileServerToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJBeWFuV29ya3MiLCJpZCI6ImNhZDI3ZjhjLTMyNWYtNDRmZC04ZmZkLWExNGNhZTY3NTMyMSJ9.I3IR7abjWbfStnxzn1BhxhV0OEzt1x3mULjDdUcgWHk" -} \ No newline at end of file +} diff --git a/scripts/taskdef/credo-ecs-taskdef.json b/scripts/taskdef/credo-ecs-taskdef.json index 8ae58ee9..c584194e 100644 --- a/scripts/taskdef/credo-ecs-taskdef.json +++ b/scripts/taskdef/credo-ecs-taskdef.json @@ -1,66 +1,59 @@ { - "family": "${FAMILY}", - "containerDefinitions": [ + "family": "${FAMILY}", + "containerDefinitions": [ + { + "name": "Platform-admin", + "image": "%REPOSITORY_URI%:CREDO_v_%BUILD_NUMBER%", + "cpu": 154, + "memory": 307, + "portMappings": [ { - "name": "Platform-admin", - "image": "%REPOSITORY_URI%:CREDO_v_%BUILD_NUMBER%", - "cpu": 154, - "memory": 307, - "portMappings": [ - { - "containerPort": 8001, - "hostPort": 8001, - "protocol": "tcp" - }, - { - "containerPort": 9001, - "hostPort": 9001, - "protocol": "tcp" - } - ], - "essential": true, - "command": [ - "--auto-accept-connections", - "--config", - "/config.json" - ], - "environment": [ - { - "name": "AFJ_REST_LOG_LEVEL", - "value": "1" - } - ], - "environmentFiles": [ - { - "value": "${S3_ARN}", - "type": "s3" - } - ], - "mountPoints": [ - { - "sourceVolume": "config", - "containerPath": "/config.json", - "readOnly": true - } - ], - "volumesFrom": [], - "ulimits": [] + "containerPort": 8001, + "hostPort": 8001, + "protocol": "tcp" + }, + { + "containerPort": 9001, + "hostPort": 9001, + "protocol": "tcp" + } + ], + "essential": true, + "command": ["--auto-accept-connections", "--config", "/config.json"], + "environment": [ + { + "name": "AFJ_REST_LOG_LEVEL", + "value": "1" + } + ], + "environmentFiles": [ + { + "value": "${S3_ARN}", + "type": "s3" } - - ], - "executionRoleArn": "arn:aws:iam::${ACCOUNT_ID}:role/ecsTaskExecutionRole", - "placementConstraints": [], - "requiresCompatibilities": [ - "EC2" - ], - "cpu": "154", - "memory": "307", - "volumes": [ + ], + "mountPoints": [ { - "name": "config", - "host": { - "sourcePath": "${SourcePath}" - } + "sourceVolume": "config", + "containerPath": "/config.json", + "readOnly": true } - ] -} \ No newline at end of file + ], + "volumesFrom": [], + "ulimits": [] + } + ], + "executionRoleArn": "arn:aws:iam::${ACCOUNT_ID}:role/ecsTaskExecutionRole", + "placementConstraints": [], + "requiresCompatibilities": ["EC2"], + "cpu": "154", + "memory": "307", + "volumes": [ + { + "name": "config", + "host": { + "sourcePath": "${SourcePath}" + } + } + ] +} diff --git a/scripts/taskdef/credo-fargate-taskdef.json b/scripts/taskdef/credo-fargate-taskdef.json index b799ef14..8e218216 100644 --- a/scripts/taskdef/credo-fargate-taskdef.json +++ b/scripts/taskdef/credo-fargate-taskdef.json @@ -1,76 +1,69 @@ { - "family": "${FAMILY}", - "containerDefinitions": [ + "family": "${FAMILY}", + "containerDefinitions": [ + { + "name": "Platform-admin", + "image": "%REPOSITORY_URI%:CREDO_v_%BUILD_NUMBER%", + "cpu": 0, + "portMappings": [ { - "name": "Platform-admin", - "image": "%REPOSITORY_URI%:CREDO_v_%BUILD_NUMBER%", - "cpu": 0, - "portMappings": [ - { - "containerPort": 8004, - "hostPort": 8004, - "protocol": "tcp" - }, - { - "containerPort": 9004, - "hostPort": 9004, - "protocol": "tcp" - } - ], - "essential": true, - "command": [ - "--auto-accept-connections", - "--config", - "/config/${CONFIG_FILE}" - ], - "environment": [ - { - "name": "AFJ_REST_LOG_LEVEL", - "value": "1" - } - ], - "environmentFiles": [ - { - "value": "${S3_ARN}", - "type": "s3" - } - ], - "mountPoints": [ - { - "sourceVolume": "config", - "containerPath": "/config", - "readOnly": false - } - ], - "volumesFrom": [], - "ulimits": [], - "logConfiguration": { - "logDriver": "awslogs", - "options": { - "awslogs-group": "/ecs/${FAMILY}", - "awslogs-create-group": "true", - "awslogs-region": "ap-south-1", - "awslogs-stream-prefix": "ecs" - } - } + "containerPort": 8004, + "hostPort": 8004, + "protocol": "tcp" + }, + { + "containerPort": 9004, + "hostPort": 9004, + "protocol": "tcp" } - - ], - "executionRoleArn": "arn:aws:iam::${ACCOUNT_ID}:role/ecsTaskExecutionRole", - "networkMode": "awsvpc", - "placementConstraints": [], - "requiresCompatibilities": [ - "FARGATE" - ], - "cpu": "1024", - "memory": "2048", - "volumes": [ + ], + "essential": true, + "command": ["--auto-accept-connections", "--config", "/config/${CONFIG_FILE}"], + "environment": [ + { + "name": "AFJ_REST_LOG_LEVEL", + "value": "1" + } + ], + "environmentFiles": [ { - "name": "config", - "efsVolumeConfiguration": { - "fileSystemId": "${EFS}", - "rootDirectory": "/" - } + "value": "${S3_ARN}", + "type": "s3" } - ] -} \ No newline at end of file + ], + "mountPoints": [ + { + "sourceVolume": "config", + "containerPath": "/config", + "readOnly": false + } + ], + "volumesFrom": [], + "ulimits": [], + "logConfiguration": { + "logDriver": "awslogs", + "options": { + "awslogs-group": "/ecs/${FAMILY}", + "awslogs-create-group": "true", + "awslogs-region": "ap-south-1", + "awslogs-stream-prefix": "ecs" + } + } + } + ], + "executionRoleArn": "arn:aws:iam::${ACCOUNT_ID}:role/ecsTaskExecutionRole", + "networkMode": "awsvpc", + "placementConstraints": [], + "requiresCompatibilities": ["FARGATE"], + "cpu": "1024", + "memory": "2048", + "volumes": [ + { + "name": "config", + "efsVolumeConfiguration": { + "fileSystemId": "${EFS}", + "rootDirectory": "/" + } + } + ] +} diff --git a/tsconfig.json b/tsconfig.json index 58a0566c..49cb417d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,4 +15,4 @@ "types": ["jest", "node"] }, "exclude": ["node_modules", "build"] -} \ No newline at end of file +} From 9fe76701a2d6d9b0b9308e2e2b5c6ab7b000d95b Mon Sep 17 00:00:00 2001 From: pranalidhanavade Date: Thu, 6 Mar 2025 13:13:18 +0530 Subject: [PATCH 03/15] fix: resolved prettier errors in compass.yml file Signed-off-by: pranalidhanavade Signed-off-by: KambleSahil3 Signed-off-by: Krishna Waske --- compass.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compass.yml b/compass.yml index a5a3d724..db63bcaf 100644 --- a/compass.yml +++ b/compass.yml @@ -19,4 +19,4 @@ labels: - language:typescript - self-sovereign-identity - source:github -customFields: null \ No newline at end of file +customFields: null From 1a7b66a9df588bd3992cf19839f100f1d1ccb949 Mon Sep 17 00:00:00 2001 From: KambleSahil3 <157386770+KambleSahil3@users.noreply.github.com> Date: Thu, 13 Mar 2025 14:19:23 +0530 Subject: [PATCH 04/15] chore: Update Dockerfile (#254) Signed-off-by: sahil.kamble@ayanworks.com Signed-off-by: KambleSahil3 Signed-off-by: Sahil Kamble Signed-off-by: Krishna Waske --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 03459e0f..210d04ee 100644 --- a/Dockerfile +++ b/Dockerfile @@ -55,6 +55,7 @@ COPY package.json yarn.lock ./ COPY . . # Install dependencies +RUN rm -rf node_modules RUN yarn install --frozen-lockfile RUN yarn global add patch-package From 075f101b36a93025287d751161418ee4daffd8ac Mon Sep 17 00:00:00 2001 From: KambleSahil3 Date: Mon, 17 Mar 2025 12:35:14 +0530 Subject: [PATCH 05/15] chore: Update Dockerfile (#256) Signed-off-by: KambleSahil3 Signed-off-by: Sahil Kamble Signed-off-by: Krishna Waske From 1eb96e4d40580f5f3dea87c5e5675fabf6fc8d93 Mon Sep 17 00:00:00 2001 From: Sahil Kamble Date: Thu, 27 Mar 2025 13:19:41 +0530 Subject: [PATCH 06/15] feat: push docker image (#257) * feat: added yml file to push docker images to github Signed-off-by: KambleSahil3 * feat: added yml file to push docker images to github Signed-off-by: KambleSahil3 * fix: updated cicd.yml file Signed-off-by: KambleSahil3 * fix: renamed yml file Signed-off-by: KambleSahil3 --------- Signed-off-by: KambleSahil3 Signed-off-by: Sahil Kamble Signed-off-by: Krishna Waske --- .github/workflows/continuous-delivery.yml | 47 +++++++++++++++++++++++ Dockerfile | 47 +---------------------- 2 files changed, 48 insertions(+), 46 deletions(-) create mode 100644 .github/workflows/continuous-delivery.yml diff --git a/.github/workflows/continuous-delivery.yml b/.github/workflows/continuous-delivery.yml new file mode 100644 index 00000000..20405081 --- /dev/null +++ b/.github/workflows/continuous-delivery.yml @@ -0,0 +1,47 @@ +name: Credo-Controller + +on: + push: + tags: + - 'v*' + +env: + REGISTRY: ghcr.io + SERVICE: credo-controller + +jobs: + build-and-push: + name: Push Docker image to GitHub + runs-on: ubuntu-latest + + permissions: + contents: read + packages: write + attestations: write + id-token: write + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Extract Git Tag + id: get_tag + run: echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and Push Docker Image ${{ env.SERVICE }} + uses: docker/build-push-action@v6 + with: + context: . + file: Dockerfile + push: true + tags: | + ${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.SERVICE }}:${{ env.TAG }} + ${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.SERVICE }}:latest + \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 210d04ee..c8175271 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,48 +1,3 @@ -# FROM ubuntu:20.04 - -# ENV DEBIAN_FRONTEND noninteractive - -# RUN apt-get update -y && apt-get install -y \ -# software-properties-common \ -# apt-transport-https \ -# curl \ -# # Only needed to build indy-sdk -# build-essential - -# RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - - -# # yarn -# RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ -# echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list - -# # install depdencies -# RUN apt-get update -y && apt-get install -y --allow-unauthenticated \ -# nodejs - -# # install depdencies -# RUN apt-get update -y && apt-get install -y --allow-unauthenticated \ -# nodejs - -# # Install yarn seperately due to `no-install-recommends` to skip nodejs install -# RUN apt-get install -y --no-install-recommends yarn - -# RUN yarn global add patch-package -# # AFJ specifc setup -# WORKDIR /www - -# COPY bin ./bin -# COPY package.json ./package.json -# COPY patches ./patches - -# RUN yarn install --production - -# COPY build ./build -# # COPY libindy_vdr.so /usr/lib/ -# # COPY libindy_vdr.so /usr/local/lib/ - -# ENTRYPOINT [ "./bin/afj-rest.js", "start" ] - - # Stage 1: Builder stage FROM node:18.19.0 AS builder @@ -76,4 +31,4 @@ COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/patches ./patches # Set entry point -ENTRYPOINT ["node", "./bin/afj-rest.js", "start"] \ No newline at end of file +ENTRYPOINT ["node", "./bin/afj-rest.js", "start"] From 8cfa466c0ebcca2edad95ec0cace9da86cbc0e0a Mon Sep 17 00:00:00 2001 From: Sahil Kamble Date: Thu, 27 Mar 2025 15:28:42 +0530 Subject: [PATCH 07/15] feat/push-docker-image (#258) * feat: added yml file to push docker images to github Signed-off-by: KambleSahil3 * feat: added yml file to push docker images to github Signed-off-by: KambleSahil3 * fix: updated cicd.yml file Signed-off-by: KambleSahil3 * fix: renamed yml file Signed-off-by: KambleSahil3 * chore: removed id-token and attestations Signed-off-by: KambleSahil3 * chore: removed id-token and attestations Signed-off-by: KambleSahil3 --------- Signed-off-by: KambleSahil3 Signed-off-by: Sahil Kamble Signed-off-by: Krishna Waske --- .github/workflows/continuous-delivery.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/continuous-delivery.yml b/.github/workflows/continuous-delivery.yml index 20405081..f8e6623b 100644 --- a/.github/workflows/continuous-delivery.yml +++ b/.github/workflows/continuous-delivery.yml @@ -1,4 +1,4 @@ -name: Credo-Controller +name: Continous Delivery on: push: @@ -17,8 +17,6 @@ jobs: permissions: contents: read packages: write - attestations: write - id-token: write steps: - name: Checkout Repository From 9b74e01dc8b7b1a91aa0dcf8e1a751c1ccae82df Mon Sep 17 00:00:00 2001 From: Tipu_Singh Date: Mon, 31 Mar 2025 09:48:33 +0530 Subject: [PATCH 08/15] feat:w3c-revocation Signed-off-by: Tipu_Singh Signed-off-by: Sahil Kamble Signed-off-by: Krishna Waske --- package.json | 8 +- src/constants.ts | 1 + .../credentials/CredentialController.ts | 145 +++++++++ .../multi-tenancy/MultiTenancyController.ts | 157 ++++++++- src/enums/enum.ts | 20 ++ src/routes/routes.ts | 187 ++++++++++- src/routes/swagger.json | 301 +++++++++++++++--- yarn.lock | 24 +- 8 files changed, 786 insertions(+), 57 deletions(-) create mode 100644 src/constants.ts diff --git a/package.json b/package.json index 4c32c3e2..a0422ddf 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "@types/node-fetch": "^2.6.4", "@types/ref-struct-di": "^1.1.9", "@types/ws": "^8.5.4", + "@types/uuid": "^8.3.3", "axios": "^1.4.0", "body-parser": "^1.20.0", "cors": "^2.8.5", @@ -64,6 +65,7 @@ "joi": "^17.12.3", "jsonwebtoken": "^9.0.2", "node-fetch": "^2.6.7", + "pako": "^2.1.0", "patch-package": "^8.0.0", "postinstall-postinstall": "^2.1.0", "reflect-metadata": "^0.1.13", @@ -71,7 +73,9 @@ "tslog": "^3.3.3", "tsoa": "^6.0.1", "tsyringe": "^4.8.0", - "yargs": "^17.3.1" + "uuidv4": "^6.2.13", + "yargs": "^17.3.1", + "zlib": "^1.0.5" }, "devDependencies": { "@types/body-parser": "^1.19.2", @@ -82,11 +86,11 @@ "@types/jsonwebtoken": "^9.0.5", "@types/multer": "^1.4.7", "@types/node": "^18.18.8", + "@types/pako": "^2.0.3", "@types/ref-array-di": "^1.2.8", "@types/ref-struct-di": "^1.1.9", "@types/supertest": "^2.0.12", "@types/swagger-ui-express": "^4.1.3", - "@types/uuid": "^8.3.4", "@typescript-eslint/eslint-plugin": "^6.19.1", "@typescript-eslint/parser": "^6.19.1", "eslint": "^7.32.0", diff --git a/src/constants.ts b/src/constants.ts new file mode 100644 index 00000000..e7b4b011 --- /dev/null +++ b/src/constants.ts @@ -0,0 +1 @@ +export const initialBitsEncoded = `uH4sIAAAAAAAAA-3BMQEAAADCoPVPbQwfoAAAAAAAAAAAAAAAAAAAAIC3AYbSVKsAQAAA` diff --git a/src/controllers/credentials/CredentialController.ts b/src/controllers/credentials/CredentialController.ts index 41fb3c1d..f21bb484 100644 --- a/src/controllers/credentials/CredentialController.ts +++ b/src/controllers/credentials/CredentialController.ts @@ -13,8 +13,11 @@ import { CredentialRole, createPeerDidDocumentFromServices, PeerDidNumAlgo, + ClaimFormat, } from '@credo-ts/core' +import axios from 'axios' import { injectable } from 'tsyringe' +import { v4 as uuidv4 } from 'uuid' import ErrorHandlingService from '../../errorHandlingService' import { CredentialExchangeRecordExample, RecordId } from '../examples' @@ -30,6 +33,15 @@ import { ThreadId, } from '../types' +import { initialBitsEncoded } from 'src/constants' +import { + CredentialContext, + CredentialStatusListType, + CredentialType, + RevocationListType, + SignatureType, +} from 'src/enums/enum' +import { BadRequestError, InternalServerError } from 'src/errors' import { Body, Controller, Get, Path, Post, Route, Tags, Example, Query, Security } from 'tsoa' @Tags('Credentials') @@ -314,4 +326,137 @@ export class CredentialController extends Controller { throw ErrorHandlingService.handle(error) } } + + /** + * Create bitstring status list credential + * + * @param tenantId Id of the tenant + * @param request BSLC required details + */ + @Security('apiKey') + @Post('/create-bslc') + public async createBitstringStatusListCredential( + @Path('tenantId') tenantId: string, + @Body() request: { issuerDID: string; statusPurpose: string; verificationMethod: string } + ) { + try { + const { issuerDID, statusPurpose, verificationMethod } = request + const bslcId = uuidv4() + const credentialpayload = { + '@context': [`${CredentialContext.V1}`, `${CredentialContext.V2}`], + id: `${process.env.BSLC_SERVER_URL}/bitstring/${bslcId}`, + type: [`${CredentialType.VerifiableCredential}`, `${CredentialType.BitstringStatusListCredential}`], + issuer: { + id: issuerDID as string, + }, + issuanceDate: new Date().toISOString(), + credentialSubject: { + id: `${process.env.BSLC_SERVER_URL}/bitstring/${bslcId}`, + type: `${RevocationListType.Bitstring}`, + statusPurpose: statusPurpose, + encodedList: initialBitsEncoded, + }, + credentialStatus: { + id: `${process.env.BSLC_SERVER_URL}/bitstring/${bslcId}`, + type: CredentialStatusListType.CredentialStatusList2017, + }, + } + + let signedCredential + // Step 2: Sign the payload + try { + //TODO: Add correct type here + signedCredential = await this.agent.w3cCredentials.signCredential({ + credential: credentialpayload, + format: ClaimFormat.LdpVc, + proofType: SignatureType.Ed25519Signature2018, + verificationMethod, + }) + } catch (signingError) { + throw new InternalServerError(`Failed to sign the BitstringStatusListCredential: ${signingError}`) + } + // Step 3: Upload the signed payload to the server + const serverUrl = process.env.BSLC_SERVER_URL + if (!serverUrl) { + throw new Error('BSLC_SERVER_URL is not defined in the environment variables') + } + + const token = process.env.BSLC_SERVER_TOKEN + if (!token) { + throw new Error('BSLC_SERVER_TOKEN is not defined in the environment variables') + } + const url = `${serverUrl}/bitstring` + const bslcPayload = { + id: bslcId, + bslcObject: signedCredential, + } + try { + const response = await axios.post(url, bslcPayload, { + headers: { + Accept: '*/*', + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', + }, + }) + + if (response.status !== 200) { + throw new Error('Failed to upload the signed BitstringStatusListCredential') + } + } catch (error) { + throw new InternalServerError(`Error uploading the BitstringStatusListCredential: ${error}`) + } + return signedCredential + } catch (error) { + throw ErrorHandlingService.handle(error) + } + } + + @Security('apiKey') + @Post('/get-empty-index/:BSLCUrl') + public async getEmptyIndexForBSLC(@Path('BSLCUrl') BSLCUrl: string) { + try { + if (!BSLCUrl) { + throw new BadRequestError('BSLCUrl is required') + } + + const response = await axios.get(BSLCUrl) + if (response.status !== 200) { + throw new Error('Failed to fetch the BitstringStatusListCredential') + } + + const credential = response.data + const encodedList = credential?.credentialSubject?.claims.encodedList + if (!encodedList) { + throw new Error('Encoded list not found in the credential') + } + + let bitstring + try { + const compressedData = Buffer.from(encodedList, 'base64').toString('binary') + bitstring = Array.from(compressedData) + .map((byte) => byte.padStart(8, '0')) + .join('') + } catch (error) { + throw new Error('Failed to decompress and process the encoded list') + } + + const unusedIndexes = [] + for (let i = 0; i < bitstring.length; i++) { + if (bitstring[i] === '0') { + unusedIndexes.push(i) + } + } + //TODO: add logic to filter from used indexs, for now returning random index with bit status as 0. + if (unusedIndexes.length === 0) { + throw new Error('No unused index found in the BitstringStatusList') + } + + const randomIndex = unusedIndexes[Math.floor(Math.random() * unusedIndexes.length)] + return { + index: randomIndex, + } + } catch (error) { + throw ErrorHandlingService.handle(error) + } + } } diff --git a/src/controllers/multi-tenancy/MultiTenancyController.ts b/src/controllers/multi-tenancy/MultiTenancyController.ts index a885fb96..ef40de97 100644 --- a/src/controllers/multi-tenancy/MultiTenancyController.ts +++ b/src/controllers/multi-tenancy/MultiTenancyController.ts @@ -1,3 +1,4 @@ +/* eslint-disable prettier/prettier */ import type { RestAgentModules, RestMultiTenantAgentModules } from '../../cliAgent' import type { Version } from '../examples' import type { RecipientKeyOption, SchemaMetadata } from '../types' @@ -44,12 +45,30 @@ import { injectable, createPeerDidDocumentFromServices, PeerDidNumAlgo, + ClaimFormat, } from '@credo-ts/core' import { QuestionAnswerRole, QuestionAnswerState } from '@credo-ts/question-answer' import axios from 'axios' import * as fs from 'fs' +import { v4 as uuidv4 } from 'uuid' +// import * as zlib from 'zlib' +// import { inflate } from 'pako' -import { CredentialEnum, DidMethod, EndorserMode, Network, NetworkTypes, Role, SchemaError } from '../../enums/enum' +import { initialBitsEncoded } from '../../constants' +import { + CredentialContext, + CredentialEnum, + CredentialStatusListType, + CredentialType, + DidMethod, + EndorserMode, + Network, + NetworkTypes, + RevocationListType, + Role, + SchemaError, + SignatureType, +} from '../../enums/enum' import ErrorHandlingService from '../../errorHandlingService' import { ENDORSER_DID_NOT_PRESENT } from '../../errorMessages' import { @@ -1904,4 +1923,140 @@ export class MultiTenancyController extends Controller { throw ErrorHandlingService.handle(error) } } + + /** + * Create bitstring status list credential + * + * @param tenantId Id of the tenant + * @param request BSLC required details + */ + @Security('apiKey') + @Post('/create-bslc/:tenantId') + public async createBitstringStatusListCredential( + @Path('tenantId') tenantId: string, + @Body() request: { issuerDID: string; statusPurpose: string, verificationMethod:string } + ) { + try { + const { issuerDID, statusPurpose, verificationMethod } = request + const bslcId = uuidv4() + const credentialpayload = { + '@context': [`${CredentialContext.V1}`, `${CredentialContext.V2}`], + id: `${process.env.BSLC_SERVER_URL}/bitstring/${bslcId}`, + type: [`${CredentialType.VerifiableCredential}`, `${CredentialType.BitstringStatusListCredential}`], + issuer: { + id: issuerDID as string, + }, + issuanceDate: new Date().toISOString(), + credentialSubject: { + id: `${process.env.BSLC_SERVER_URL}/bitstring/${bslcId}`, + type: `${RevocationListType.Bitstring}`, + statusPurpose: statusPurpose, + encodedList: initialBitsEncoded, + }, + credentialStatus: { + id: `${process.env.BSLC_SERVER_URL}/bitstring/${bslcId}`, + type: CredentialStatusListType.CredentialStatusList2017, + }, + } + + let signedCredential + + await this.agent.modules.tenants.withTenantAgent({ tenantId }, async (tenantAgent) => { + // Step 2: Sign the payload + try { + //TODO: Add correct type here + signedCredential = await tenantAgent.w3cCredentials.signCredential({ + credential: credentialpayload, + format: ClaimFormat.LdpVc, + proofType: SignatureType.Ed25519Signature2018, + verificationMethod, + }) + } catch (signingError) { + throw new InternalServerError(`Failed to sign the BitstringStatusListCredential: ${signingError}`) + } + }) + // Step 3: Upload the signed payload to the server + const serverUrl = process.env.BSLC_SERVER_URL + if (!serverUrl) { + throw new Error('BSLC_SERVER_URL is not defined in the environment variables') + } + + const token = process.env.BSLC_SERVER_TOKEN + if (!token) { + throw new Error('BSLC_SERVER_TOKEN is not defined in the environment variables') + } + const url = `${serverUrl}/bitstring` + const bslcPayload = { + id: bslcId, + bslcObject: signedCredential, + } + try { + const response = await axios.post(url, bslcPayload, { + headers: { + Accept: '*/*', + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', + }, + }) + + if (response.status !== 200) { + throw new Error('Failed to upload the signed BitstringStatusListCredential') + } + } catch (error) { + throw new InternalServerError(`Error uploading the BitstringStatusListCredential: ${error}`) + } + return signedCredential + } catch (error) { + throw ErrorHandlingService.handle(error) + } + } + + @Security('apiKey') + @Post('/get-empty-index/:BSLCUrl') + public async getEmptyIndexForBSLC(@Path('BSLCUrl') BSLCUrl: string) { + try { + if (!BSLCUrl) { + throw new BadRequestError('BSLCUrl is required') + } + + const response = await axios.get(BSLCUrl) + if (response.status !== 200) { + throw new Error('Failed to fetch the BitstringStatusListCredential') + } + + const credential = response.data + const encodedList = credential?.credentialSubject?.claims.encodedList + if (!encodedList) { + throw new Error('Encoded list not found in the credential') + } + + let bitstring + try { + const compressedData = Buffer.from(encodedList, 'base64').toString('binary') + bitstring = Array.from(compressedData) + .map((byte) => byte.padStart(8, '0')) + .join('') + } catch (error) { + throw new Error('Failed to decompress and process the encoded list') + } + + const unusedIndexes = [] + for (let i = 0; i < bitstring.length; i++) { + if (bitstring[i] === '0') { + unusedIndexes.push(i) + } + } + //TODO: add logic to filter from used indexs, for now returning random index with bit status as 0. + if (unusedIndexes.length === 0) { + throw new Error('No unused index found in the BitstringStatusList') + } + + const randomIndex = unusedIndexes[Math.floor(Math.random() * unusedIndexes.length)] + return { + index: randomIndex, + } + } catch (error) { + throw ErrorHandlingService.handle(error) + } + } } diff --git a/src/enums/enum.ts b/src/enums/enum.ts index 6468e3af..4d1f8f18 100644 --- a/src/enums/enum.ts +++ b/src/enums/enum.ts @@ -71,3 +71,23 @@ export declare enum CustomHandshakeProtocol { DidExchange = 'https://didcomm.org/didexchange/1.1', Connections = 'https://didcomm.org/connections/1.0', } + +export enum CredentialContext { + V1 = 'https://www.w3.org/2018/credentials/v1', + V2 = 'https://www.w3.org/ns/credentials/v2', +} + +export enum CredentialType { + VerifiableCredential = 'VerifiableCredential', + BitstringStatusListCredential = 'BitstringStatusListCredential', +} +export enum RevocationListType { + Bitstring = 'BitstringStatusList', +} + +export enum CredentialStatusListType { + CredentialStatusList2017 = 'CredentialStatusList2017', +} +export enum SignatureType { + Ed25519Signature2018 = 'Ed25519Signature2018', +} diff --git a/src/routes/routes.ts b/src/routes/routes.ts index 0ffd1f1c..75c49301 100644 --- a/src/routes/routes.ts +++ b/src/routes/routes.ts @@ -418,7 +418,7 @@ const models: TsoaRoute.Models = { "DidCreate": { "dataType": "refObject", "properties": { - "keyType": {"ref":"KeyType","required":true}, + "keyType": {"ref":"KeyType"}, "seed": {"dataType":"string"}, "domain": {"dataType":"string"}, "method": {"dataType":"string","required":true}, @@ -585,6 +585,7 @@ const models: TsoaRoute.Models = { "issuanceDate": {"dataType":"string","required":true}, "expirationDate": {"dataType":"string"}, "credentialSubject": {"ref":"SingleOrArray_JsonObject_","required":true}, + "prettyVc": {"dataType":"any"}, }, "additionalProperties": {"dataType":"any"}, }, @@ -1128,6 +1129,31 @@ const models: TsoaRoute.Models = { "additionalProperties": false, }, // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "CredentialFormatDataMessagePayload__40_LegacyIndyCredentialFormat-or-JsonLdCredentialFormat-or-AnonCredsCredentialFormat_41_-Array.proposal_": { + "dataType": "refAlias", + "type": {"dataType":"nestedObjectLiteral","nestedProperties":{},"validators":{}}, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "CredentialFormatDataMessagePayload__40_LegacyIndyCredentialFormat-or-JsonLdCredentialFormat-or-AnonCredsCredentialFormat_41_-Array.offer_": { + "dataType": "refAlias", + "type": {"dataType":"nestedObjectLiteral","nestedProperties":{},"validators":{}}, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "CredentialFormatDataMessagePayload__40_LegacyIndyCredentialFormat-or-JsonLdCredentialFormat-or-AnonCredsCredentialFormat_41_-Array.request_": { + "dataType": "refAlias", + "type": {"dataType":"nestedObjectLiteral","nestedProperties":{},"validators":{}}, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "CredentialFormatDataMessagePayload__40_LegacyIndyCredentialFormat-or-JsonLdCredentialFormat-or-AnonCredsCredentialFormat_41_-Array.credential_": { + "dataType": "refAlias", + "type": {"dataType":"nestedObjectLiteral","nestedProperties":{},"validators":{}}, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "GetCredentialFormatDataReturn__40_LegacyIndyCredentialFormat-or-JsonLdCredentialFormat-or-AnonCredsCredentialFormat_41_-Array_": { + "dataType": "refAlias", + "type": {"dataType":"nestedObjectLiteral","nestedProperties":{"credential":{"ref":"CredentialFormatDataMessagePayload__40_LegacyIndyCredentialFormat-or-JsonLdCredentialFormat-or-AnonCredsCredentialFormat_41_-Array.credential_"},"request":{"ref":"CredentialFormatDataMessagePayload__40_LegacyIndyCredentialFormat-or-JsonLdCredentialFormat-or-AnonCredsCredentialFormat_41_-Array.request_"},"offerAttributes":{"dataType":"array","array":{"dataType":"refObject","ref":"CredentialPreviewAttributeOptions"}},"offer":{"ref":"CredentialFormatDataMessagePayload__40_LegacyIndyCredentialFormat-or-JsonLdCredentialFormat-or-AnonCredsCredentialFormat_41_-Array.offer_"},"proposal":{"ref":"CredentialFormatDataMessagePayload__40_LegacyIndyCredentialFormat-or-JsonLdCredentialFormat-or-AnonCredsCredentialFormat_41_-Array.proposal_"},"proposalAttributes":{"dataType":"array","array":{"dataType":"refObject","ref":"CredentialPreviewAttributeOptions"}}},"validators":{}}, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa "BasicMessageRecord": { "dataType": "refAlias", "type": {"ref":"Record_string.unknown_","validators":{}}, @@ -1149,11 +1175,18 @@ const templateService = new ExpressTemplateService(models, {"noImplicitAdditiona // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + + + export function RegisterRoutes(app: Router) { + // ########################################################################################################### // NOTE: If you do not see routes for all of your controllers in this file, then you might not have informed tsoa of where to look // Please look into the "controllerPathGlobs" config option described in the readme: https://github.com/lukeautry/tsoa // ########################################################################################################### + + + app.get('/proofs', authenticateMiddleware([{"apiKey":[]}]), ...(fetchMiddlewares(ProofController)), @@ -2468,7 +2501,7 @@ export function RegisterRoutes(app: Router) { } }); // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.post('/multi-tenancy/polygon-wc3/schema/:tenantId', + app.post('/multi-tenancy/polygon-w3c/schema/:tenantId', authenticateMiddleware([{"apiKey":[]}]), ...(fetchMiddlewares(MultiTenancyController)), ...(fetchMiddlewares(MultiTenancyController.prototype.createPolygonW3CSchema)), @@ -2505,7 +2538,7 @@ export function RegisterRoutes(app: Router) { } }); // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.get('/multi-tenancy/polygon-wc3/schema/:did/:schemaId/:tenantId', + app.get('/multi-tenancy/polygon-w3c/schema/:did/:schemaId/:tenantId', authenticateMiddleware([{"apiKey":[]}]), ...(fetchMiddlewares(MultiTenancyController)), ...(fetchMiddlewares(MultiTenancyController.prototype.getPolygonW3CSchemaById)), @@ -2878,6 +2911,43 @@ export function RegisterRoutes(app: Router) { } }); // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + app.get('/multi-tenancy/credentials/form-data/:tenantId/:credentialRecordId', + authenticateMiddleware([{"apiKey":[]}]), + ...(fetchMiddlewares(MultiTenancyController)), + ...(fetchMiddlewares(MultiTenancyController.prototype.credentialFormData)), + + async function MultiTenancyController_credentialFormData(request: ExRequest, response: ExResponse, next: any) { + const args: Record = { + tenantId: {"in":"path","name":"tenantId","required":true,"dataType":"string"}, + credentialRecordId: {"in":"path","name":"credentialRecordId","required":true,"dataType":"string"}, + }; + + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + + let validatedArgs: any[] = []; + try { + validatedArgs = templateService.getValidatedArgs({ args, request, response }); + + const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; + + const controller: any = await container.get(MultiTenancyController); + if (typeof controller['setStatus'] === 'function') { + controller.setStatus(undefined); + } + + await templateService.apiHandler({ + methodName: 'credentialFormData', + controller, + response, + next, + validatedArgs, + successStatus: undefined, + }); + } catch (err) { + return next(err); + } + }); + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa app.get('/multi-tenancy/proofs/:tenantId', authenticateMiddleware([{"apiKey":[]}]), ...(fetchMiddlewares(MultiTenancyController)), @@ -3476,6 +3546,79 @@ export function RegisterRoutes(app: Router) { } }); // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + app.post('/multi-tenancy/create-bslc/:tenantId', + authenticateMiddleware([{"apiKey":[]}]), + ...(fetchMiddlewares(MultiTenancyController)), + ...(fetchMiddlewares(MultiTenancyController.prototype.createBitstringStatusListCredential)), + + async function MultiTenancyController_createBitstringStatusListCredential(request: ExRequest, response: ExResponse, next: any) { + const args: Record = { + tenantId: {"in":"path","name":"tenantId","required":true,"dataType":"string"}, + request: {"in":"body","name":"request","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"verificationMethod":{"dataType":"string","required":true},"statusPurpose":{"dataType":"string","required":true},"issuerDID":{"dataType":"string","required":true}}}, + }; + + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + + let validatedArgs: any[] = []; + try { + validatedArgs = templateService.getValidatedArgs({ args, request, response }); + + const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; + + const controller: any = await container.get(MultiTenancyController); + if (typeof controller['setStatus'] === 'function') { + controller.setStatus(undefined); + } + + await templateService.apiHandler({ + methodName: 'createBitstringStatusListCredential', + controller, + response, + next, + validatedArgs, + successStatus: undefined, + }); + } catch (err) { + return next(err); + } + }); + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + app.post('/multi-tenancy/get-empty-index/:BSLCUrl', + authenticateMiddleware([{"apiKey":[]}]), + ...(fetchMiddlewares(MultiTenancyController)), + ...(fetchMiddlewares(MultiTenancyController.prototype.getEmptyIndexForBSLC)), + + async function MultiTenancyController_getEmptyIndexForBSLC(request: ExRequest, response: ExResponse, next: any) { + const args: Record = { + BSLCUrl: {"in":"path","name":"BSLCUrl","required":true,"dataType":"string"}, + }; + + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + + let validatedArgs: any[] = []; + try { + validatedArgs = templateService.getValidatedArgs({ args, request, response }); + + const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; + + const controller: any = await container.get(MultiTenancyController); + if (typeof controller['setStatus'] === 'function') { + controller.setStatus(undefined); + } + + await templateService.apiHandler({ + methodName: 'getEmptyIndexForBSLC', + controller, + response, + next, + validatedArgs, + successStatus: undefined, + }); + } catch (err) { + return next(err); + } + }); + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa app.post('/transactions/endorse', authenticateMiddleware([{"apiKey":[]}]), ...(fetchMiddlewares(EndorserTransactionController)), @@ -4234,6 +4377,42 @@ export function RegisterRoutes(app: Router) { } }); // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + app.get('/credentials/:credentialRecordId/form-data', + authenticateMiddleware([{"apiKey":[]}]), + ...(fetchMiddlewares(CredentialController)), + ...(fetchMiddlewares(CredentialController.prototype.credentialFormData)), + + async function CredentialController_credentialFormData(request: ExRequest, response: ExResponse, next: any) { + const args: Record = { + credentialRecordId: {"in":"path","name":"credentialRecordId","required":true,"dataType":"string"}, + }; + + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + + let validatedArgs: any[] = []; + try { + validatedArgs = templateService.getValidatedArgs({ args, request, response }); + + const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; + + const controller: any = await container.get(CredentialController); + if (typeof controller['setStatus'] === 'function') { + controller.setStatus(undefined); + } + + await templateService.apiHandler({ + methodName: 'credentialFormData', + controller, + response, + next, + validatedArgs, + successStatus: undefined, + }); + } catch (err) { + return next(err); + } + }); + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa app.get('/connections', authenticateMiddleware([{"apiKey":[]}]), ...(fetchMiddlewares(ConnectionController)), @@ -4822,4 +5001,4 @@ export function RegisterRoutes(app: Router) { // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa } -// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa \ No newline at end of file +// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa diff --git a/src/routes/swagger.json b/src/routes/swagger.json index b2137d50..d4d005e5 100644 --- a/src/routes/swagger.json +++ b/src/routes/swagger.json @@ -941,7 +941,6 @@ } }, "required": [ - "keyType", "method" ], "type": "object", @@ -1379,7 +1378,8 @@ }, "credentialSubject": { "$ref": "#/components/schemas/SingleOrArray_JsonObject_" - } + }, + "prettyVc": {} }, "required": [ "@context", @@ -2585,6 +2585,56 @@ "type": "object", "additionalProperties": false }, + "CredentialFormatDataMessagePayload__40_LegacyIndyCredentialFormat-or-JsonLdCredentialFormat-or-AnonCredsCredentialFormat_41_-Array.proposal_": { + "properties": {}, + "type": "object", + "description": "Get the format data payload for a specific message from a list of CredentialFormat interfaces and a message\n\nFor an indy offer, this resolves to the cred abstract format as defined here:\nhttps://github.com/hyperledger/aries-rfcs/tree/b3a3942ef052039e73cd23d847f42947f8287da2/features/0592-indy-attachments#cred-abstract-format" + }, + "CredentialFormatDataMessagePayload__40_LegacyIndyCredentialFormat-or-JsonLdCredentialFormat-or-AnonCredsCredentialFormat_41_-Array.offer_": { + "properties": {}, + "type": "object", + "description": "Get the format data payload for a specific message from a list of CredentialFormat interfaces and a message\n\nFor an indy offer, this resolves to the cred abstract format as defined here:\nhttps://github.com/hyperledger/aries-rfcs/tree/b3a3942ef052039e73cd23d847f42947f8287da2/features/0592-indy-attachments#cred-abstract-format" + }, + "CredentialFormatDataMessagePayload__40_LegacyIndyCredentialFormat-or-JsonLdCredentialFormat-or-AnonCredsCredentialFormat_41_-Array.request_": { + "properties": {}, + "type": "object", + "description": "Get the format data payload for a specific message from a list of CredentialFormat interfaces and a message\n\nFor an indy offer, this resolves to the cred abstract format as defined here:\nhttps://github.com/hyperledger/aries-rfcs/tree/b3a3942ef052039e73cd23d847f42947f8287da2/features/0592-indy-attachments#cred-abstract-format" + }, + "CredentialFormatDataMessagePayload__40_LegacyIndyCredentialFormat-or-JsonLdCredentialFormat-or-AnonCredsCredentialFormat_41_-Array.credential_": { + "properties": {}, + "type": "object", + "description": "Get the format data payload for a specific message from a list of CredentialFormat interfaces and a message\n\nFor an indy offer, this resolves to the cred abstract format as defined here:\nhttps://github.com/hyperledger/aries-rfcs/tree/b3a3942ef052039e73cd23d847f42947f8287da2/features/0592-indy-attachments#cred-abstract-format" + }, + "GetCredentialFormatDataReturn__40_LegacyIndyCredentialFormat-or-JsonLdCredentialFormat-or-AnonCredsCredentialFormat_41_-Array_": { + "properties": { + "credential": { + "$ref": "#/components/schemas/CredentialFormatDataMessagePayload__40_LegacyIndyCredentialFormat-or-JsonLdCredentialFormat-or-AnonCredsCredentialFormat_41_-Array.credential_" + }, + "request": { + "$ref": "#/components/schemas/CredentialFormatDataMessagePayload__40_LegacyIndyCredentialFormat-or-JsonLdCredentialFormat-or-AnonCredsCredentialFormat_41_-Array.request_" + }, + "offerAttributes": { + "items": { + "$ref": "#/components/schemas/CredentialPreviewAttributeOptions" + }, + "type": "array" + }, + "offer": { + "$ref": "#/components/schemas/CredentialFormatDataMessagePayload__40_LegacyIndyCredentialFormat-or-JsonLdCredentialFormat-or-AnonCredsCredentialFormat_41_-Array.offer_" + }, + "proposal": { + "$ref": "#/components/schemas/CredentialFormatDataMessagePayload__40_LegacyIndyCredentialFormat-or-JsonLdCredentialFormat-or-AnonCredsCredentialFormat_41_-Array.proposal_" + }, + "proposalAttributes": { + "items": { + "$ref": "#/components/schemas/CredentialPreviewAttributeOptions" + }, + "type": "array" + } + }, + "type": "object", + "description": "Get format data return value. Each key holds a mapping of credential format key to format data." + }, "BasicMessageRecord": { "$ref": "#/components/schemas/Record_string.unknown_" }, @@ -2624,7 +2674,7 @@ }, "info": { "title": "credo-controller", - "version": "0.9.4", + "version": "2.0.0", "description": "Rest endpoint wrapper for using your agent over HTTP", "license": { "name": "Apache-2.0" @@ -2890,26 +2940,11 @@ "application/json": { "schema": { "properties": { - "recipientKey": { - "anyOf": [ - { - "properties": { - "recipientKey": {} - }, - "type": "object" - }, - { - "properties": { - "recipientKey": { - "type": "string" - } - }, - "required": [ - "recipientKey" - ], - "type": "object" - } - ] + "proofRecordThId": { + "type": "string" + }, + "invitationDid": { + "type": "string" }, "outOfBandRecord": { "$ref": "#/components/schemas/Record_string.unknown_" @@ -2922,7 +2957,8 @@ } }, "required": [ - "recipientKey", + "proofRecordThId", + "invitationDid", "outOfBandRecord", "invitation", "invitationUrl" @@ -4860,7 +4896,7 @@ } } }, - "/multi-tenancy/polygon-wc3/schema/{tenantId}": { + "/multi-tenancy/polygon-w3c/schema/{tenantId}": { "post": { "operationId": "CreatePolygonW3CSchema", "responses": { @@ -4923,7 +4959,7 @@ } } }, - "/multi-tenancy/polygon-wc3/schema/{did}/{schemaId}/{tenantId}": { + "/multi-tenancy/polygon-w3c/schema/{did}/{schemaId}/{tenantId}": { "get": { "operationId": "GetPolygonW3CSchemaById", "responses": { @@ -5392,6 +5428,47 @@ ] } }, + "/multi-tenancy/credentials/form-data/{tenantId}/{credentialRecordId}": { + "get": { + "operationId": "CredentialFormData", + "responses": { + "200": { + "description": "Ok", + "content": { + "application/json": { + "schema": {} + } + } + } + }, + "tags": [ + "MultiTenancy" + ], + "security": [ + { + "apiKey": [] + } + ], + "parameters": [ + { + "in": "path", + "name": "tenantId", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "credentialRecordId", + "required": true, + "schema": { + "type": "string" + } + } + ] + } + }, "/multi-tenancy/proofs/{tenantId}": { "get": { "operationId": "GetAllProofs", @@ -6259,6 +6336,110 @@ } } }, + "/multi-tenancy/create-bslc/{tenantId}": { + "post": { + "operationId": "CreateBitstringStatusListCredential", + "responses": { + "200": { + "description": "Ok", + "content": { + "application/json": { + "schema": {} + } + } + } + }, + "description": "Create bitstring status list credential", + "tags": [ + "MultiTenancy" + ], + "security": [ + { + "apiKey": [] + } + ], + "parameters": [ + { + "description": "Id of the tenant", + "in": "path", + "name": "tenantId", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "BSLC required details", + "required": true, + "content": { + "application/json": { + "schema": { + "properties": { + "verificationMethod": { + "type": "string" + }, + "statusPurpose": { + "type": "string" + }, + "issuerDID": { + "type": "string" + } + }, + "required": [ + "verificationMethod", + "statusPurpose", + "issuerDID" + ], + "type": "object", + "description": "BSLC required details" + } + } + } + } + } + }, + "/multi-tenancy/get-empty-index/{BSLCUrl}": { + "post": { + "operationId": "GetEmptyIndexForBSLC", + "responses": { + "200": { + "description": "Ok", + "content": { + "application/json": { + "schema": { + "properties": { + "index": {} + }, + "required": [ + "index" + ], + "type": "object" + } + } + } + } + }, + "tags": [ + "MultiTenancy" + ], + "security": [ + { + "apiKey": [] + } + ], + "parameters": [ + { + "in": "path", + "name": "BSLCUrl", + "required": true, + "schema": { + "type": "string" + } + } + ] + } + }, "/transactions/endorse": { "post": { "operationId": "EndorserTransaction", @@ -7261,26 +7442,14 @@ "application/json": { "schema": { "properties": { - "recipientKey": { - "anyOf": [ - { - "properties": { - "recipientKey": {} - }, - "type": "object" - }, - { - "properties": { - "recipientKey": { - "type": "string" - } - }, - "required": [ - "recipientKey" - ], - "type": "object" - } - ] + "invitationDid": { + "type": "string" + }, + "credentialRequestThId": { + "type": "string" + }, + "outOfBandRecordId": { + "type": "string" }, "outOfBandRecord": { "$ref": "#/components/schemas/Record_string.unknown_" @@ -7293,7 +7462,9 @@ } }, "required": [ - "recipientKey", + "invitationDid", + "credentialRequestThId", + "outOfBandRecordId", "outOfBandRecord", "invitation", "invitationUrl" @@ -7508,6 +7679,42 @@ } } }, + "/credentials/{credentialRecordId}/form-data": { + "get": { + "operationId": "CredentialFormData", + "responses": { + "200": { + "description": "credentialRecord", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetCredentialFormatDataReturn__40_LegacyIndyCredentialFormat-or-JsonLdCredentialFormat-or-AnonCredsCredentialFormat_41_-Array_" + } + } + } + } + }, + "description": "Return credentialRecord", + "tags": [ + "Credentials" + ], + "security": [ + { + "apiKey": [] + } + ], + "parameters": [ + { + "in": "path", + "name": "credentialRecordId", + "required": true, + "schema": { + "type": "string" + } + } + ] + } + }, "/connections": { "get": { "operationId": "GetAllConnections", diff --git a/yarn.lock b/yarn.lock index c7958edd..ecea63bd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2259,6 +2259,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.66.tgz#dd035d409df322acc83dff62a602f12a5783bbb3" integrity sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw== +"@types/pako@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/pako/-/pako-2.0.3.tgz#b6993334f3af27c158f3fe0dfeeba987c578afb1" + integrity sha512-bq0hMV9opAcrmE0Byyo0fY3Ew4tgOevJmQ9grUhpXQhYfyLJ1Kqg3P33JT5fdbT2AjeAjR51zqqVjAL/HMkx7Q== + "@types/qs@*": version "6.9.15" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.15.tgz#adde8a060ec9c305a82de1babc1056e73bd64dce" @@ -2359,7 +2364,7 @@ "@types/express" "*" "@types/serve-static" "*" -"@types/uuid@^8.3.4": +"@types/uuid@8.3.4", "@types/uuid@^8.3.4": version "8.3.4" resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== @@ -6410,7 +6415,7 @@ package-json-from-dist@^1.0.0: resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00" integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw== -pako@^2.0.4: +pako@^2.0.4, pako@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/pako/-/pako-2.1.0.tgz#266cc37f98c7d883545d11335c00fbd4062c9a86" integrity sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug== @@ -7653,7 +7658,7 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== -"uuid@^7.0.0 || ^8.0.0": +uuid@8.3.2, "uuid@^7.0.0 || ^8.0.0": version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== @@ -7663,6 +7668,14 @@ uuid@^9.0.0, uuid@^9.0.1: resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== +uuidv4@^6.2.13: + version "6.2.13" + resolved "https://registry.yarnpkg.com/uuidv4/-/uuidv4-6.2.13.tgz#8f95ec5ef22d1f92c8e5d4c70b735d1c89572cb7" + integrity sha512-AXyzMjazYB3ovL3q051VLH06Ixj//Knx7QnUSi1T//Ie3io6CpsPu9nVMOx5MoLWh6xV0B9J0hIaxungxXUbPQ== + dependencies: + "@types/uuid" "8.3.4" + uuid "8.3.2" + v8-compile-cache-lib@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" @@ -7912,3 +7925,8 @@ yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zlib@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/zlib/-/zlib-1.0.5.tgz#6e7c972fc371c645a6afb03ab14769def114fcc0" + integrity sha512-40fpE2II+Cd3k8HWTWONfeKE2jL+P42iWJ1zzps5W51qcTsOUKM5Q5m2PFb0CLxlmFAaUuUdJGc3OfZy947v0w== From edeabf3ab6176ae73d79363d0afd8810560f2707 Mon Sep 17 00:00:00 2001 From: Tipu_Singh Date: Mon, 31 Mar 2025 13:09:31 +0530 Subject: [PATCH 09/15] refactor: removed revocation code Signed-off-by: Tipu_Singh Signed-off-by: Sahil Kamble Signed-off-by: Krishna Waske --- .../credentials/CredentialController.ts | 145 ----------------- .../multi-tenancy/MultiTenancyController.ts | 146 ------------------ src/routes/routes.ts | 73 --------- src/routes/swagger.json | 104 ------------- 4 files changed, 468 deletions(-) diff --git a/src/controllers/credentials/CredentialController.ts b/src/controllers/credentials/CredentialController.ts index f21bb484..41fb3c1d 100644 --- a/src/controllers/credentials/CredentialController.ts +++ b/src/controllers/credentials/CredentialController.ts @@ -13,11 +13,8 @@ import { CredentialRole, createPeerDidDocumentFromServices, PeerDidNumAlgo, - ClaimFormat, } from '@credo-ts/core' -import axios from 'axios' import { injectable } from 'tsyringe' -import { v4 as uuidv4 } from 'uuid' import ErrorHandlingService from '../../errorHandlingService' import { CredentialExchangeRecordExample, RecordId } from '../examples' @@ -33,15 +30,6 @@ import { ThreadId, } from '../types' -import { initialBitsEncoded } from 'src/constants' -import { - CredentialContext, - CredentialStatusListType, - CredentialType, - RevocationListType, - SignatureType, -} from 'src/enums/enum' -import { BadRequestError, InternalServerError } from 'src/errors' import { Body, Controller, Get, Path, Post, Route, Tags, Example, Query, Security } from 'tsoa' @Tags('Credentials') @@ -326,137 +314,4 @@ export class CredentialController extends Controller { throw ErrorHandlingService.handle(error) } } - - /** - * Create bitstring status list credential - * - * @param tenantId Id of the tenant - * @param request BSLC required details - */ - @Security('apiKey') - @Post('/create-bslc') - public async createBitstringStatusListCredential( - @Path('tenantId') tenantId: string, - @Body() request: { issuerDID: string; statusPurpose: string; verificationMethod: string } - ) { - try { - const { issuerDID, statusPurpose, verificationMethod } = request - const bslcId = uuidv4() - const credentialpayload = { - '@context': [`${CredentialContext.V1}`, `${CredentialContext.V2}`], - id: `${process.env.BSLC_SERVER_URL}/bitstring/${bslcId}`, - type: [`${CredentialType.VerifiableCredential}`, `${CredentialType.BitstringStatusListCredential}`], - issuer: { - id: issuerDID as string, - }, - issuanceDate: new Date().toISOString(), - credentialSubject: { - id: `${process.env.BSLC_SERVER_URL}/bitstring/${bslcId}`, - type: `${RevocationListType.Bitstring}`, - statusPurpose: statusPurpose, - encodedList: initialBitsEncoded, - }, - credentialStatus: { - id: `${process.env.BSLC_SERVER_URL}/bitstring/${bslcId}`, - type: CredentialStatusListType.CredentialStatusList2017, - }, - } - - let signedCredential - // Step 2: Sign the payload - try { - //TODO: Add correct type here - signedCredential = await this.agent.w3cCredentials.signCredential({ - credential: credentialpayload, - format: ClaimFormat.LdpVc, - proofType: SignatureType.Ed25519Signature2018, - verificationMethod, - }) - } catch (signingError) { - throw new InternalServerError(`Failed to sign the BitstringStatusListCredential: ${signingError}`) - } - // Step 3: Upload the signed payload to the server - const serverUrl = process.env.BSLC_SERVER_URL - if (!serverUrl) { - throw new Error('BSLC_SERVER_URL is not defined in the environment variables') - } - - const token = process.env.BSLC_SERVER_TOKEN - if (!token) { - throw new Error('BSLC_SERVER_TOKEN is not defined in the environment variables') - } - const url = `${serverUrl}/bitstring` - const bslcPayload = { - id: bslcId, - bslcObject: signedCredential, - } - try { - const response = await axios.post(url, bslcPayload, { - headers: { - Accept: '*/*', - Authorization: `Bearer ${token}`, - 'Content-Type': 'application/json', - }, - }) - - if (response.status !== 200) { - throw new Error('Failed to upload the signed BitstringStatusListCredential') - } - } catch (error) { - throw new InternalServerError(`Error uploading the BitstringStatusListCredential: ${error}`) - } - return signedCredential - } catch (error) { - throw ErrorHandlingService.handle(error) - } - } - - @Security('apiKey') - @Post('/get-empty-index/:BSLCUrl') - public async getEmptyIndexForBSLC(@Path('BSLCUrl') BSLCUrl: string) { - try { - if (!BSLCUrl) { - throw new BadRequestError('BSLCUrl is required') - } - - const response = await axios.get(BSLCUrl) - if (response.status !== 200) { - throw new Error('Failed to fetch the BitstringStatusListCredential') - } - - const credential = response.data - const encodedList = credential?.credentialSubject?.claims.encodedList - if (!encodedList) { - throw new Error('Encoded list not found in the credential') - } - - let bitstring - try { - const compressedData = Buffer.from(encodedList, 'base64').toString('binary') - bitstring = Array.from(compressedData) - .map((byte) => byte.padStart(8, '0')) - .join('') - } catch (error) { - throw new Error('Failed to decompress and process the encoded list') - } - - const unusedIndexes = [] - for (let i = 0; i < bitstring.length; i++) { - if (bitstring[i] === '0') { - unusedIndexes.push(i) - } - } - //TODO: add logic to filter from used indexs, for now returning random index with bit status as 0. - if (unusedIndexes.length === 0) { - throw new Error('No unused index found in the BitstringStatusList') - } - - const randomIndex = unusedIndexes[Math.floor(Math.random() * unusedIndexes.length)] - return { - index: randomIndex, - } - } catch (error) { - throw ErrorHandlingService.handle(error) - } - } } diff --git a/src/controllers/multi-tenancy/MultiTenancyController.ts b/src/controllers/multi-tenancy/MultiTenancyController.ts index ef40de97..739463d8 100644 --- a/src/controllers/multi-tenancy/MultiTenancyController.ts +++ b/src/controllers/multi-tenancy/MultiTenancyController.ts @@ -45,29 +45,19 @@ import { injectable, createPeerDidDocumentFromServices, PeerDidNumAlgo, - ClaimFormat, } from '@credo-ts/core' import { QuestionAnswerRole, QuestionAnswerState } from '@credo-ts/question-answer' import axios from 'axios' import * as fs from 'fs' -import { v4 as uuidv4 } from 'uuid' -// import * as zlib from 'zlib' -// import { inflate } from 'pako' -import { initialBitsEncoded } from '../../constants' import { - CredentialContext, CredentialEnum, - CredentialStatusListType, - CredentialType, DidMethod, EndorserMode, Network, NetworkTypes, - RevocationListType, Role, SchemaError, - SignatureType, } from '../../enums/enum' import ErrorHandlingService from '../../errorHandlingService' import { ENDORSER_DID_NOT_PRESENT } from '../../errorMessages' @@ -1923,140 +1913,4 @@ export class MultiTenancyController extends Controller { throw ErrorHandlingService.handle(error) } } - - /** - * Create bitstring status list credential - * - * @param tenantId Id of the tenant - * @param request BSLC required details - */ - @Security('apiKey') - @Post('/create-bslc/:tenantId') - public async createBitstringStatusListCredential( - @Path('tenantId') tenantId: string, - @Body() request: { issuerDID: string; statusPurpose: string, verificationMethod:string } - ) { - try { - const { issuerDID, statusPurpose, verificationMethod } = request - const bslcId = uuidv4() - const credentialpayload = { - '@context': [`${CredentialContext.V1}`, `${CredentialContext.V2}`], - id: `${process.env.BSLC_SERVER_URL}/bitstring/${bslcId}`, - type: [`${CredentialType.VerifiableCredential}`, `${CredentialType.BitstringStatusListCredential}`], - issuer: { - id: issuerDID as string, - }, - issuanceDate: new Date().toISOString(), - credentialSubject: { - id: `${process.env.BSLC_SERVER_URL}/bitstring/${bslcId}`, - type: `${RevocationListType.Bitstring}`, - statusPurpose: statusPurpose, - encodedList: initialBitsEncoded, - }, - credentialStatus: { - id: `${process.env.BSLC_SERVER_URL}/bitstring/${bslcId}`, - type: CredentialStatusListType.CredentialStatusList2017, - }, - } - - let signedCredential - - await this.agent.modules.tenants.withTenantAgent({ tenantId }, async (tenantAgent) => { - // Step 2: Sign the payload - try { - //TODO: Add correct type here - signedCredential = await tenantAgent.w3cCredentials.signCredential({ - credential: credentialpayload, - format: ClaimFormat.LdpVc, - proofType: SignatureType.Ed25519Signature2018, - verificationMethod, - }) - } catch (signingError) { - throw new InternalServerError(`Failed to sign the BitstringStatusListCredential: ${signingError}`) - } - }) - // Step 3: Upload the signed payload to the server - const serverUrl = process.env.BSLC_SERVER_URL - if (!serverUrl) { - throw new Error('BSLC_SERVER_URL is not defined in the environment variables') - } - - const token = process.env.BSLC_SERVER_TOKEN - if (!token) { - throw new Error('BSLC_SERVER_TOKEN is not defined in the environment variables') - } - const url = `${serverUrl}/bitstring` - const bslcPayload = { - id: bslcId, - bslcObject: signedCredential, - } - try { - const response = await axios.post(url, bslcPayload, { - headers: { - Accept: '*/*', - Authorization: `Bearer ${token}`, - 'Content-Type': 'application/json', - }, - }) - - if (response.status !== 200) { - throw new Error('Failed to upload the signed BitstringStatusListCredential') - } - } catch (error) { - throw new InternalServerError(`Error uploading the BitstringStatusListCredential: ${error}`) - } - return signedCredential - } catch (error) { - throw ErrorHandlingService.handle(error) - } - } - - @Security('apiKey') - @Post('/get-empty-index/:BSLCUrl') - public async getEmptyIndexForBSLC(@Path('BSLCUrl') BSLCUrl: string) { - try { - if (!BSLCUrl) { - throw new BadRequestError('BSLCUrl is required') - } - - const response = await axios.get(BSLCUrl) - if (response.status !== 200) { - throw new Error('Failed to fetch the BitstringStatusListCredential') - } - - const credential = response.data - const encodedList = credential?.credentialSubject?.claims.encodedList - if (!encodedList) { - throw new Error('Encoded list not found in the credential') - } - - let bitstring - try { - const compressedData = Buffer.from(encodedList, 'base64').toString('binary') - bitstring = Array.from(compressedData) - .map((byte) => byte.padStart(8, '0')) - .join('') - } catch (error) { - throw new Error('Failed to decompress and process the encoded list') - } - - const unusedIndexes = [] - for (let i = 0; i < bitstring.length; i++) { - if (bitstring[i] === '0') { - unusedIndexes.push(i) - } - } - //TODO: add logic to filter from used indexs, for now returning random index with bit status as 0. - if (unusedIndexes.length === 0) { - throw new Error('No unused index found in the BitstringStatusList') - } - - const randomIndex = unusedIndexes[Math.floor(Math.random() * unusedIndexes.length)] - return { - index: randomIndex, - } - } catch (error) { - throw ErrorHandlingService.handle(error) - } - } } diff --git a/src/routes/routes.ts b/src/routes/routes.ts index 75c49301..4566e855 100644 --- a/src/routes/routes.ts +++ b/src/routes/routes.ts @@ -3546,79 +3546,6 @@ export function RegisterRoutes(app: Router) { } }); // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.post('/multi-tenancy/create-bslc/:tenantId', - authenticateMiddleware([{"apiKey":[]}]), - ...(fetchMiddlewares(MultiTenancyController)), - ...(fetchMiddlewares(MultiTenancyController.prototype.createBitstringStatusListCredential)), - - async function MultiTenancyController_createBitstringStatusListCredential(request: ExRequest, response: ExResponse, next: any) { - const args: Record = { - tenantId: {"in":"path","name":"tenantId","required":true,"dataType":"string"}, - request: {"in":"body","name":"request","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"verificationMethod":{"dataType":"string","required":true},"statusPurpose":{"dataType":"string","required":true},"issuerDID":{"dataType":"string","required":true}}}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = templateService.getValidatedArgs({ args, request, response }); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(MultiTenancyController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - await templateService.apiHandler({ - methodName: 'createBitstringStatusListCredential', - controller, - response, - next, - validatedArgs, - successStatus: undefined, - }); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.post('/multi-tenancy/get-empty-index/:BSLCUrl', - authenticateMiddleware([{"apiKey":[]}]), - ...(fetchMiddlewares(MultiTenancyController)), - ...(fetchMiddlewares(MultiTenancyController.prototype.getEmptyIndexForBSLC)), - - async function MultiTenancyController_getEmptyIndexForBSLC(request: ExRequest, response: ExResponse, next: any) { - const args: Record = { - BSLCUrl: {"in":"path","name":"BSLCUrl","required":true,"dataType":"string"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = templateService.getValidatedArgs({ args, request, response }); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(MultiTenancyController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - await templateService.apiHandler({ - methodName: 'getEmptyIndexForBSLC', - controller, - response, - next, - validatedArgs, - successStatus: undefined, - }); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa app.post('/transactions/endorse', authenticateMiddleware([{"apiKey":[]}]), ...(fetchMiddlewares(EndorserTransactionController)), diff --git a/src/routes/swagger.json b/src/routes/swagger.json index d4d005e5..8eea6fe5 100644 --- a/src/routes/swagger.json +++ b/src/routes/swagger.json @@ -6336,110 +6336,6 @@ } } }, - "/multi-tenancy/create-bslc/{tenantId}": { - "post": { - "operationId": "CreateBitstringStatusListCredential", - "responses": { - "200": { - "description": "Ok", - "content": { - "application/json": { - "schema": {} - } - } - } - }, - "description": "Create bitstring status list credential", - "tags": [ - "MultiTenancy" - ], - "security": [ - { - "apiKey": [] - } - ], - "parameters": [ - { - "description": "Id of the tenant", - "in": "path", - "name": "tenantId", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "description": "BSLC required details", - "required": true, - "content": { - "application/json": { - "schema": { - "properties": { - "verificationMethod": { - "type": "string" - }, - "statusPurpose": { - "type": "string" - }, - "issuerDID": { - "type": "string" - } - }, - "required": [ - "verificationMethod", - "statusPurpose", - "issuerDID" - ], - "type": "object", - "description": "BSLC required details" - } - } - } - } - } - }, - "/multi-tenancy/get-empty-index/{BSLCUrl}": { - "post": { - "operationId": "GetEmptyIndexForBSLC", - "responses": { - "200": { - "description": "Ok", - "content": { - "application/json": { - "schema": { - "properties": { - "index": {} - }, - "required": [ - "index" - ], - "type": "object" - } - } - } - } - }, - "tags": [ - "MultiTenancy" - ], - "security": [ - { - "apiKey": [] - } - ], - "parameters": [ - { - "in": "path", - "name": "BSLCUrl", - "required": true, - "schema": { - "type": "string" - } - } - ] - } - }, "/transactions/endorse": { "post": { "operationId": "EndorserTransaction", From d422e8afbaf084ede07fbe537114b51a2c915682 Mon Sep 17 00:00:00 2001 From: Tipu_Singh Date: Mon, 31 Mar 2025 13:31:27 +0530 Subject: [PATCH 10/15] refactore: removed constant and enum Signed-off-by: Tipu_Singh Signed-off-by: Sahil Kamble Signed-off-by: Krishna Waske --- src/constants.ts | 1 - src/enums/enum.ts | 22 +--------------------- 2 files changed, 1 insertion(+), 22 deletions(-) delete mode 100644 src/constants.ts diff --git a/src/constants.ts b/src/constants.ts deleted file mode 100644 index e7b4b011..00000000 --- a/src/constants.ts +++ /dev/null @@ -1 +0,0 @@ -export const initialBitsEncoded = `uH4sIAAAAAAAAA-3BMQEAAADCoPVPbQwfoAAAAAAAAAAAAAAAAAAAAIC3AYbSVKsAQAAA` diff --git a/src/enums/enum.ts b/src/enums/enum.ts index 4d1f8f18..49f9e74f 100644 --- a/src/enums/enum.ts +++ b/src/enums/enum.ts @@ -70,24 +70,4 @@ export enum HttpStatusCode { export declare enum CustomHandshakeProtocol { DidExchange = 'https://didcomm.org/didexchange/1.1', Connections = 'https://didcomm.org/connections/1.0', -} - -export enum CredentialContext { - V1 = 'https://www.w3.org/2018/credentials/v1', - V2 = 'https://www.w3.org/ns/credentials/v2', -} - -export enum CredentialType { - VerifiableCredential = 'VerifiableCredential', - BitstringStatusListCredential = 'BitstringStatusListCredential', -} -export enum RevocationListType { - Bitstring = 'BitstringStatusList', -} - -export enum CredentialStatusListType { - CredentialStatusList2017 = 'CredentialStatusList2017', -} -export enum SignatureType { - Ed25519Signature2018 = 'Ed25519Signature2018', -} +} \ No newline at end of file From 510e4d26a85212f2282944b73f3528214f7c325f Mon Sep 17 00:00:00 2001 From: bhavanakarwade Date: Fri, 25 Apr 2025 17:04:40 +0530 Subject: [PATCH 11/15] chore: Update Dockerfile (#256) (#266) feat: push docker image (#257) * feat: added yml file to push docker images to github * feat: added yml file to push docker images to github * fix: updated cicd.yml file * fix: renamed yml file --------- feat:w3c-revocation refactor: removed revocation code refactore: removed constant and enum chore: remove unnecessary package chore: remove unwanted files chore: remove unwanted files chore: remove unwanted files Signed-off-by: bhavanakarwade Co-authored-by: KambleSahil3 Signed-off-by: Krishna Waske --- package.json | 4 +--- src/enums/enum.ts | 2 +- yarn.lock | 9 ++------- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index a0422ddf..ed4f9a66 100644 --- a/package.json +++ b/package.json @@ -54,8 +54,8 @@ "@tsoa/runtime": "^6.0.0", "@types/node-fetch": "^2.6.4", "@types/ref-struct-di": "^1.1.9", - "@types/ws": "^8.5.4", "@types/uuid": "^8.3.3", + "@types/ws": "^8.5.4", "axios": "^1.4.0", "body-parser": "^1.20.0", "cors": "^2.8.5", @@ -65,7 +65,6 @@ "joi": "^17.12.3", "jsonwebtoken": "^9.0.2", "node-fetch": "^2.6.7", - "pako": "^2.1.0", "patch-package": "^8.0.0", "postinstall-postinstall": "^2.1.0", "reflect-metadata": "^0.1.13", @@ -86,7 +85,6 @@ "@types/jsonwebtoken": "^9.0.5", "@types/multer": "^1.4.7", "@types/node": "^18.18.8", - "@types/pako": "^2.0.3", "@types/ref-array-di": "^1.2.8", "@types/ref-struct-di": "^1.1.9", "@types/supertest": "^2.0.12", diff --git a/src/enums/enum.ts b/src/enums/enum.ts index 49f9e74f..6468e3af 100644 --- a/src/enums/enum.ts +++ b/src/enums/enum.ts @@ -70,4 +70,4 @@ export enum HttpStatusCode { export declare enum CustomHandshakeProtocol { DidExchange = 'https://didcomm.org/didexchange/1.1', Connections = 'https://didcomm.org/connections/1.0', -} \ No newline at end of file +} diff --git a/yarn.lock b/yarn.lock index ecea63bd..17787e3e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2259,11 +2259,6 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.66.tgz#dd035d409df322acc83dff62a602f12a5783bbb3" integrity sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw== -"@types/pako@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@types/pako/-/pako-2.0.3.tgz#b6993334f3af27c158f3fe0dfeeba987c578afb1" - integrity sha512-bq0hMV9opAcrmE0Byyo0fY3Ew4tgOevJmQ9grUhpXQhYfyLJ1Kqg3P33JT5fdbT2AjeAjR51zqqVjAL/HMkx7Q== - "@types/qs@*": version "6.9.15" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.15.tgz#adde8a060ec9c305a82de1babc1056e73bd64dce" @@ -2364,7 +2359,7 @@ "@types/express" "*" "@types/serve-static" "*" -"@types/uuid@8.3.4", "@types/uuid@^8.3.4": +"@types/uuid@8.3.4", "@types/uuid@^8.3.3": version "8.3.4" resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== @@ -6415,7 +6410,7 @@ package-json-from-dist@^1.0.0: resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00" integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw== -pako@^2.0.4, pako@^2.1.0: +pako@^2.0.4: version "2.1.0" resolved "https://registry.yarnpkg.com/pako/-/pako-2.1.0.tgz#266cc37f98c7d883545d11335c00fbd4062c9a86" integrity sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug== From 36ec9ec22dc1f6baa520132022babacd11a9c07b Mon Sep 17 00:00:00 2001 From: Krishna Waske Date: Tue, 29 Apr 2025 13:19:26 +0530 Subject: [PATCH 12/15] chore: remove unwanted package (#268) Signed-off-by: Krishna Waske --- package.json | 6 ++---- yarn.lock | 17 ++--------------- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/package.json b/package.json index ed4f9a66..d4ea9547 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "@tsoa/runtime": "^6.0.0", "@types/node-fetch": "^2.6.4", "@types/ref-struct-di": "^1.1.9", - "@types/uuid": "^8.3.3", + "@types/uuid": "^8.3.4", "@types/ws": "^8.5.4", "axios": "^1.4.0", "body-parser": "^1.20.0", @@ -72,9 +72,7 @@ "tslog": "^3.3.3", "tsoa": "^6.0.1", "tsyringe": "^4.8.0", - "uuidv4": "^6.2.13", - "yargs": "^17.3.1", - "zlib": "^1.0.5" + "yargs": "^17.3.1" }, "devDependencies": { "@types/body-parser": "^1.19.2", diff --git a/yarn.lock b/yarn.lock index 17787e3e..c7958edd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2359,7 +2359,7 @@ "@types/express" "*" "@types/serve-static" "*" -"@types/uuid@8.3.4", "@types/uuid@^8.3.3": +"@types/uuid@^8.3.4": version "8.3.4" resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== @@ -7653,7 +7653,7 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== -uuid@8.3.2, "uuid@^7.0.0 || ^8.0.0": +"uuid@^7.0.0 || ^8.0.0": version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== @@ -7663,14 +7663,6 @@ uuid@^9.0.0, uuid@^9.0.1: resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== -uuidv4@^6.2.13: - version "6.2.13" - resolved "https://registry.yarnpkg.com/uuidv4/-/uuidv4-6.2.13.tgz#8f95ec5ef22d1f92c8e5d4c70b735d1c89572cb7" - integrity sha512-AXyzMjazYB3ovL3q051VLH06Ixj//Knx7QnUSi1T//Ie3io6CpsPu9nVMOx5MoLWh6xV0B9J0hIaxungxXUbPQ== - dependencies: - "@types/uuid" "8.3.4" - uuid "8.3.2" - v8-compile-cache-lib@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" @@ -7920,8 +7912,3 @@ yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== - -zlib@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/zlib/-/zlib-1.0.5.tgz#6e7c972fc371c645a6afb03ab14769def114fcc0" - integrity sha512-40fpE2II+Cd3k8HWTWONfeKE2jL+P42iWJ1zzps5W51qcTsOUKM5Q5m2PFb0CLxlmFAaUuUdJGc3OfZy947v0w== From b9603b0d05aa9444fc9502c8993f9bc012940bf8 Mon Sep 17 00:00:00 2001 From: Ankita Patidar <35130088+ankita-p17@users.noreply.github.com> Date: Fri, 13 Jun 2025 14:14:31 +0530 Subject: [PATCH 13/15] Sign and verify raw data with the provided key (#273) * feat:sign and verify raw data with the provided key Signed-off-by: Ankita Patidar * sign and verify credential payload Signed-off-by: Ankita Patidar * fix: update sign API Signed-off-by: Krishna Waske * fix: verification logic Signed-off-by: Krishna Waske * fix: final touches Signed-off-by: Krishna Waske * fix: verify credential even with credential status object present in it Signed-off-by: Krishna Waske * fix: final touches Signed-off-by: Krishna Waske --------- Signed-off-by: Ankita Patidar Signed-off-by: Krishna Waske Co-authored-by: Krishna Waske Signed-off-by: Krishna Waske --- .../multi-tenancy/MultiTenancyController.ts | 118 ++- src/controllers/types.ts | 39 +- src/routes/routes.ts | 348 ++++++++ src/routes/swagger.json | 758 ++++++++++++++++++ 4 files changed, 1255 insertions(+), 8 deletions(-) diff --git a/src/controllers/multi-tenancy/MultiTenancyController.ts b/src/controllers/multi-tenancy/MultiTenancyController.ts index 739463d8..1383c773 100644 --- a/src/controllers/multi-tenancy/MultiTenancyController.ts +++ b/src/controllers/multi-tenancy/MultiTenancyController.ts @@ -1,7 +1,7 @@ /* eslint-disable prettier/prettier */ import type { RestAgentModules, RestMultiTenantAgentModules } from '../../cliAgent' import type { Version } from '../examples' -import type { RecipientKeyOption, SchemaMetadata } from '../types' +import type { RecipientKeyOption, SafeW3cJsonLdVerifyCredentialOptions, SchemaMetadata } from '../types' import type { PolygonDidCreateOptions } from '@ayanworks/credo-polygon-w3c-module/build/dids' import type { AcceptProofRequestOptions, @@ -15,7 +15,8 @@ import type { ProofExchangeRecordProps, ProofsProtocolVersionType, Routing, -} from '@credo-ts/core' + W3cJsonLdSignCredentialOptions, + W3cVerifiableCredential} from '@credo-ts/core' import type { IndyVdrDidCreateOptions, IndyVdrDidCreateResult } from '@credo-ts/indy-vdr' import type { QuestionAnswerRecord, ValidResponse } from '@credo-ts/question-answer' import type { TenantRecord } from '@credo-ts/tenants' @@ -27,6 +28,7 @@ import { parseIndyCredentialDefinitionId, parseIndySchemaId, } from '@credo-ts/anoncreds' +import { assertAskarWallet } from '@credo-ts/askar/build/utils/assertAskarWallet' import { AcceptCredentialOfferOptions, Agent, @@ -45,7 +47,9 @@ import { injectable, createPeerDidDocumentFromServices, PeerDidNumAlgo, -} from '@credo-ts/core' + W3cJsonLdVerifiableCredential, + W3cCredential, + ClaimFormat} from '@credo-ts/core' import { QuestionAnswerRole, QuestionAnswerState } from '@credo-ts/question-answer' import axios from 'axios' import * as fs from 'fs' @@ -89,7 +93,7 @@ import { CreateProofRequestOobOptions, CreateOfferOobOptions, CreateSchemaInput, -} from '../types' + VerifyDataOptions , SignDataOptions } from '../types' import { Body, Controller, Delete, Get, Post, Query, Route, Tags, Path, Example, Security, Response } from 'tsoa' @@ -1913,4 +1917,110 @@ export class MultiTenancyController extends Controller { throw ErrorHandlingService.handle(error) } } + + + /** + * Sign data using a key + * + * @param tenantId Tenant identifier + * @param request Sign options + * data - Data has to be in base64 format + * publicKeyBase58 - Public key in base58 format + * @returns Signature in base64 format + */ + @Security('apiKey') + @Post('/sign/:tenantId') + public async sign(@Path('tenantId') tenantId: string, @Body() request: SignDataOptions) { + try { + const signature = await this.agent.modules.tenants.withTenantAgent({ tenantId }, async (tenantAgent) => { + // assertAskarWallet(tenantAgent.context.wallet) + + // tenantAgent.w3cCredentials + + const signature = await tenantAgent.context.wallet.sign({ + data: TypedArrayEncoder.fromBase64(request.data), + key: Key.fromPublicKeyBase58(request.publicKeyBase58, request.keyType), + }) + return TypedArrayEncoder.toBase64(signature) + }) + return signature + } catch (error) { + throw ErrorHandlingService.handle(error) + } + } + + /** + * Verify data using a key + * + * @param tenantId Tenant identifier + * @param request Verify options + * data - Data has to be in base64 format + * publicKeyBase58 - Public key in base58 format + * signature - Signature in base64 format + * @returns isValidSignature - true if signature is valid, false otherwise + */ + @Security('apiKey') + @Post('/verify/:tenantId') + public async verify(@Path('tenantId') tenantId: string, @Body() request: VerifyDataOptions) { + try { + const isValidSignature = await this.agent.modules.tenants.withTenantAgent({ tenantId }, async (tenantAgent) => { + assertAskarWallet(tenantAgent.context.wallet) + const isValidSignature = await tenantAgent.context.wallet.verify({ + data: TypedArrayEncoder.fromBase64(request.data), + key: Key.fromPublicKeyBase58(request.publicKeyBase58, request.keyType), + signature: TypedArrayEncoder.fromBase64(request.signature), + }) + return isValidSignature + }) + return isValidSignature + } catch (error) { + throw ErrorHandlingService.handle(error) + } + } + + @Security('apiKey') + @Post('/credential/sign/:tenantId') + public async signCredential( + @Path('tenantId') tenantId: string, + @Query('storeCredential') storeCredential: boolean, + @Body() credentialToSign: W3cJsonLdSignCredentialOptions | any + ) { + let storedCredential + let formattedCredential + try { + await this.agent.modules.tenants.withTenantAgent({ tenantId }, async (tenantAgent) => { + credentialToSign.format = ClaimFormat.LdpVc + + const signedCred = await tenantAgent.w3cCredentials.signCredential(credentialToSign) as W3cJsonLdVerifiableCredential + formattedCredential = signedCred.toJson() + if (storeCredential) { + storedCredential = await tenantAgent.w3cCredentials.storeCredential({ credential: signedCred }) + } + }) + return storedCredential ?? formattedCredential + } catch (error) { + throw ErrorHandlingService.handle(error) + } + } + + @Security('apiKey') + @Post('/credential/verify/:tenantId') + public async verifyCredential( + @Path('tenantId') tenantId: string, + @Body() credentialToVerify: SafeW3cJsonLdVerifyCredentialOptions | any + ) { + let formattedCredential + try { + await this.agent.modules.tenants.withTenantAgent({ tenantId }, async (tenantAgent) => { + const {credential, ...credentialOptions}= credentialToVerify + const transformedCredential = JsonTransformer.fromJSON(credentialToVerify?.credential, W3cJsonLdVerifiableCredential) + const signedCred = await tenantAgent.w3cCredentials.verifyCredential({credential: transformedCredential, ...credentialOptions}) + formattedCredential = signedCred + }) + return formattedCredential + } catch (error) { + throw ErrorHandlingService.handle(error) + } + } } + diff --git a/src/controllers/types.ts b/src/controllers/types.ts index 3753d6f2..f3acb079 100644 --- a/src/controllers/types.ts +++ b/src/controllers/types.ts @@ -25,8 +25,13 @@ import type { Attachment, KeyType, JsonLdCredentialFormat, + JsonObject, + W3cJsonLdVerifyCredentialOptions, + DataIntegrityProofOptions, } from '@credo-ts/core' +import type { SingleOrArray } from '@credo-ts/core/build/utils' import type { DIDDocument } from 'did-resolver' +import { LinkedDataProofOptions } from '@credo-ts/core/build/modules/vc/data-integrity/models/LinkedDataProof' export type TenantConfig = Pick & { walletConfig: Pick @@ -37,10 +42,6 @@ export interface AgentInfo { endpoints: string[] isInitialized: boolean publicDid: void - // publicDid?: { - // did: string - // verkey: string - // } } export interface AgentMessageType { @@ -388,3 +389,33 @@ export interface SchemaMetadata { * @example "ea4e5e69-fc04-465a-90d2-9f8ff78aa71d" */ export type ThreadId = string + +export type SignDataOptions = { + data: string + keyType: KeyType + publicKeyBase58: string +} + +export type VerifyDataOptions = { + data: string + keyType: KeyType + publicKeyBase58: string + signature: string +} + +export interface jsonLdCredentialOptions { + '@context': Array + type: Array + credentialSubject: SingleOrArray + proofType: string +} + +export interface credentialPayloadToSign { + issuerDID: string + method: string + credential: jsonLdCredentialOptions // TODO: add support for other credential format +} +export interface SafeW3cJsonLdVerifyCredentialOptions extends W3cJsonLdVerifyCredentialOptions { + // Ommited due to issues with TSOA + proof: SingleOrArray | DataIntegrityProofOptions> +} \ No newline at end of file diff --git a/src/routes/routes.ts b/src/routes/routes.ts index 4566e855..c2294d13 100644 --- a/src/routes/routes.ts +++ b/src/routes/routes.ts @@ -693,6 +693,205 @@ const models: TsoaRoute.Models = { "type": {"dataType":"nestedObjectLiteral","nestedProperties":{"content":{"dataType":"string","required":true}},"validators":{}}, }, // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "SignDataOptions": { + "dataType": "refAlias", + "type": {"dataType":"nestedObjectLiteral","nestedProperties":{"publicKeyBase58":{"dataType":"string","required":true},"keyType":{"ref":"KeyType","required":true},"data":{"dataType":"string","required":true}},"validators":{}}, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "VerifyDataOptions": { + "dataType": "refAlias", + "type": {"dataType":"nestedObjectLiteral","nestedProperties":{"signature":{"dataType":"string","required":true},"publicKeyBase58":{"dataType":"string","required":true},"keyType":{"ref":"KeyType","required":true},"data":{"dataType":"string","required":true}},"validators":{}}, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "ClaimFormat.LdpVc": { + "dataType": "refEnum", + "enums": ["ldp_vc"], + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "ProofPurpose": { + "dataType": "refAlias", + "type": {"dataType":"any","validators":{}}, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "ClaimFormat": { + "dataType": "refEnum", + "enums": ["jwt","jwt_vc","jwt_vp","ldp","ldp_vc","ldp_vp","di","di_vc","di_vp","vc+sd-jwt"], + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "W3cIssuer": { + "dataType": "refObject", + "properties": { + "id": {"dataType":"string","required":true}, + }, + "additionalProperties": false, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "W3cCredentialSubject": { + "dataType": "refObject", + "properties": { + "id": {"dataType":"string"}, + "claims": {"ref":"Record_string.unknown_"}, + }, + "additionalProperties": false, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "SingleOrArray_W3cCredentialSubject_": { + "dataType": "refAlias", + "type": {"dataType":"union","subSchemas":[{"ref":"W3cCredentialSubject"},{"dataType":"array","array":{"dataType":"refObject","ref":"W3cCredentialSubject"}}],"validators":{}}, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "W3cCredentialSchema": { + "dataType": "refObject", + "properties": { + "id": {"dataType":"string","required":true}, + "type": {"dataType":"string","required":true}, + }, + "additionalProperties": false, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "SingleOrArray_W3cCredentialSchema_": { + "dataType": "refAlias", + "type": {"dataType":"union","subSchemas":[{"ref":"W3cCredentialSchema"},{"dataType":"array","array":{"dataType":"refObject","ref":"W3cCredentialSchema"}}],"validators":{}}, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "W3cCredentialStatus": { + "dataType": "refObject", + "properties": { + "id": {"dataType":"string","required":true}, + "type": {"dataType":"string","required":true}, + }, + "additionalProperties": false, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "W3cCredential": { + "dataType": "refObject", + "properties": { + "context": {"dataType":"array","array":{"dataType":"union","subSchemas":[{"dataType":"string"},{"ref":"JsonObject"}]},"required":true}, + "id": {"dataType":"string"}, + "type": {"dataType":"array","array":{"dataType":"string"},"required":true}, + "issuer": {"dataType":"union","subSchemas":[{"dataType":"string"},{"ref":"W3cIssuer"}],"required":true}, + "issuanceDate": {"dataType":"string","required":true}, + "expirationDate": {"dataType":"string"}, + "credentialSubject": {"ref":"SingleOrArray_W3cCredentialSubject_","required":true}, + "credentialSchema": {"ref":"SingleOrArray_W3cCredentialSchema_"}, + "credentialStatus": {"ref":"W3cCredentialStatus"}, + }, + "additionalProperties": false, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "W3cJsonLdSignCredentialOptions": { + "dataType": "refObject", + "properties": { + "format": {"ref":"ClaimFormat.LdpVc","required":true}, + "credential": {"ref":"W3cCredential","required":true}, + "verificationMethod": {"dataType":"string","required":true}, + "proofType": {"dataType":"string","required":true}, + "proofPurpose": {"ref":"ProofPurpose"}, + "created": {"dataType":"string"}, + }, + "additionalProperties": false, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "Pick_LinkedDataProofOptions.Exclude_keyofLinkedDataProofOptions.cryptosuite__": { + "dataType": "refAlias", + "type": {"dataType":"nestedObjectLiteral","nestedProperties":{"type":{"dataType":"string","required":true},"proofPurpose":{"dataType":"string","required":true},"verificationMethod":{"dataType":"string","required":true},"created":{"dataType":"string","required":true},"domain":{"dataType":"string"},"challenge":{"dataType":"string"},"jws":{"dataType":"string"},"proofValue":{"dataType":"string"},"nonce":{"dataType":"string"}},"validators":{}}, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "Omit_LinkedDataProofOptions.cryptosuite_": { + "dataType": "refAlias", + "type": {"ref":"Pick_LinkedDataProofOptions.Exclude_keyofLinkedDataProofOptions.cryptosuite__","validators":{}}, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "DataIntegrityProofOptions": { + "dataType": "refObject", + "properties": { + "type": {"dataType":"string","required":true}, + "cryptosuite": {"dataType":"string","required":true}, + "verificationMethod": {"dataType":"string","required":true}, + "proofPurpose": {"dataType":"string","required":true}, + "domain": {"dataType":"string"}, + "challenge": {"dataType":"string"}, + "nonce": {"dataType":"string"}, + "created": {"dataType":"string"}, + "expires": {"dataType":"string"}, + "proofValue": {"dataType":"string"}, + "previousProof": {"dataType":"string"}, + }, + "additionalProperties": false, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "SingleOrArray_Omit_LinkedDataProofOptions.cryptosuite_-or-DataIntegrityProofOptions_": { + "dataType": "refAlias", + "type": {"dataType":"union","subSchemas":[{"dataType":"union","subSchemas":[{"ref":"Omit_LinkedDataProofOptions.cryptosuite_"},{"ref":"DataIntegrityProofOptions"}]},{"dataType":"array","array":{"dataType":"union","subSchemas":[{"ref":"Omit_LinkedDataProofOptions.cryptosuite_"},{"ref":"DataIntegrityProofOptions"}]}}],"validators":{}}, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "LinkedDataProof": { + "dataType": "refObject", + "properties": { + "type": {"dataType":"string","required":true}, + "proofPurpose": {"dataType":"string","required":true}, + "verificationMethod": {"dataType":"string","required":true}, + "created": {"dataType":"string","required":true}, + "domain": {"dataType":"string"}, + "challenge": {"dataType":"string"}, + "jws": {"dataType":"string"}, + "proofValue": {"dataType":"string"}, + "nonce": {"dataType":"string"}, + }, + "additionalProperties": false, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "DataIntegrityProof": { + "dataType": "refObject", + "properties": { + "type": {"dataType":"string","required":true}, + "cryptosuite": {"dataType":"string","required":true}, + "proofPurpose": {"dataType":"string","required":true}, + "verificationMethod": {"dataType":"string","required":true}, + "domain": {"dataType":"string"}, + "challenge": {"dataType":"string"}, + "nonce": {"dataType":"string"}, + "created": {"dataType":"string"}, + "expires": {"dataType":"string"}, + "proofValue": {"dataType":"string"}, + "previousProof": {"dataType":"string"}, + }, + "additionalProperties": false, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "SingleOrArray_LinkedDataProof-or-DataIntegrityProof_": { + "dataType": "refAlias", + "type": {"dataType":"union","subSchemas":[{"dataType":"union","subSchemas":[{"ref":"LinkedDataProof"},{"ref":"DataIntegrityProof"}]},{"dataType":"array","array":{"dataType":"union","subSchemas":[{"ref":"LinkedDataProof"},{"ref":"DataIntegrityProof"}]}}],"validators":{}}, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "W3cJsonLdVerifiableCredential": { + "dataType": "refObject", + "properties": { + "context": {"dataType":"array","array":{"dataType":"union","subSchemas":[{"dataType":"string"},{"ref":"JsonObject"}]},"required":true}, + "id": {"dataType":"string"}, + "type": {"dataType":"array","array":{"dataType":"string"},"required":true}, + "issuer": {"dataType":"union","subSchemas":[{"dataType":"string"},{"ref":"W3cIssuer"}],"required":true}, + "issuanceDate": {"dataType":"string","required":true}, + "expirationDate": {"dataType":"string"}, + "credentialSubject": {"ref":"SingleOrArray_W3cCredentialSubject_","required":true}, + "credentialSchema": {"ref":"SingleOrArray_W3cCredentialSchema_"}, + "credentialStatus": {"ref":"W3cCredentialStatus"}, + "proof": {"ref":"SingleOrArray_LinkedDataProof-or-DataIntegrityProof_","required":true}, + }, + "additionalProperties": false, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "SafeW3cJsonLdVerifyCredentialOptions": { + "dataType": "refObject", + "properties": { + "credential": {"ref":"W3cJsonLdVerifiableCredential","required":true}, + "verifyCredentialStatus": {"dataType":"boolean"}, + "proofPurpose": {"ref":"ProofPurpose"}, + "proof": {"ref":"SingleOrArray_Omit_LinkedDataProofOptions.cryptosuite_-or-DataIntegrityProofOptions_","required":true}, + }, + "additionalProperties": false, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa "DidRegistrationSecretOptions": { "dataType": "refAlias", "type": {"ref":"Record_string.unknown_","validators":{}}, @@ -3546,6 +3745,155 @@ export function RegisterRoutes(app: Router) { } }); // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + app.post('/multi-tenancy/sign/:tenantId', + authenticateMiddleware([{"apiKey":[]}]), + ...(fetchMiddlewares(MultiTenancyController)), + ...(fetchMiddlewares(MultiTenancyController.prototype.sign)), + + async function MultiTenancyController_sign(request: ExRequest, response: ExResponse, next: any) { + const args: Record = { + tenantId: {"in":"path","name":"tenantId","required":true,"dataType":"string"}, + request: {"in":"body","name":"request","required":true,"ref":"SignDataOptions"}, + }; + + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + + let validatedArgs: any[] = []; + try { + validatedArgs = templateService.getValidatedArgs({ args, request, response }); + + const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; + + const controller: any = await container.get(MultiTenancyController); + if (typeof controller['setStatus'] === 'function') { + controller.setStatus(undefined); + } + + await templateService.apiHandler({ + methodName: 'sign', + controller, + response, + next, + validatedArgs, + successStatus: undefined, + }); + } catch (err) { + return next(err); + } + }); + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + app.post('/multi-tenancy/verify/:tenantId', + authenticateMiddleware([{"apiKey":[]}]), + ...(fetchMiddlewares(MultiTenancyController)), + ...(fetchMiddlewares(MultiTenancyController.prototype.verify)), + + async function MultiTenancyController_verify(request: ExRequest, response: ExResponse, next: any) { + const args: Record = { + tenantId: {"in":"path","name":"tenantId","required":true,"dataType":"string"}, + request: {"in":"body","name":"request","required":true,"ref":"VerifyDataOptions"}, + }; + + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + + let validatedArgs: any[] = []; + try { + validatedArgs = templateService.getValidatedArgs({ args, request, response }); + + const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; + + const controller: any = await container.get(MultiTenancyController); + if (typeof controller['setStatus'] === 'function') { + controller.setStatus(undefined); + } + + await templateService.apiHandler({ + methodName: 'verify', + controller, + response, + next, + validatedArgs, + successStatus: undefined, + }); + } catch (err) { + return next(err); + } + }); + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + app.post('/multi-tenancy/credential/sign/:tenantId', + authenticateMiddleware([{"apiKey":[]}]), + ...(fetchMiddlewares(MultiTenancyController)), + ...(fetchMiddlewares(MultiTenancyController.prototype.signCredential)), + + async function MultiTenancyController_signCredential(request: ExRequest, response: ExResponse, next: any) { + const args: Record = { + tenantId: {"in":"path","name":"tenantId","required":true,"dataType":"string"}, + storeCredential: {"in":"query","name":"storeCredential","required":true,"dataType":"boolean"}, + credentialToSign: {"in":"body","name":"credentialToSign","required":true,"dataType":"union","subSchemas":[{"ref":"W3cJsonLdSignCredentialOptions"},{"dataType":"any"}]}, + }; + + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + + let validatedArgs: any[] = []; + try { + validatedArgs = templateService.getValidatedArgs({ args, request, response }); + + const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; + + const controller: any = await container.get(MultiTenancyController); + if (typeof controller['setStatus'] === 'function') { + controller.setStatus(undefined); + } + + await templateService.apiHandler({ + methodName: 'signCredential', + controller, + response, + next, + validatedArgs, + successStatus: undefined, + }); + } catch (err) { + return next(err); + } + }); + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + app.post('/multi-tenancy/credential/verify/:tenantId', + authenticateMiddleware([{"apiKey":[]}]), + ...(fetchMiddlewares(MultiTenancyController)), + ...(fetchMiddlewares(MultiTenancyController.prototype.verifyCredential)), + + async function MultiTenancyController_verifyCredential(request: ExRequest, response: ExResponse, next: any) { + const args: Record = { + tenantId: {"in":"path","name":"tenantId","required":true,"dataType":"string"}, + credentialToVerify: {"in":"body","name":"credentialToVerify","required":true,"dataType":"union","subSchemas":[{"ref":"SafeW3cJsonLdVerifyCredentialOptions"},{"dataType":"any"}]}, + }; + + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + + let validatedArgs: any[] = []; + try { + validatedArgs = templateService.getValidatedArgs({ args, request, response }); + + const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; + + const controller: any = await container.get(MultiTenancyController); + if (typeof controller['setStatus'] === 'function') { + controller.setStatus(undefined); + } + + await templateService.apiHandler({ + methodName: 'verifyCredential', + controller, + response, + next, + validatedArgs, + successStatus: undefined, + }); + } catch (err) { + return next(err); + } + }); + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa app.post('/transactions/endorse', authenticateMiddleware([{"apiKey":[]}]), ...(fetchMiddlewares(EndorserTransactionController)), diff --git a/src/routes/swagger.json b/src/routes/swagger.json index 8eea6fe5..c872bd20 100644 --- a/src/routes/swagger.json +++ b/src/routes/swagger.json @@ -1625,6 +1625,562 @@ "type": "object", "description": "Construct a type with a set of properties K of type T" }, + "SignDataOptions": { + "properties": { + "publicKeyBase58": { + "type": "string" + }, + "keyType": { + "$ref": "#/components/schemas/KeyType" + }, + "data": { + "type": "string" + } + }, + "required": [ + "publicKeyBase58", + "keyType", + "data" + ], + "type": "object" + }, + "VerifyDataOptions": { + "properties": { + "signature": { + "type": "string" + }, + "publicKeyBase58": { + "type": "string" + }, + "keyType": { + "$ref": "#/components/schemas/KeyType" + }, + "data": { + "type": "string" + } + }, + "required": [ + "signature", + "publicKeyBase58", + "keyType", + "data" + ], + "type": "object" + }, + "ClaimFormat.LdpVc": { + "enum": [ + "ldp_vc" + ], + "type": "string" + }, + "ProofPurpose": {}, + "ClaimFormat": { + "description": "Defines the claim format based on the formats registered in\n[DIF Claim Format Registry](https://identity.foundation/claim-format-registry/).", + "enum": [ + "jwt", + "jwt_vc", + "jwt_vp", + "ldp", + "ldp_vc", + "ldp_vp", + "di", + "di_vc", + "di_vp", + "vc+sd-jwt" + ], + "type": "string" + }, + "W3cIssuer": { + "properties": { + "id": { + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object", + "additionalProperties": false + }, + "W3cCredentialSubject": { + "properties": { + "id": { + "type": "string" + }, + "claims": { + "$ref": "#/components/schemas/Record_string.unknown_" + } + }, + "type": "object", + "additionalProperties": false + }, + "SingleOrArray_W3cCredentialSubject_": { + "anyOf": [ + { + "$ref": "#/components/schemas/W3cCredentialSubject" + }, + { + "items": { + "$ref": "#/components/schemas/W3cCredentialSubject" + }, + "type": "array" + } + ] + }, + "W3cCredentialSchema": { + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "id", + "type" + ], + "type": "object", + "additionalProperties": false + }, + "SingleOrArray_W3cCredentialSchema_": { + "anyOf": [ + { + "$ref": "#/components/schemas/W3cCredentialSchema" + }, + { + "items": { + "$ref": "#/components/schemas/W3cCredentialSchema" + }, + "type": "array" + } + ] + }, + "W3cCredentialStatus": { + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "id", + "type" + ], + "type": "object", + "additionalProperties": false + }, + "W3cCredential": { + "properties": { + "context": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "$ref": "#/components/schemas/JsonObject" + } + ] + }, + "type": "array" + }, + "id": { + "type": "string" + }, + "type": { + "items": { + "type": "string" + }, + "type": "array" + }, + "issuer": { + "anyOf": [ + { + "type": "string" + }, + { + "$ref": "#/components/schemas/W3cIssuer" + } + ] + }, + "issuanceDate": { + "type": "string" + }, + "expirationDate": { + "type": "string" + }, + "credentialSubject": { + "$ref": "#/components/schemas/SingleOrArray_W3cCredentialSubject_" + }, + "credentialSchema": { + "$ref": "#/components/schemas/SingleOrArray_W3cCredentialSchema_" + }, + "credentialStatus": { + "$ref": "#/components/schemas/W3cCredentialStatus" + } + }, + "required": [ + "context", + "type", + "issuer", + "issuanceDate", + "credentialSubject" + ], + "type": "object", + "additionalProperties": false + }, + "W3cJsonLdSignCredentialOptions": { + "properties": { + "format": { + "$ref": "#/components/schemas/ClaimFormat.LdpVc", + "description": "The format of the credential to be signed. Must be either `jwt_vc` or `ldp_vc`." + }, + "credential": { + "$ref": "#/components/schemas/W3cCredential", + "description": "The credential to be signed." + }, + "verificationMethod": { + "type": "string", + "description": "URI of the verificationMethod to be used for signing the credential.\n\nMust be a valid did url pointing to a key." + }, + "proofType": { + "type": "string", + "description": "The proofType to be used for signing the credential.\n\nMust be a valid Linked Data Signature suite." + }, + "proofPurpose": { + "$ref": "#/components/schemas/ProofPurpose" + }, + "created": { + "type": "string" + } + }, + "required": [ + "format", + "credential", + "verificationMethod", + "proofType" + ], + "type": "object", + "additionalProperties": false + }, + "Pick_LinkedDataProofOptions.Exclude_keyofLinkedDataProofOptions.cryptosuite__": { + "properties": { + "type": { + "type": "string" + }, + "proofPurpose": { + "type": "string" + }, + "verificationMethod": { + "type": "string" + }, + "created": { + "type": "string" + }, + "domain": { + "type": "string" + }, + "challenge": { + "type": "string" + }, + "jws": { + "type": "string" + }, + "proofValue": { + "type": "string" + }, + "nonce": { + "type": "string" + } + }, + "required": [ + "type", + "proofPurpose", + "verificationMethod", + "created" + ], + "type": "object", + "description": "From T, pick a set of properties whose keys are in the union K" + }, + "Omit_LinkedDataProofOptions.cryptosuite_": { + "$ref": "#/components/schemas/Pick_LinkedDataProofOptions.Exclude_keyofLinkedDataProofOptions.cryptosuite__", + "description": "Construct a type with the properties of T except for those in type K." + }, + "DataIntegrityProofOptions": { + "properties": { + "type": { + "type": "string" + }, + "cryptosuite": { + "type": "string" + }, + "verificationMethod": { + "type": "string" + }, + "proofPurpose": { + "type": "string" + }, + "domain": { + "type": "string" + }, + "challenge": { + "type": "string" + }, + "nonce": { + "type": "string" + }, + "created": { + "type": "string" + }, + "expires": { + "type": "string" + }, + "proofValue": { + "type": "string" + }, + "previousProof": { + "type": "string" + } + }, + "required": [ + "type", + "cryptosuite", + "verificationMethod", + "proofPurpose" + ], + "type": "object", + "additionalProperties": false + }, + "SingleOrArray_Omit_LinkedDataProofOptions.cryptosuite_-or-DataIntegrityProofOptions_": { + "anyOf": [ + { + "anyOf": [ + { + "$ref": "#/components/schemas/Omit_LinkedDataProofOptions.cryptosuite_" + }, + { + "$ref": "#/components/schemas/DataIntegrityProofOptions" + } + ] + }, + { + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/Omit_LinkedDataProofOptions.cryptosuite_" + }, + { + "$ref": "#/components/schemas/DataIntegrityProofOptions" + } + ] + }, + "type": "array" + } + ] + }, + "LinkedDataProof": { + "description": "Linked Data Proof", + "properties": { + "type": { + "type": "string" + }, + "proofPurpose": { + "type": "string" + }, + "verificationMethod": { + "type": "string" + }, + "created": { + "type": "string" + }, + "domain": { + "type": "string" + }, + "challenge": { + "type": "string" + }, + "jws": { + "type": "string" + }, + "proofValue": { + "type": "string" + }, + "nonce": { + "type": "string" + } + }, + "required": [ + "type", + "proofPurpose", + "verificationMethod", + "created" + ], + "type": "object", + "additionalProperties": false + }, + "DataIntegrityProof": { + "description": "Linked Data Proof", + "properties": { + "type": { + "type": "string" + }, + "cryptosuite": { + "type": "string" + }, + "proofPurpose": { + "type": "string" + }, + "verificationMethod": { + "type": "string" + }, + "domain": { + "type": "string" + }, + "challenge": { + "type": "string" + }, + "nonce": { + "type": "string" + }, + "created": { + "type": "string" + }, + "expires": { + "type": "string" + }, + "proofValue": { + "type": "string" + }, + "previousProof": { + "type": "string" + } + }, + "required": [ + "type", + "cryptosuite", + "proofPurpose", + "verificationMethod" + ], + "type": "object", + "additionalProperties": false + }, + "SingleOrArray_LinkedDataProof-or-DataIntegrityProof_": { + "anyOf": [ + { + "anyOf": [ + { + "$ref": "#/components/schemas/LinkedDataProof" + }, + { + "$ref": "#/components/schemas/DataIntegrityProof" + } + ] + }, + { + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/LinkedDataProof" + }, + { + "$ref": "#/components/schemas/DataIntegrityProof" + } + ] + }, + "type": "array" + } + ] + }, + "W3cJsonLdVerifiableCredential": { + "properties": { + "context": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "$ref": "#/components/schemas/JsonObject" + } + ] + }, + "type": "array" + }, + "id": { + "type": "string" + }, + "type": { + "items": { + "type": "string" + }, + "type": "array" + }, + "issuer": { + "anyOf": [ + { + "type": "string" + }, + { + "$ref": "#/components/schemas/W3cIssuer" + } + ] + }, + "issuanceDate": { + "type": "string" + }, + "expirationDate": { + "type": "string" + }, + "credentialSubject": { + "$ref": "#/components/schemas/SingleOrArray_W3cCredentialSubject_" + }, + "credentialSchema": { + "$ref": "#/components/schemas/SingleOrArray_W3cCredentialSchema_" + }, + "credentialStatus": { + "$ref": "#/components/schemas/W3cCredentialStatus" + }, + "proof": { + "$ref": "#/components/schemas/SingleOrArray_LinkedDataProof-or-DataIntegrityProof_" + } + }, + "required": [ + "context", + "type", + "issuer", + "issuanceDate", + "credentialSubject", + "proof" + ], + "type": "object", + "additionalProperties": false + }, + "SafeW3cJsonLdVerifyCredentialOptions": { + "properties": { + "credential": { + "$ref": "#/components/schemas/W3cJsonLdVerifiableCredential" + }, + "verifyCredentialStatus": { + "type": "boolean", + "description": "Whether to verify the credentialStatus, if present." + }, + "proofPurpose": { + "$ref": "#/components/schemas/ProofPurpose" + }, + "proof": { + "$ref": "#/components/schemas/SingleOrArray_Omit_LinkedDataProofOptions.cryptosuite_-or-DataIntegrityProofOptions_" + } + }, + "required": [ + "credential", + "proof" + ], + "type": "object", + "additionalProperties": false + }, "DidRegistrationSecretOptions": { "$ref": "#/components/schemas/Record_string.unknown_" }, @@ -6336,6 +6892,208 @@ } } }, + "/multi-tenancy/sign/{tenantId}": { + "post": { + "operationId": "Sign", + "responses": { + "200": { + "description": "Signature in base64 format", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + } + }, + "description": "Sign data using a key", + "tags": [ + "MultiTenancy" + ], + "security": [ + { + "apiKey": [] + } + ], + "parameters": [ + { + "description": "Tenant identifier", + "in": "path", + "name": "tenantId", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "Sign options\ndata - Data has to be in base64 format\npublicKeyBase58 - Public key in base58 format", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SignDataOptions", + "description": "Sign options\ndata - Data has to be in base64 format\npublicKeyBase58 - Public key in base58 format" + } + } + } + } + } + }, + "/multi-tenancy/verify/{tenantId}": { + "post": { + "operationId": "Verify", + "responses": { + "200": { + "description": "isValidSignature - true if signature is valid, false otherwise", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + }, + "description": "Verify data using a key", + "tags": [ + "MultiTenancy" + ], + "security": [ + { + "apiKey": [] + } + ], + "parameters": [ + { + "description": "Tenant identifier", + "in": "path", + "name": "tenantId", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "Verify options\ndata - Data has to be in base64 format\npublicKeyBase58 - Public key in base58 format\nsignature - Signature in base64 format", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyDataOptions", + "description": "Verify options\ndata - Data has to be in base64 format\npublicKeyBase58 - Public key in base58 format\nsignature - Signature in base64 format" + } + } + } + } + } + }, + "/multi-tenancy/credential/sign/{tenantId}": { + "post": { + "operationId": "SignCredential", + "responses": { + "200": { + "description": "Ok", + "content": { + "application/json": { + "schema": {} + } + } + } + }, + "tags": [ + "MultiTenancy" + ], + "security": [ + { + "apiKey": [] + } + ], + "parameters": [ + { + "in": "path", + "name": "tenantId", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "storeCredential", + "required": true, + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/W3cJsonLdSignCredentialOptions" + }, + {} + ] + } + } + } + } + } + }, + "/multi-tenancy/credential/verify/{tenantId}": { + "post": { + "operationId": "VerifyCredential", + "responses": { + "200": { + "description": "Ok", + "content": { + "application/json": { + "schema": {} + } + } + } + }, + "tags": [ + "MultiTenancy" + ], + "security": [ + { + "apiKey": [] + } + ], + "parameters": [ + { + "in": "path", + "name": "tenantId", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/SafeW3cJsonLdVerifyCredentialOptions" + }, + {} + ] + } + } + } + } + } + }, "/transactions/endorse": { "post": { "operationId": "EndorserTransaction", From 9bd5464637dc36940b94c63a7ec38032095c3d4c Mon Sep 17 00:00:00 2001 From: Krishna Waske Date: Fri, 13 Jun 2025 16:25:56 +0530 Subject: [PATCH 14/15] feat/sign verify rawdata (#274) * feat:sign and verify raw data with the provided key Signed-off-by: Ankita Patidar * sign and verify credential payload Signed-off-by: Ankita Patidar * fix: update sign API Signed-off-by: Krishna Waske * fix: verification logic Signed-off-by: Krishna Waske * fix: final touches Signed-off-by: Krishna Waske * fix: verify credential even with credential status object present in it Signed-off-by: Krishna Waske * fix: final touches Signed-off-by: Krishna Waske * fix: combine sign credential and sign raw data Signed-off-by: Krishna Waske --------- Signed-off-by: Ankita Patidar Signed-off-by: Krishna Waske Co-authored-by: Ankita Patidar Signed-off-by: Krishna Waske --- .../multi-tenancy/MultiTenancyController.ts | 94 ++++---- src/controllers/types.ts | 20 +- src/routes/routes.ts | 100 +++------ src/routes/swagger.json | 203 ++++++++---------- 4 files changed, 188 insertions(+), 229 deletions(-) diff --git a/src/controllers/multi-tenancy/MultiTenancyController.ts b/src/controllers/multi-tenancy/MultiTenancyController.ts index 1383c773..c79510c2 100644 --- a/src/controllers/multi-tenancy/MultiTenancyController.ts +++ b/src/controllers/multi-tenancy/MultiTenancyController.ts @@ -1918,37 +1918,6 @@ export class MultiTenancyController extends Controller { } } - - /** - * Sign data using a key - * - * @param tenantId Tenant identifier - * @param request Sign options - * data - Data has to be in base64 format - * publicKeyBase58 - Public key in base58 format - * @returns Signature in base64 format - */ - @Security('apiKey') - @Post('/sign/:tenantId') - public async sign(@Path('tenantId') tenantId: string, @Body() request: SignDataOptions) { - try { - const signature = await this.agent.modules.tenants.withTenantAgent({ tenantId }, async (tenantAgent) => { - // assertAskarWallet(tenantAgent.context.wallet) - - // tenantAgent.w3cCredentials - - const signature = await tenantAgent.context.wallet.sign({ - data: TypedArrayEncoder.fromBase64(request.data), - key: Key.fromPublicKeyBase58(request.publicKeyBase58, request.keyType), - }) - return TypedArrayEncoder.toBase64(signature) - }) - return signature - } catch (error) { - throw ErrorHandlingService.handle(error) - } - } - /** * Verify data using a key * @@ -1983,21 +1952,66 @@ export class MultiTenancyController extends Controller { public async signCredential( @Path('tenantId') tenantId: string, @Query('storeCredential') storeCredential: boolean, - @Body() credentialToSign: W3cJsonLdSignCredentialOptions | any + @Query('dataTypeToSign') dataTypeToSign: 'rawData' | 'jsonLd', + @Body() data: CustomW3cJsonLdSignCredentialOptions | SignDataOptions | any ) { - let storedCredential - let formattedCredential try { - await this.agent.modules.tenants.withTenantAgent({ tenantId }, async (tenantAgent) => { - credentialToSign.format = ClaimFormat.LdpVc + return await this.agent.modules.tenants.withTenantAgent({ tenantId }, async (tenantAgent) => { + // JSON-LD VC Signing + if (dataTypeToSign === 'jsonLd') { + const credentialData = data as unknown as W3cJsonLdSignCredentialOptions + credentialData.format = ClaimFormat.LdpVc + + const signedCredential = await tenantAgent.w3cCredentials.signCredential(credentialData) as W3cJsonLdVerifiableCredential - const signedCred = await tenantAgent.w3cCredentials.signCredential(credentialToSign) as W3cJsonLdVerifiableCredential - formattedCredential = signedCred.toJson() if (storeCredential) { - storedCredential = await tenantAgent.w3cCredentials.storeCredential({ credential: signedCred }) + return await tenantAgent.w3cCredentials.storeCredential({ credential: signedCredential }) } + + return signedCredential.toJson() + } + + // Raw Data Signing + const rawData = data as SignDataOptions + + if (!rawData.data) throw new BadRequestError('Missing "data" for raw data signing.') + + const hasDidOrMethod = rawData.did || rawData.method + const hasPublicKey = rawData.publicKeyBase58 && rawData.keyType + + if (!hasDidOrMethod && !hasPublicKey) { + throw new BadRequestError('Either (did or method) OR (publicKeyBase58 and keyType) must be provided.') + } + + let keyToUse: Key + + if (hasDidOrMethod) { + const dids = await tenantAgent.dids.getCreatedDids({ + method: rawData.method || undefined, + did: rawData.did || undefined, + }) + + const verificationMethod = dids[0]?.didDocument?.verificationMethod?.[0]?.publicKeyBase58 + if (!verificationMethod) { + throw new BadRequestError('No publicKeyBase58 found for the given DID or method.') + } + + keyToUse = Key.fromPublicKeyBase58(verificationMethod, rawData.keyType) + } else { + keyToUse = Key.fromPublicKeyBase58(rawData.publicKeyBase58, rawData.keyType) + } + + if (!keyToUse) { + throw new Error('Unable to construct signing key.') + } + + const signature = await tenantAgent.context.wallet.sign({ + data: TypedArrayEncoder.fromBase64(rawData.data), + key: keyToUse, + }) + + return TypedArrayEncoder.toBase64(signature) }) - return storedCredential ?? formattedCredential } catch (error) { throw ErrorHandlingService.handle(error) } diff --git a/src/controllers/types.ts b/src/controllers/types.ts index f3acb079..227d94a0 100644 --- a/src/controllers/types.ts +++ b/src/controllers/types.ts @@ -28,6 +28,9 @@ import type { JsonObject, W3cJsonLdVerifyCredentialOptions, DataIntegrityProofOptions, + W3cJsonLdSignCredentialOptions, + W3cCredential, + W3cCredentialSubject, } from '@credo-ts/core' import type { SingleOrArray } from '@credo-ts/core/build/utils' import type { DIDDocument } from 'did-resolver' @@ -394,6 +397,8 @@ export type SignDataOptions = { data: string keyType: KeyType publicKeyBase58: string + did?: string + method?: string } export type VerifyDataOptions = { @@ -418,4 +423,17 @@ export interface credentialPayloadToSign { export interface SafeW3cJsonLdVerifyCredentialOptions extends W3cJsonLdVerifyCredentialOptions { // Ommited due to issues with TSOA proof: SingleOrArray | DataIntegrityProofOptions> -} \ No newline at end of file +} + +export type ExtensibleW3cCredentialSubject = W3cCredentialSubject & { + [key: string]: unknown +} + +export type ExtensibleW3cCredential = W3cCredential & { + [key: string]: unknown + credentialSubject: SingleOrArray +} + +export type CustomW3cJsonLdSignCredentialOptions = Omit & { + [key: string]: unknown +} diff --git a/src/routes/routes.ts b/src/routes/routes.ts index c2294d13..68fbc8c9 100644 --- a/src/routes/routes.ts +++ b/src/routes/routes.ts @@ -693,29 +693,14 @@ const models: TsoaRoute.Models = { "type": {"dataType":"nestedObjectLiteral","nestedProperties":{"content":{"dataType":"string","required":true}},"validators":{}}, }, // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "SignDataOptions": { - "dataType": "refAlias", - "type": {"dataType":"nestedObjectLiteral","nestedProperties":{"publicKeyBase58":{"dataType":"string","required":true},"keyType":{"ref":"KeyType","required":true},"data":{"dataType":"string","required":true}},"validators":{}}, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa "VerifyDataOptions": { "dataType": "refAlias", "type": {"dataType":"nestedObjectLiteral","nestedProperties":{"signature":{"dataType":"string","required":true},"publicKeyBase58":{"dataType":"string","required":true},"keyType":{"ref":"KeyType","required":true},"data":{"dataType":"string","required":true}},"validators":{}}, }, // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "ClaimFormat.LdpVc": { - "dataType": "refEnum", - "enums": ["ldp_vc"], - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "ProofPurpose": { + "W3cCredentialRecord": { "dataType": "refAlias", - "type": {"dataType":"any","validators":{}}, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "ClaimFormat": { - "dataType": "refEnum", - "enums": ["jwt","jwt_vc","jwt_vp","ldp","ldp_vc","ldp_vp","di","di_vc","di_vp","vc+sd-jwt"], + "type": {"ref":"Record_string.unknown_","validators":{}}, }, // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa "W3cIssuer": { @@ -779,22 +764,29 @@ const models: TsoaRoute.Models = { "additionalProperties": false, }, // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "W3cJsonLdSignCredentialOptions": { - "dataType": "refObject", - "properties": { - "format": {"ref":"ClaimFormat.LdpVc","required":true}, - "credential": {"ref":"W3cCredential","required":true}, - "verificationMethod": {"dataType":"string","required":true}, - "proofType": {"dataType":"string","required":true}, - "proofPurpose": {"ref":"ProofPurpose"}, - "created": {"dataType":"string"}, - }, - "additionalProperties": false, + "Pick_W3cJsonLdSignCredentialOptions.Exclude_keyofW3cJsonLdSignCredentialOptions.format__": { + "dataType": "refAlias", + "type": {"dataType":"nestedObjectLiteral","nestedProperties":{"credential":{"ref":"W3cCredential","required":true},"proofType":{"dataType":"string","required":true},"proofPurpose":{"dataType":"any"},"created":{"dataType":"string"},"verificationMethod":{"dataType":"string","required":true}},"validators":{}}, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "Omit_W3cJsonLdSignCredentialOptions.format_": { + "dataType": "refAlias", + "type": {"ref":"Pick_W3cJsonLdSignCredentialOptions.Exclude_keyofW3cJsonLdSignCredentialOptions.format__","validators":{}}, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "CustomW3cJsonLdSignCredentialOptions": { + "dataType": "refAlias", + "type": {"dataType":"intersection","subSchemas":[{"ref":"Omit_W3cJsonLdSignCredentialOptions.format_"},{"dataType":"nestedObjectLiteral","nestedProperties":{},"additionalProperties":{"dataType":"any"}}],"validators":{}}, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "SignDataOptions": { + "dataType": "refAlias", + "type": {"dataType":"nestedObjectLiteral","nestedProperties":{"method":{"dataType":"string"},"did":{"dataType":"string"},"publicKeyBase58":{"dataType":"string","required":true},"keyType":{"ref":"KeyType","required":true},"data":{"dataType":"string","required":true}},"validators":{}}, }, // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa "Pick_LinkedDataProofOptions.Exclude_keyofLinkedDataProofOptions.cryptosuite__": { "dataType": "refAlias", - "type": {"dataType":"nestedObjectLiteral","nestedProperties":{"type":{"dataType":"string","required":true},"proofPurpose":{"dataType":"string","required":true},"verificationMethod":{"dataType":"string","required":true},"created":{"dataType":"string","required":true},"domain":{"dataType":"string"},"challenge":{"dataType":"string"},"jws":{"dataType":"string"},"proofValue":{"dataType":"string"},"nonce":{"dataType":"string"}},"validators":{}}, + "type": {"dataType":"nestedObjectLiteral","nestedProperties":{"proofPurpose":{"dataType":"string","required":true},"created":{"dataType":"string","required":true},"verificationMethod":{"dataType":"string","required":true},"type":{"dataType":"string","required":true},"domain":{"dataType":"string"},"challenge":{"dataType":"string"},"jws":{"dataType":"string"},"proofValue":{"dataType":"string"},"nonce":{"dataType":"string"}},"validators":{}}, }, // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa "Omit_LinkedDataProofOptions.cryptosuite_": { @@ -881,6 +873,11 @@ const models: TsoaRoute.Models = { "additionalProperties": false, }, // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + "ProofPurpose": { + "dataType": "refAlias", + "type": {"dataType":"any","validators":{}}, + }, + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa "SafeW3cJsonLdVerifyCredentialOptions": { "dataType": "refObject", "properties": { @@ -1170,11 +1167,6 @@ const models: TsoaRoute.Models = { "enums": ["issuer","holder"], }, // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "W3cCredentialRecord": { - "dataType": "refAlias", - "type": {"ref":"Record_string.unknown_","validators":{}}, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa "CredentialExchangeRecord": { "dataType": "refAlias", "type": {"ref":"Record_string.unknown_","validators":{}}, @@ -3745,43 +3737,6 @@ export function RegisterRoutes(app: Router) { } }); // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.post('/multi-tenancy/sign/:tenantId', - authenticateMiddleware([{"apiKey":[]}]), - ...(fetchMiddlewares(MultiTenancyController)), - ...(fetchMiddlewares(MultiTenancyController.prototype.sign)), - - async function MultiTenancyController_sign(request: ExRequest, response: ExResponse, next: any) { - const args: Record = { - tenantId: {"in":"path","name":"tenantId","required":true,"dataType":"string"}, - request: {"in":"body","name":"request","required":true,"ref":"SignDataOptions"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = templateService.getValidatedArgs({ args, request, response }); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(MultiTenancyController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - await templateService.apiHandler({ - methodName: 'sign', - controller, - response, - next, - validatedArgs, - successStatus: undefined, - }); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa app.post('/multi-tenancy/verify/:tenantId', authenticateMiddleware([{"apiKey":[]}]), ...(fetchMiddlewares(MultiTenancyController)), @@ -3828,7 +3783,8 @@ export function RegisterRoutes(app: Router) { const args: Record = { tenantId: {"in":"path","name":"tenantId","required":true,"dataType":"string"}, storeCredential: {"in":"query","name":"storeCredential","required":true,"dataType":"boolean"}, - credentialToSign: {"in":"body","name":"credentialToSign","required":true,"dataType":"union","subSchemas":[{"ref":"W3cJsonLdSignCredentialOptions"},{"dataType":"any"}]}, + dataTypeToSign: {"in":"query","name":"dataTypeToSign","required":true,"dataType":"union","subSchemas":[{"dataType":"enum","enums":["rawData"]},{"dataType":"enum","enums":["jsonLd"]}]}, + data: {"in":"body","name":"data","required":true,"dataType":"union","subSchemas":[{"ref":"CustomW3cJsonLdSignCredentialOptions"},{"ref":"SignDataOptions"},{"dataType":"any"}]}, }; // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa diff --git a/src/routes/swagger.json b/src/routes/swagger.json index c872bd20..d22382dd 100644 --- a/src/routes/swagger.json +++ b/src/routes/swagger.json @@ -1625,25 +1625,6 @@ "type": "object", "description": "Construct a type with a set of properties K of type T" }, - "SignDataOptions": { - "properties": { - "publicKeyBase58": { - "type": "string" - }, - "keyType": { - "$ref": "#/components/schemas/KeyType" - }, - "data": { - "type": "string" - } - }, - "required": [ - "publicKeyBase58", - "keyType", - "data" - ], - "type": "object" - }, "VerifyDataOptions": { "properties": { "signature": { @@ -1667,28 +1648,8 @@ ], "type": "object" }, - "ClaimFormat.LdpVc": { - "enum": [ - "ldp_vc" - ], - "type": "string" - }, - "ProofPurpose": {}, - "ClaimFormat": { - "description": "Defines the claim format based on the formats registered in\n[DIF Claim Format Registry](https://identity.foundation/claim-format-registry/).", - "enum": [ - "jwt", - "jwt_vc", - "jwt_vp", - "ldp", - "ldp_vc", - "ldp_vp", - "di", - "di_vc", - "di_vp", - "vc+sd-jwt" - ], - "type": "string" + "W3cCredentialRecord": { + "$ref": "#/components/schemas/Record_string.unknown_" }, "W3cIssuer": { "properties": { @@ -1832,52 +1793,86 @@ "type": "object", "additionalProperties": false }, - "W3cJsonLdSignCredentialOptions": { + "Pick_W3cJsonLdSignCredentialOptions.Exclude_keyofW3cJsonLdSignCredentialOptions.format__": { "properties": { - "format": { - "$ref": "#/components/schemas/ClaimFormat.LdpVc", - "description": "The format of the credential to be signed. Must be either `jwt_vc` or `ldp_vc`." - }, "credential": { "$ref": "#/components/schemas/W3cCredential", "description": "The credential to be signed." }, - "verificationMethod": { - "type": "string", - "description": "URI of the verificationMethod to be used for signing the credential.\n\nMust be a valid did url pointing to a key." - }, "proofType": { "type": "string", "description": "The proofType to be used for signing the credential.\n\nMust be a valid Linked Data Signature suite." }, - "proofPurpose": { - "$ref": "#/components/schemas/ProofPurpose" - }, + "proofPurpose": {}, "created": { "type": "string" + }, + "verificationMethod": { + "type": "string", + "description": "URI of the verificationMethod to be used for signing the credential.\n\nMust be a valid did url pointing to a key." } }, "required": [ - "format", "credential", - "verificationMethod", - "proofType" + "proofType", + "verificationMethod" ], "type": "object", - "additionalProperties": false + "description": "From T, pick a set of properties whose keys are in the union K" }, - "Pick_LinkedDataProofOptions.Exclude_keyofLinkedDataProofOptions.cryptosuite__": { + "Omit_W3cJsonLdSignCredentialOptions.format_": { + "$ref": "#/components/schemas/Pick_W3cJsonLdSignCredentialOptions.Exclude_keyofW3cJsonLdSignCredentialOptions.format__", + "description": "Construct a type with the properties of T except for those in type K." + }, + "CustomW3cJsonLdSignCredentialOptions": { + "allOf": [ + { + "$ref": "#/components/schemas/Omit_W3cJsonLdSignCredentialOptions.format_" + }, + { + "properties": {}, + "additionalProperties": {}, + "type": "object" + } + ] + }, + "SignDataOptions": { "properties": { - "type": { + "method": { "type": "string" }, + "did": { + "type": "string" + }, + "publicKeyBase58": { + "type": "string" + }, + "keyType": { + "$ref": "#/components/schemas/KeyType" + }, + "data": { + "type": "string" + } + }, + "required": [ + "publicKeyBase58", + "keyType", + "data" + ], + "type": "object" + }, + "Pick_LinkedDataProofOptions.Exclude_keyofLinkedDataProofOptions.cryptosuite__": { + "properties": { "proofPurpose": { "type": "string" }, + "created": { + "type": "string" + }, "verificationMethod": { "type": "string" }, - "created": { + "type": { "type": "string" }, "domain": { @@ -1897,10 +1892,10 @@ } }, "required": [ - "type", "proofPurpose", + "created", "verificationMethod", - "created" + "type" ], "type": "object", "description": "From T, pick a set of properties whose keys are in the union K" @@ -2158,6 +2153,7 @@ "type": "object", "additionalProperties": false }, + "ProofPurpose": {}, "SafeW3cJsonLdVerifyCredentialOptions": { "properties": { "credential": { @@ -2826,9 +2822,6 @@ ], "type": "string" }, - "W3cCredentialRecord": { - "$ref": "#/components/schemas/Record_string.unknown_" - }, "CredentialExchangeRecord": { "$ref": "#/components/schemas/Record_string.unknown_" }, @@ -6892,55 +6885,6 @@ } } }, - "/multi-tenancy/sign/{tenantId}": { - "post": { - "operationId": "Sign", - "responses": { - "200": { - "description": "Signature in base64 format", - "content": { - "application/json": { - "schema": { - "type": "string" - } - } - } - } - }, - "description": "Sign data using a key", - "tags": [ - "MultiTenancy" - ], - "security": [ - { - "apiKey": [] - } - ], - "parameters": [ - { - "description": "Tenant identifier", - "in": "path", - "name": "tenantId", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "description": "Sign options\ndata - Data has to be in base64 format\npublicKeyBase58 - Public key in base58 format", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SignDataOptions", - "description": "Sign options\ndata - Data has to be in base64 format\npublicKeyBase58 - Public key in base58 format" - } - } - } - } - } - }, "/multi-tenancy/verify/{tenantId}": { "post": { "operationId": "Verify", @@ -6998,7 +6942,19 @@ "description": "Ok", "content": { "application/json": { - "schema": {} + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "$ref": "#/components/schemas/Record_string.any_" + }, + { + "$ref": "#/components/schemas/W3cCredentialRecord" + } + ] + } } } } @@ -7027,6 +6983,18 @@ "schema": { "type": "boolean" } + }, + { + "in": "query", + "name": "dataTypeToSign", + "required": true, + "schema": { + "type": "string", + "enum": [ + "rawData", + "jsonLd" + ] + } } ], "requestBody": { @@ -7036,7 +7004,10 @@ "schema": { "anyOf": [ { - "$ref": "#/components/schemas/W3cJsonLdSignCredentialOptions" + "$ref": "#/components/schemas/CustomW3cJsonLdSignCredentialOptions" + }, + { + "$ref": "#/components/schemas/SignDataOptions" }, {} ] From 96f5ff0ef7fcdb6295b4bd051764a1eea96cceb5 Mon Sep 17 00:00:00 2001 From: Krishna Waske Date: Fri, 13 Jun 2025 16:34:58 +0530 Subject: [PATCH 15/15] chore: fix imports (#275) Signed-off-by: Krishna Waske --- src/controllers/multi-tenancy/MultiTenancyController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/multi-tenancy/MultiTenancyController.ts b/src/controllers/multi-tenancy/MultiTenancyController.ts index c79510c2..551d5258 100644 --- a/src/controllers/multi-tenancy/MultiTenancyController.ts +++ b/src/controllers/multi-tenancy/MultiTenancyController.ts @@ -1,7 +1,7 @@ /* eslint-disable prettier/prettier */ import type { RestAgentModules, RestMultiTenantAgentModules } from '../../cliAgent' import type { Version } from '../examples' -import type { RecipientKeyOption, SafeW3cJsonLdVerifyCredentialOptions, SchemaMetadata } from '../types' +import type { CustomW3cJsonLdSignCredentialOptions, RecipientKeyOption, SafeW3cJsonLdVerifyCredentialOptions, SchemaMetadata } from '../types' import type { PolygonDidCreateOptions } from '@ayanworks/credo-polygon-w3c-module/build/dids' import type { AcceptProofRequestOptions,