diff --git a/.deploy/SSL2.yaml b/.deploy/SSL2.yaml new file mode 100644 index 00000000..7c48333d --- /dev/null +++ b/.deploy/SSL2.yaml @@ -0,0 +1,11 @@ +# secret.yaml +apiVersion: v1 +kind: Secret + +metadata: + name: entity-ssl-test + namespace: hypermine-development +type: kubernetes.io/tls +stringData: + tls.key: "" + tls.crt: "" diff --git a/.deploy/cert2.yaml b/.deploy/cert2.yaml new file mode 100644 index 00000000..c9472a05 --- /dev/null +++ b/.deploy/cert2.yaml @@ -0,0 +1,13 @@ +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: entity-ssl-test + namespace: hypermine-development +spec: + dnsNames: + - api.entity-test.hypersign.id + - "*.api.entity-test.hypersign.id" + issuerRef: + kind: Issuer + name: letsencrypt-production + secretName: entity-ssl-test diff --git a/.deploy/deployment.yaml b/.deploy/deployment.yaml index 8f49c0d1..13cdfc7b 100644 --- a/.deploy/deployment.yaml +++ b/.deploy/deployment.yaml @@ -1,4 +1,3 @@ ---- apiVersion: apps/v1 kind: Deployment metadata: @@ -16,50 +15,63 @@ spec: app: entity-api spec: containers: - - name: entity-api - image: __GOOGLE_ARTIFACT_URL__/__GOOGLE_PROJECT_ID__/__GOOGLE_ARTIFACT_REPO__/enity-api-service:__LATEST_RELEASE_TAG__ - imagePullPolicy: Always + - name: entity-api + image: __GOOGLE_ARTIFACT_URL__/__GOOGLE_PROJECT_ID__/__GOOGLE_ARTIFACT_REPO__/enity-api-service:__LATEST_RELEASE_TAG__ + imagePullPolicy: Always + livenessProbe: + httpGet: + path: /api/v1/edv/state + port: 3001 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 - resources: - limits: - memory: "1Gi" - cpu: "1000m" - ports: - - containerPort: __PORT__ - env: - - name: PORT - value: "__PORT__" - - name: BASE_DB_PATH - value: __BASE_DB_PATH__ - - name: DB_CONFIG - value: __DB_CONFIG__ - - name: HID_NETWORK_RPC - value: __HID_NETWORK_RPC__ - - name: HID_NETWORK_API - value: __HID_NETWORK_API__ - - name: HID_NETWORK_NAMESPACE - value: __HID_NETWORK_NAMESPACE__ - - name: EDV_BASE_URL - value: __EDV_BASE_URL__ - - name: EDV_CONFIG_DIR - value: __EDV_CONFIG_DIR__ - - name: EDV_DID_FILE_PATH - value: __EDV_DID_FILE_PATH__ - - name: EDV_KEY_FILE_PATH - value: __EDV_KEY_FILE_PATH__ - - name: MNEMONIC - value: __MNEMONIC__ - - name: JWT_SECRET - value: __JWT_SECRET__ - - name: WHITELISTED_CORS - value: "['https://entity.hypersign.id','https://api.entity.hypersign.id','https://wallet-prajna.hypersign.id']" - volumeMounts: - - name: mongo - mountPath: "/data" - volumes: + resources: + limits: + memory: "2Gi" + cpu: "1000m" + ports: + - containerPort: __PORT__ + env: + - name: PORT + value: "__PORT__" + - name: BASE_DB_PATH + value: __BASE_DB_PATH__ + - name: DB_CONFIG + value: __DB_CONFIG__ + - name: HID_NETWORK_RPC + value: __HID_NETWORK_RPC__ + - name: HID_NETWORK_API + value: __HID_NETWORK_API__ + - name: HID_NETWORK_NAMESPACE + value: __HID_NETWORK_NAMESPACE__ + - name: EDV_BASE_URL + value: __EDV_BASE_URL__ + - name: EDV_CONFIG_DIR + value: __EDV_CONFIG_DIR__ + - name: EDV_DID_FILE_PATH + value: __EDV_DID_FILE_PATH__ + - name: EDV_KEY_FILE_PATH + value: __EDV_KEY_FILE_PATH__ + - name: MNEMONIC + value: __MNEMONIC__ + - name: JWT_SECRET + value: __JWT_SECRET__ + - name: GLOBAL_TXN_CONTROLLER_QUEUE + value: __GLOBAL_TXN_CONTROLLER_QUEUE__ + - name: RABBIT_MQ_URI + value: __RABBIT_MQ_URI__ + - name: VAULT_PREFIX + value: __VAULT_PREFIX__ + - name: WHITELISTED_CORS + value: "['https://entity.hypersign.id','https://api.entity.hypersign.id','https://api.entity-test.hypersign.id','https://wallet-prajna.hypersign.id']" + volumeMounts: - name: mongo - secret: - secretName: mongo + mountPath: "/data" + volumes: + - name: mongo + secret: + secretName: mongo --- apiVersion: v1 kind: Service @@ -74,9 +86,9 @@ spec: selector: app: entity-api ports: - - port: __PORT__ - targetPort: __PORT__ - protocol: TCP + - port: __PORT__ + targetPort: __PORT__ + protocol: TCP # --- # apiVersion: apps/v1 # kind: Deployment @@ -122,3 +134,6 @@ spec: # - port: 8080 # targetPort: 8080 # protocol: TCP + + + diff --git a/.deploy/hpa.yaml b/.deploy/hpa.yaml new file mode 100644 index 00000000..68d1dde1 --- /dev/null +++ b/.deploy/hpa.yaml @@ -0,0 +1,25 @@ +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: entity-api + namespace: hypermine-development +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: entity-api + minReplicas: 1 + maxReplicas: 5 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 70 + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: 70 diff --git a/.deploy/ingress2.yaml b/.deploy/ingress2.yaml new file mode 100644 index 00000000..5f4a9c38 --- /dev/null +++ b/.deploy/ingress2.yaml @@ -0,0 +1,70 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: entity-ingress-test + namespace: hypermine-development + annotations: + kubernetes.io/ingress.allow-http: "false" + kubernetes.io/force-ssl-redirect: redirect + ingressClassName: "gce" + kubernetes.io/ingress.global-static-ip-name: entity-ip-test + cert-manager.io/issuer: letsencrypt-production + labels: + name: ingress + +spec: + tls: + - secretName: entity-ssl-test + hosts: + - "api.entity-test.hypersign.id" + - "*.api.entity-test.hypersign.id" + + rules: + - host: "api.entity-test.hypersign.id" + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: entity-api-test-service + port: + number: 3001 + - path: /ssi/ + pathType: Prefix + backend: + service: + name: entity-api-test-service + port: + number: 3001 + - path: /api/ + pathType: Prefix + backend: + service: + name: entity-api-test-service + port: + number: 3001 + - host: "*.api.entity-test.hypersign.id" + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: entity-api-test-service + port: + number: 3001 + - path: /ssi/ + pathType: Prefix + backend: + service: + name: entity-api-test-service + port: + number: 3001 + - path: /api/ + pathType: Prefix + backend: + service: + name: entity-api-test-service + port: + number: 3001 diff --git a/.github/workflows/CI-CD.yaml b/.github/workflows/CI-CD.yaml index a0c3ce29..d5650ee6 100644 --- a/.github/workflows/CI-CD.yaml +++ b/.github/workflows/CI-CD.yaml @@ -82,36 +82,42 @@ jobs: - name: "Configure kubectl" run: gcloud container clusters get-credentials hypermine-gke --region=asia-south1 - name: Replace tags - run: find .deploy/deployment.yaml -type f -exec sed -i -e "s#__LATEST_RELEASE_TAG__#${{ env.LATEST_RELEASE_TAG }}#" {} \; + run: find .deploy/deployment2.yaml -type f -exec sed -i -e "s#__LATEST_RELEASE_TAG__#${{ env.LATEST_RELEASE_TAG }}#" {} \; - name: "Replace secrets" - run: find .deploy/deployment.yaml -type f -exec sed -i ''s/__PORT__/${{ secrets.PORT }}/g'' {} \; + run: find .deploy/deployment2.yaml -type f -exec sed -i ''s/__PORT__/${{ secrets.PORT }}/g'' {} \; - name: "Replace secrets" - run: find .deploy/deployment.yaml -type f -exec sed -i -e "s#__BASE_DB_PATH__#${{ secrets.BASE_DB_PATH }}#" {} \; + run: find .deploy/deployment2.yaml -type f -exec sed -i -e "s#__BASE_DB_PATH__#${{ secrets.BASE_DB_PATH }}#" {} \; - name: "Replace secrets" - run: find .deploy/deployment.yaml -type f -exec sed -i -e "s#__DB_CONFIG__#${{ secrets.DB_CONFIG }}#" {} \; + run: find .deploy/deployment2.yaml -type f -exec sed -i -e "s#__DB_CONFIG__#${{ secrets.DB_CONFIG }}#" {} \; - name: "Replace secrets" - run: find .deploy/deployment.yaml -type f -exec sed -i -e "s#__HID_NETWORK_RPC__#${{ secrets.HID_NETWORK_RPC }}#" {} \; + run: find .deploy/deployment2.yaml -type f -exec sed -i -e "s#__HID_NETWORK_RPC__#${{ secrets.HID_NETWORK_RPC }}#" {} \; - name: "Replace secrets" - run: find .deploy/deployment.yaml -type f -exec sed -i -e "s#__HID_NETWORK_API__#${{ secrets.HID_NETWORK_API }}#" {} \; + run: find .deploy/deployment2.yaml -type f -exec sed -i -e "s#__HID_NETWORK_API__#${{ secrets.HID_NETWORK_API }}#" {} \; - name: "Replace secrets" - run: find .deploy/deployment.yaml -type f -exec sed -i -e "s#__HID_NETWORK_NAMESPACE__#${{ secrets.HID_NETWORK_NAMESPACE }}#" {} \; + run: find .deploy/deployment2.yaml -type f -exec sed -i -e "s#__HID_NETWORK_NAMESPACE__#${{ secrets.HID_NETWORK_NAMESPACE }}#" {} \; - name: "Replace secrets" - run: find .deploy/deployment.yaml -type f -exec sed -i -e "s#__EDV_BASE_URL__#${{ secrets.EDV_BASE_URL }}#" {} \; + run: find .deploy/deployment2.yaml -type f -exec sed -i -e "s#__EDV_BASE_URL__#${{ secrets.EDV_BASE_URL }}#" {} \; - name: "Replace secrets" - run: find .deploy/deployment.yaml -type f -exec sed -i -e "s#__EDV_CONFIG_DIR__#${{ secrets.EDV_CONFIG_DIR }}#" {} \; + run: find .deploy/deployment2.yaml -type f -exec sed -i -e "s#__EDV_CONFIG_DIR__#${{ secrets.EDV_CONFIG_DIR }}#" {} \; - name: "Replace secrets" - run: find .deploy/deployment.yaml -type f -exec sed -i -e "s#__EDV_DID_FILE_PATH__#${{ secrets.EDV_DID_FILE_PATH }}#" {} \; + run: find .deploy/deployment2.yaml -type f -exec sed -i -e "s#__EDV_DID_FILE_PATH__#${{ secrets.EDV_DID_FILE_PATH }}#" {} \; - name: "Replace secrets" - run: find .deploy/deployment.yaml -type f -exec sed -i -e "s#__EDV_KEY_FILE_PATH__#${{ secrets.EDV_KEY_FILE_PATH }}#" {} \; + run: find .deploy/deployment2.yaml -type f -exec sed -i -e "s#__EDV_KEY_FILE_PATH__#${{ secrets.EDV_KEY_FILE_PATH }}#" {} \; - name: "Replace secrets" - run: find .deploy/deployment.yaml -type f -exec sed -i -e "s#__MNEMONIC__#${{ secrets.MNEMONIC }}#" {} \; + run: find .deploy/deployment2.yaml -type f -exec sed -i -e "s#__GLOBAL_TXN_CONTROLLER_QUEUE__#${{ secrets.GLOBAL_TXN_CONTROLLER_QUEUE }}#" {} \; - name: "Replace secrets" - run: find .deploy/deployment.yaml -type f -exec sed -i -e "s#__JWT_SECRET__#${{ secrets.JWT_SECRET }}#" {} \; + run: find .deploy/deployment2.yaml -type f -exec sed -i -e "s#__RABBIT_MQ_URI__#${{ secrets.RABBIT_MQ_URI }}#" {} \; - name: "Replace secrets" - run: find .deploy/deployment.yaml -type f -exec sed -i ''s/__GOOGLE_ARTIFACT_URL__/${{ secrets.GOOGLE_ARTIFACT_URL }}/g'' {} \; + run: find .deploy/deployment2.yaml -type f -exec sed -i -e "s#__VAULT_PREFIX__#${{ secrets.VAULT_PREFIX }}#" {} \; - name: "Replace secrets" - run: find .deploy/deployment.yaml -type f -exec sed -i ''s/__GOOGLE_ARTIFACT_REPO__/${{ secrets.GOOGLE_ARTIFACT_REPO }}/g'' {} \; + run: find .deploy/deployment2.yaml -type f -exec sed -i -e "s#__MNEMONIC__#${{ secrets.MNEMONIC }}#" {} \; - name: "Replace secrets" - run: find .deploy/deployment.yaml -type f -exec sed -i ''s/__GOOGLE_PROJECT_ID__/${{ secrets.GOOGLE_PROJECT_ID }}/g'' {} \; + run: find .deploy/deployment2.yaml -type f -exec sed -i -e "s#__JWT_SECRET__#${{ secrets.JWT_SECRET }}#" {} \; + - name: "Replace secrets" + run: find .deploy/deployment2.yaml -type f -exec sed -i ''s/__GOOGLE_ARTIFACT_URL__/${{ secrets.GOOGLE_ARTIFACT_URL }}/g'' {} \; + - name: "Replace secrets" + run: find .deploy/deployment2.yaml -type f -exec sed -i ''s/__GOOGLE_ARTIFACT_REPO__/${{ secrets.GOOGLE_ARTIFACT_REPO }}/g'' {} \; + - name: "Replace secrets" + run: find .deploy/deployment2.yaml -type f -exec sed -i ''s/__GOOGLE_PROJECT_ID__/${{ secrets.GOOGLE_PROJECT_ID }}/g'' {} \; - name: "Deploy to GKE" run: kubectl apply -f .deploy/deployment.yaml diff --git a/Dockerfile b/Dockerfile index 05f26073..329d9d82 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,13 @@ -FROM node:16 +FROM node:18 +RUN npm install -g npm@latest WORKDIR /usr/src/app COPY ./package.json . +RUN npx patch-package -y + COPY ./tsconfig.json . + +ENV NODE_OPTIONS="--openssl-legacy-provider --max-old-space-size=4096" + RUN npm install COPY . . RUN npm run build diff --git a/package.json b/package.json index 0616e397..1778a7d8 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,8 @@ "@nestjs/passport": "^9.0.0", "@nestjs/platform-express": "^9.0.0", "@nestjs/swagger": "^6.1.4", + "amqp-connection-manager": "^4.1.14", + "amqplib": "^0.10.4", "argon2": "^0.30.3", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", @@ -42,12 +44,13 @@ "fs": "^0.0.1-security", "hid-hd-wallet": "git+https://github.com/hypersign-protocol/hid-hd-wallet.git#main", "hs-ssi-sdk": "github:hypersign-protocol/hid-ssi-js-sdk#testcase/bjj", - "hypersign-edv-client": "github:hypersign-protocol/hypersign-edv-client#develop", + "hypersign-edv-client": "github:hypersign-protocol/hypersign-edv-client#deleteByDocumentId", "idb-keyval": "^6.2.1", "mongoose": "^6.8.3", "passport": "^0.6.0", "passport-jwt": "^4.0.1", "passport-local": "^1.0.0", + "patch-package": "^8.0.0", "readline-sync": "^1.4.10", "reflect-metadata": "^0.1.13", "rxjs": "^7.2.0", diff --git a/src/app.module.ts b/src/app.module.ts index e996bd16..bb649722 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -7,6 +7,7 @@ import { DidModule } from './did/did.module'; import { SchemaModule } from './schema/schema.module'; import { CredentialModule } from './credential/credential.module'; import { PresentationModule } from './presentation/presentation.module'; +import { TxSendModuleModule } from './tx-send-module/tx-send-module.module'; @Module({ imports: [ ConfigModule.forRoot({ @@ -18,6 +19,7 @@ import { PresentationModule } from './presentation/presentation.module'; SchemaModule, CredentialModule, PresentationModule, + TxSendModuleModule, ], controllers: [], providers: [{ provide: APP_FILTER, useClass: AllExceptionsFilter }], diff --git a/src/credential/credential.module.ts b/src/credential/credential.module.ts index 5cc59bfc..3f2641b3 100644 --- a/src/credential/credential.module.ts +++ b/src/credential/credential.module.ts @@ -16,9 +16,10 @@ import { WhitelistSSICorsMiddleware } from 'src/utils/middleware/cors.middleware import { TrimMiddleware } from 'src/utils/middleware/trim.middleware'; import { credentialProviders } from './providers/credential.provider'; import { databaseProviders } from '../mongoose/tenant-mongoose-connections'; +import { TxSendModuleModule } from 'src/tx-send-module/tx-send-module.module'; @Module({ - imports: [EdvModule, HidWalletModule, DidModule], + imports: [EdvModule, HidWalletModule, DidModule, TxSendModuleModule], controllers: [CredentialController], providers: [ CredentialService, diff --git a/src/credential/services/credential.service.ts b/src/credential/services/credential.service.ts index 529385e4..aa351241 100644 --- a/src/credential/services/credential.service.ts +++ b/src/credential/services/credential.service.ts @@ -15,6 +15,7 @@ import { HypersignDID, HypersignVerifiableCredential } from 'hs-ssi-sdk'; import { VerifyCredentialDto } from '../dto/verify-credential.dto'; import { RegisterCredentialStatusDto } from '../dto/register-credential.dto'; import { getAppVault, getAppMenemonic } from '../../utils/app-vault-service'; +import { TxSendModuleService } from 'src/tx-send-module/tx-send-module.service'; @Injectable() export class CredentialService { @@ -24,8 +25,28 @@ export class CredentialService { private readonly hidWallet: HidWalletService, private credentialRepository: CredentialRepository, private readonly didRepositiory: DidRepository, + private readonly txnService: TxSendModuleService, ) {} + async checkAllowence(address) { + const url = + this.config.get('HID_NETWORK_API') + + '/cosmos/feegrant/v1beta1/allowances/' + + address; + + const resp = await fetch(url); + + const res = await resp.json(); + if (resp.status === 200) { + if (res.allowances.length > 0) { + return true; + } else { + return false; + } + } + return false; + } + async create(createCredentialDto: CreateCredentialDto, appDetail) { Logger.log('create() method: starts....', 'CredentialService'); const { @@ -137,8 +158,20 @@ export class CredentialService { issuerDid, verificationMethodId, privateKeyMultibase, - registerCredential: registerCredentialStatus, + registerCredential: false, }); + + const credStatusTemp = {}; + Object.assign(credStatusTemp, credentialStatus); + + const credStatus = { + credentialStatus, + namespace: nameSpace, + } as RegisterCredentialStatusDto; + if (registerCredentialStatus) { + await this.registerCredentialStatus(credStatus, appDetail); + } + let edvData = undefined; if (persist) { const creedential = { @@ -180,7 +213,7 @@ export class CredentialService { return { credentialDocument: signedCredential, - credentialStatus, + credentialStatus: credStatusTemp, persist, }; } catch (e) { @@ -311,7 +344,7 @@ export class CredentialService { ? namespace : this.config.get('NETWORK') ? this.config.get('NETWORK') - : 'testnet'; + : namespace; const hypersignVC = await this.credentialSSIService.initateHypersignVC( appMenemonic, nameSpace, @@ -327,17 +360,46 @@ export class CredentialService { 'update() method: before calling hypersignVC.updateCredentialStatus to update cred status on chain', 'CredentialService', ); - const updatedCredResult = await hypersignVC.updateCredentialStatus({ - credentialStatus, - issuerDid, - verificationMethodId, - privateKeyMultibase, - status: statusChange, - statusReason, - }); + + const { wallet, address } = await this.hidWallet.generateWallet( + appMenemonic, + ); + let updatedCredResult; + if (await this.checkAllowence(address)) { + const updateCredenital: any = await hypersignVC.updateCredentialStatus({ + credentialStatus, + issuerDid, + verificationMethodId, + privateKeyMultibase, + status: statusChange, + statusReason, + readonly: true, + }); + + await this.txnService.sendUpdateVC( + updateCredenital?.credentialStatus, + updateCredenital?.proofValue, + appMenemonic, + ); + } else { + updatedCredResult = await hypersignVC.updateCredentialStatus({ + credentialStatus, + issuerDid, + verificationMethodId, + privateKeyMultibase, + status: statusChange, + statusReason, + readonly: false, + }); + } + await this.credentialRepository.findOneAndUpdate( { appId: appDetail.appId, credentialId: id }, - { transactionHash: updatedCredResult.transactionHash }, + { + transactionHash: updatedCredResult?.transactionHash + ? updatedCredResult?.transactionHash + : '', + }, ); Logger.log('update() method: ends....', 'CredentialService'); @@ -419,6 +481,7 @@ export class CredentialService { ); const { credentialStatus, namespace } = registerCredentialDto; + const credentialId = credentialStatus.id; const { kmsId } = appDetail; Logger.log( 'registerCredentialStatus() method: initialising edv service', @@ -427,20 +490,32 @@ export class CredentialService { let registeredVC: { transactionHash: string }; try { const appMenemonic = await getAppMenemonic(kmsId); - const hypersignVC = await this.credentialSSIService.initateHypersignVC( - appMenemonic, - namespace, - ); Logger.log( 'registerCredentialStatus() method: before calling hypersignVC.registerCredentialStatus to register credential status on chain', 'CredentialService', ); + const { proof } = credentialStatus; + delete credentialStatus['proof']; - registeredVC = await hypersignVC.registerCredentialStatus({ - credentialStatus, - credentialStatusProof: proof, - }); + + const { wallet, address } = await this.hidWallet.generateWallet( + appMenemonic, + ); + + const hypersignVC = await this.credentialSSIService.initateHypersignVC( + appMenemonic, + namespace, + ); + + if (await this.checkAllowence(address)) { + await this.txnService.sendVCTxn(credentialStatus, proof, appMenemonic); + } else { + registeredVC = await hypersignVC.registerCredentialStatus({ + credentialStatus, + credentialStatusProof: proof, + }); + } } catch (e) { Logger.error( `registerCredentialStatus() method: Error ${e.message}`, @@ -452,6 +527,6 @@ export class CredentialService { 'registerCredentialStatus() method: ends....', 'CredentialService', ); - return { transactionHash: registeredVC.transactionHash }; + return { transactionHash: registeredVC?.transactionHash }; } } diff --git a/src/credential/services/credential.ssi.service.ts b/src/credential/services/credential.ssi.service.ts index 91b68e85..742043bb 100644 --- a/src/credential/services/credential.ssi.service.ts +++ b/src/credential/services/credential.ssi.service.ts @@ -10,7 +10,7 @@ export class CredentialSSIService { private readonly config: ConfigService, private readonly hidWallet: HidWalletService, ) {} - async initateHypersignVC(mnemonic: string, namespace: string) { + async initateHypersignVC(mnemonic: string,namespace: string): Promise { Logger.log('InitateHypersignVC(): starts....', 'CredentialSSIService'); const nodeRpcEndpoint = this.config.get('HID_NETWORK_RPC'); const nodeRestEndpoint = this.config.get('HID_NETWORK_API'); diff --git a/src/did/did.module.ts b/src/did/did.module.ts index f029853b..588b5d41 100644 --- a/src/did/did.module.ts +++ b/src/did/did.module.ts @@ -23,8 +23,9 @@ import { TrimMiddleware } from 'src/utils/middleware/trim.middleware'; import { databaseProviders } from '../mongoose/tenant-mongoose-connections'; import { didProviders } from './providers/did.provider'; import { JwtStrategy } from '../utils/jwt.strategy'; +import { TxSendModuleModule } from 'src/tx-send-module/tx-send-module.module'; @Module({ - imports: [EdvModule, HidWalletModule], + imports: [EdvModule, HidWalletModule, TxSendModuleModule], controllers: [DidController], providers: [ JwtStrategy, diff --git a/src/did/repository/did.repository.ts b/src/did/repository/did.repository.ts index 645cc471..1d98a919 100644 --- a/src/did/repository/did.repository.ts +++ b/src/did/repository/did.repository.ts @@ -5,7 +5,6 @@ import { DidMetaData, } from '../schemas/did.schema'; import { FilterQuery, Model } from 'mongoose'; -import { InjectConnection, InjectModel } from '@nestjs/mongoose'; import { Inject, Injectable, Logger } from '@nestjs/common'; @Injectable() diff --git a/src/did/services/did.service.ts b/src/did/services/did.service.ts index 8557bbf6..b96c5552 100644 --- a/src/did/services/did.service.ts +++ b/src/did/services/did.service.ts @@ -32,7 +32,7 @@ import { getAppVault, getAppMenemonic } from '../../utils/app-vault-service'; import { ConfigService } from '@nestjs/config'; import { SignDidDto } from '../dto/sign-did.dto'; import { VerifyDidDto } from '../dto/verify-did.dto'; - +import { TxSendModuleService } from 'src/tx-send-module/tx-send-module.service'; @Injectable({ scope: Scope.REQUEST }) export class DidService { constructor( @@ -41,8 +41,28 @@ export class DidService { private readonly hidWallet: HidWalletService, private readonly didSSIService: DidSSIService, private readonly config: ConfigService, + private readonly txnService: TxSendModuleService, ) {} + async checkAllowence(address) { + const url = + this.config.get('HID_NETWORK_API') + + '/cosmos/feegrant/v1beta1/allowances/' + + address; + + const resp = await fetch(url); + + const res = await resp.json(); + if (resp.status === 200) { + if (res.allowances.length > 0) { + return true; + } else { + return false; + } + } + return false; + } + // TODO: need to fix this once ed25519 is finished. async createByClientSpec(createDidDto: CreateDidDto, appDetail) { Logger.log('createByClientSpec() method: starts....', 'DidService'); @@ -369,16 +389,38 @@ export class DidService { seed: seed, }); const regDidDocument = registerDidDto.didDocument as Did; + + Logger.log( + 'register() method: before calling hypersignDid.register ', + 'DidService', + ); + const didDocPreserved = {}; + Object.assign(didDocPreserved, didDocument); + const signInfos = await hypersignDid.createSignInfos({ + didDocument, + privateKeyMultibase, + verificationMethodId: verificationMethodId, + }); const params = { - didDocument: regDidDocument, + didDocument: didDocPreserved, privateKeyMultibase, verificationMethodId: verificationMethodId, }; - Logger.log( - 'register() method: before calling hypersignDid.register ', - 'DidService', + + const { wallet, address } = await this.hidWallet.generateWallet( + appMenemonic, ); - registerDidDoc = await hypersignDid.register(params); + if (await this.checkAllowence(address)) { + await this.txnService.sendDIDTxn( + didDocument, + signInfos, + verificationMethodId, + appMenemonic, + ); + } else { + registerDidDoc = await hypersignDid.register(params); + } + data = await this.didRepositiory.findOneAndUpdate( { did: didDocument['id'] }, { @@ -508,7 +550,7 @@ export class DidService { const mnemonic = await getAppMenemonic(kmsId); const hypersignDid = await this.didSSIService.initiateHypersignDid( mnemonic, - 'testnet', + this.config.get('NETWORK') ? this.config.get('NETWORK') : 'testnet', ); const didInfo = await this.didRepositiory.findOne({ @@ -516,8 +558,13 @@ export class DidService { did, }); const { signInfos } = updateDidDto; + console.log({ + signInfos, + didInfo, + }); + // If signature is passed then no need to check if it is present in db or not - if (!signInfos && (!didInfo || didInfo == null)) { + if (!signInfos && (!didInfo || didInfo == null || didInfo == undefined)) { throw new NotFoundException([ `${did} not found`, `${did} is not owned by the appId ${appDetail.appId}`, @@ -615,30 +662,67 @@ export class DidService { }); try { + const { wallet, address } = await this.hidWallet.generateWallet( + appMenemonic, + ); + if (!updateDidDto.deactivate) { Logger.debug( 'updateDid() method: before calling hypersignDid.update to update did', 'DidService', ); - updatedDid = await hypersignDid.update({ - didDocument: updateDidDto.didDocument as Did, - privateKeyMultibase, - verificationMethodId: resolvedDid['verificationMethod'][0].id, - versionId: updatedDidDocMetaData.versionId, - }); + if ((await this.checkAllowence(address)) == false) { + updatedDid = await hypersignDid.update({ + didDocument: updateDidDto.didDocument as Did, + privateKeyMultibase, + verificationMethodId: resolvedDid['verificationMethod'][0].id, + versionId: updatedDidDocMetaData.versionId, + readonly: false, + }); + } else { + updatedDid = await hypersignDid.update({ + didDocument: updateDidDto.didDocument as Did, + privateKeyMultibase, + verificationMethodId: resolvedDid['verificationMethod'][0].id, + versionId: updatedDidDocMetaData.versionId, + readonly: true, + }); + await this.txnService.sendDIDUpdate( + updatedDid.didDocument, + updatedDid.signInfos, + updatedDid.versionId, + appMenemonic, + ); + } } else { Logger.debug( 'updateDid() method: before calling hypersignDid.deactivate to deactivate did', 'DidService', ); - updatedDid = await hypersignDid.deactivate({ - didDocument: updateDidDto.didDocument as Did, - privateKeyMultibase, - verificationMethodId: resolvedDid['verificationMethod'][0].id, - versionId: updatedDidDocMetaData.versionId, - }); + if ((await this.checkAllowence(address)) == false) { + updatedDid = await hypersignDid.deactivate({ + didDocument: updateDidDto.didDocument as Did, + privateKeyMultibase, + verificationMethodId: resolvedDid['verificationMethod'][0].id, + versionId: updatedDidDocMetaData.versionId, + }); + } else { + updatedDid = await hypersignDid.update({ + didDocument: updateDidDto.didDocument as Did, + privateKeyMultibase, + verificationMethodId: resolvedDid['verificationMethod'][0].id, + versionId: updatedDidDocMetaData.versionId, + readonly: true, + }); + await this.txnService.sendDIDDeactivate( + updatedDid.didDocument, + updatedDid.signInfos, + updatedDid.versionId, + appMenemonic, + ); + } } } catch (error) { Logger.error( diff --git a/src/hid-wallet/hid-wallet.module.ts b/src/hid-wallet/hid-wallet.module.ts index 17903d22..f0afa284 100644 --- a/src/hid-wallet/hid-wallet.module.ts +++ b/src/hid-wallet/hid-wallet.module.ts @@ -3,5 +3,6 @@ import { HidWalletService } from './services/hid-wallet.service'; @Module({ controllers: [], providers: [HidWalletService], + exports: [HidWalletService], }) export class HidWalletModule {} diff --git a/src/hid-wallet/services/hid-wallet.service.ts b/src/hid-wallet/services/hid-wallet.service.ts index e5a74e64..33b1d024 100644 --- a/src/hid-wallet/services/hid-wallet.service.ts +++ b/src/hid-wallet/services/hid-wallet.service.ts @@ -11,6 +11,7 @@ export class HidWalletService { async generateWallet(mnemonic?: string): Promise<{ mnemonic: string; + wallet: DirectSecp256k1HdWallet; address: string; }> { Logger.log('generateWallet() method: starts....', 'generateWallet'); @@ -41,6 +42,7 @@ export class HidWalletService { this.mnemonic = generatedMnemonice; return { mnemonic: generatedMnemonice, + wallet: wallet, address: hidWalletAddress[0].address, }; } diff --git a/src/main.ts b/src/main.ts index 93b3bc0d..a935974f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -55,7 +55,25 @@ async function bootstrap() { mnemonic_EnglishMnemonic, ); - app.setGlobalPrefix('api/v1'); + app.setGlobalPrefix('api/v1/'); + + app.use((req, res, next) => { + Logger.debug({ edv_stats: process.env.EDV_STATUS }, '/api/v1/edv/state'); + if (req.path == '/api/v1/edv/state' && process.env.EDV_STATUS !== 'DOWN') { + return res.status(200).json({ + status: 200, + isEdvLive: true, + }); + } + if (req.path == '/api/v1/edv/state' && process.env.EDV_STATUS == 'DOWN') { + return res.status(502).json({ + status: 502, + isEdvLive: false, + }); + } + next(); + }); + if (!existDir(process.env.EDV_CONFIG_DIR)) { createDir(process.env.EDV_CONFIG_DIR); } @@ -83,8 +101,10 @@ async function bootstrap() { globalThis.kmsVault = kmsVault; Logger.log('After keymanager initialization', 'main'); + process.env.EDV_STATUS = 'UP'; } catch (e) { Logger.error('Could not initialize keymanager', 'main'); + process.env.EDV_STATUS = 'DOWN'; Logger.error(e); } @@ -126,5 +146,19 @@ async function bootstrap() { `Server running on http://localhost:${process.env.PORT}`, 'Bootstrap', ); + setInterval(async () => await checkEdv(), 120000); } + +async function checkEdv() { + try { + const resp = await fetch(process.env.EDV_BASE_URL + '/api'); + + if (resp.status == 200) { + process.env.EDV_STATUS = 'UP'; + } + } catch (error) { + process.env.EDV_STATUS = 'DOWN'; + } +} + bootstrap(); diff --git a/src/presentation/repository/presentation-template.repository.ts b/src/presentation/repository/presentation-template.repository.ts index 51ebd567..ce9bd0ba 100644 --- a/src/presentation/repository/presentation-template.repository.ts +++ b/src/presentation/repository/presentation-template.repository.ts @@ -4,7 +4,6 @@ import { } from '../schemas/presentation-template.schema'; import { FilterQuery, Model } from 'mongoose'; import { Inject, Injectable, Logger } from '@nestjs/common'; -import { InjectModel } from '@nestjs/mongoose'; @Injectable() export class PresentationTemplateRepository { diff --git a/src/schema/repository/schema.repository.ts b/src/schema/repository/schema.repository.ts index 2daa12ee..281438d1 100644 --- a/src/schema/repository/schema.repository.ts +++ b/src/schema/repository/schema.repository.ts @@ -1,6 +1,5 @@ import { Schemas, SchemaDocument } from '../schemas/schemas.schema'; import { FilterQuery, Model } from 'mongoose'; -import { InjectModel } from '@nestjs/mongoose'; import { Inject, Injectable, Logger } from '@nestjs/common'; @Injectable() diff --git a/src/schema/schema.module.ts b/src/schema/schema.module.ts index abaecc11..65e2bef2 100644 --- a/src/schema/schema.module.ts +++ b/src/schema/schema.module.ts @@ -15,9 +15,10 @@ import { WhitelistSSICorsMiddleware } from 'src/utils/middleware/cors.middleware import { TrimMiddleware } from 'src/utils/middleware/trim.middleware'; import { schemaProviders } from './providers/schema.provider'; import { databaseProviders } from '../mongoose/tenant-mongoose-connections'; +import { TxSendModuleModule } from 'src/tx-send-module/tx-send-module.module'; @Module({ - imports: [DidModule], + imports: [DidModule, TxSendModuleModule], controllers: [SchemaController], providers: [ SchemaService, diff --git a/src/schema/services/schema.service.ts b/src/schema/services/schema.service.ts index dddb138d..6a04b78c 100644 --- a/src/schema/services/schema.service.ts +++ b/src/schema/services/schema.service.ts @@ -20,6 +20,7 @@ import { Schemas } from '../schemas/schemas.schema'; import { RegisterSchemaDto } from '../dto/register-schema.dto'; import { Namespace } from 'src/did/dto/create-did.dto'; import { getAppVault, getAppMenemonic } from '../../utils/app-vault-service'; +import { TxSendModuleService } from 'src/tx-send-module/tx-send-module.service'; @Injectable({ scope: Scope.REQUEST }) export class SchemaService { @@ -29,7 +30,27 @@ export class SchemaService { private readonly schemaSSIservice: SchemaSSIService, private readonly hidWallet: HidWalletService, private readonly didRepositiory: DidRepository, + private readonly txnService: TxSendModuleService, ) {} + + async checkAllowence(address) { + const url = + this.config.get('HID_NETWORK_API') + + '/cosmos/feegrant/v1beta1/allowances/' + + address; + + const resp = await fetch(url); + + const res = await resp.json(); + if (resp.status === 200) { + if (res.allowances.length > 0) { + return true; + } else { + return false; + } + } + return false; + } async create( createSchemaDto: CreateSchemaDto, appDetail, @@ -92,9 +113,23 @@ export class SchemaService { 'SchemaService', ); - const registeredSchema = await hypersignSchema.register({ - schema: signedSchema, - }); + const { wallet, address } = await this.hidWallet.generateWallet( + appMenemonic, + ); + let registeredSchema; + + if (await this.checkAllowence(address)) { + await this.txnService.sendSchemaTxn( + generatedSchema, + signedSchema.proof, + appMenemonic, + ); + } else { + registeredSchema = await hypersignSchema.register({ + schema: signedSchema, + }); + } + Logger.log( 'create() method: storing schema information to DB', 'SchemaService', @@ -103,13 +138,17 @@ export class SchemaService { schemaId: signedSchema.id, appId: appDetail.appId, authorDid: author, - transactionHash: registeredSchema['transactionHash'], + transactionHash: registeredSchema['transactionHash'] + ? registeredSchema['transactionHash'] + : '', }); Logger.log('create() method: ends', 'SchemaService'); return { schemaId: signedSchema.id, - transactionHash: registeredSchema['transactionHash'], + transactionHash: registeredSchema['transactionHash'] + ? registeredSchema['transactionHash'] + : '', }; } catch (error) { Logger.error( @@ -191,7 +230,7 @@ export class SchemaService { async registerSchema( registerSchemaDto: RegisterSchemaDto, appDetail, - ): Promise<{ transactionHash: string }> { + ): Promise { Logger.log('registerSchema() method: starts....', 'SchemaService'); const { edvId, kmsId } = appDetail; @@ -219,19 +258,30 @@ export class SchemaService { appMenemonic, namespace, ); - let registeredSchema = {} as { transactionHash: string }; schemaDocument['proof'] = schemaProof; Logger.log('registerSchema() method: registering schema on the blockchain'); + let registeredSchema; try { - registeredSchema = await hypersignSchema.register({ - schema: schemaDocument, - }); + const { wallet, address } = await this.hidWallet.generateWallet( + appMenemonic, + ); + if (await this.checkAllowence(address)) { + await this.txnService.sendSchemaTxn( + registerSchemaDto.schemaDocument, + registerSchemaDto.schemaProof, + appMenemonic, + ); + } else { + registeredSchema = await hypersignSchema.register({ + schema: schemaDocument, + }); + } } catch (e) { Logger.error('registerSchema() method: Error while registering schema'); throw new BadRequestException([e.message]); } Logger.log('registerSchema() method: ends....', 'SchemaService'); - return { transactionHash: registeredSchema.transactionHash }; + return { transactionHash: registeredSchema?.transactionHash }; } } diff --git a/src/tx-send-module/tx-send-module.module.ts b/src/tx-send-module/tx-send-module.module.ts new file mode 100644 index 00000000..eda3628a --- /dev/null +++ b/src/tx-send-module/tx-send-module.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common'; +import { TxSendModuleService } from './tx-send-module.service'; +import { ConfigModule } from '@nestjs/config'; +import { HidWalletModule } from 'src/hid-wallet/hid-wallet.module'; +import { DidSSIService } from 'src/did/services/did.ssi.service'; + +@Module({ + imports: [ConfigModule, HidWalletModule], + controllers: [], + providers: [TxSendModuleService, DidSSIService], + exports: [TxSendModuleService], +}) +export class TxSendModuleModule {} diff --git a/src/tx-send-module/tx-send-module.service.spec.ts b/src/tx-send-module/tx-send-module.service.spec.ts new file mode 100644 index 00000000..d2bca434 --- /dev/null +++ b/src/tx-send-module/tx-send-module.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { TxSendModuleService } from './tx-send-module.service'; + +describe('TxSendModuleService', () => { + let service: TxSendModuleService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [TxSendModuleService], + }).compile(); + + service = module.get(TxSendModuleService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/src/tx-send-module/tx-send-module.service.ts b/src/tx-send-module/tx-send-module.service.ts new file mode 100644 index 00000000..308bd773 --- /dev/null +++ b/src/tx-send-module/tx-send-module.service.ts @@ -0,0 +1,508 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import amqp, { ChannelWrapper } from 'amqp-connection-manager'; +import { + MsgRegisterDID, + MsgRegisterCredentialStatus, + MsgUpdateCredentialStatus, + MsgUpdateDID, + MsgDeactivateDID, + MsgRegisterCredentialSchema, +} from 'hs-ssi-sdk/build/libs/generated/ssi/tx'; +import { DidSSIService } from 'src/did/services/did.ssi.service'; +import { HidWalletService } from 'src/hid-wallet/services/hid-wallet.service'; +import { StdFee } from '@cosmjs/stargate'; +import { + MsgExec, + MsgGrant, + MsgRevoke, +} from 'cosmjs-types/cosmos/authz/v1beta1/tx'; + +@Injectable() +export class TxSendModuleService { + private channel: ChannelWrapper; + private granterAddress; + constructor( + private readonly configService: ConfigService, + private readonly hidWalletService: HidWalletService, + private readonly didSSIService: DidSSIService, + ) { + this.connect(); + } + + async invokeTxnController(address, granteeMnemonic) { + const podENV = { + RMQ_URL: this.configService.get('RABBIT_MQ_URI'), + QUEUE_NAME: 'TXN_QUEUE_' + address, + NODE_RPC_URL: this.configService.get('HID_NETWORK_RPC'), + GRANTEE_MNEMONIC: granteeMnemonic, + GRANTER_ADDRESS: this.granterAddress, + DID_REGISTER_FIXED_FEE: '50', + CRED_REGISTER_FIXED_FEE: '50', + SCHEMA_CREATE_FIXED_FEE: '50', + ESTIMATE_GAS_PRICE: '155303', + podName: 'txn-dynamic', + granteeWalletAddress: address, + }; + + await this.channel.assertQueue('GLOBAL_TXN_CONTROLLER_QUEUE', { + durable: false, + }); + const sendToQueue2 = await this.channel.sendToQueue( + this.configService.get('GLOBAL_TXN_CONTROLLER_QUEUE'), + Buffer.from(JSON.stringify(podENV)), + ); + } + + async prepareMsgCreateDID( + didDocument, + didDocumentSigned, + verificationMethodId, + txAuthor, + ): Promise { + const proof = didDocumentSigned?.find((e) => { + return e.verification_method_id === verificationMethodId; + }); + + const vm = didDocument.verificationMethod?.find((e) => { + return e.id == verificationMethodId; + }); + let signatureType = ''; + let proofPurpose = ''; + switch (vm.type) { + case 'Ed25519VerificationKey2020': { + signatureType = 'Ed25519Signature2020'; + proofPurpose = 'assertionMethod'; + + break; + } + default: { + throw Error('Type is not matched'); + } + } + + return MsgRegisterDID.fromPartial({ + didDocument: didDocument, + didDocumentProofs: [ + { + verificationMethod: verificationMethodId, + type: signatureType, + proofPurpose: proofPurpose, + created: proof.created, + proofValue: proof.signature, + }, + ], + txAuthor: txAuthor, + }); + } + + async connect() { + Logger.log('Connecting Rabbit'); + const connection = await amqp.connect( + this.configService.get('RABBIT_MQ_URI'), + ); + this.channel = await connection.createChannel(); + const { address: granterAddress } = + await this.hidWalletService.generateWallet( + this.configService.get('MNEMONIC'), + ); + this.granterAddress = granterAddress; + Logger.log('Connected Rabbit'); + } + + async prepareRegisterCredentialStatus( + credentialStatus, + credentialStatusProof, + txAuthor, + ) { + return MsgRegisterCredentialStatus.fromPartial({ + credentialStatusDocument: credentialStatus, + credentialStatusProof: credentialStatusProof, + txAuthor, + }); + } + + async prepareUpdateCredentialStatus(credentialStatus, proofValue, address) { + return MsgUpdateCredentialStatus.fromPartial({ + credentialStatusDocument: credentialStatus, + credentialStatusProof: proofValue, + txAuthor: address, + }); + } + + async sendUpdateVC(credentialStatus, proofValue, granteeMnemonic) { + if (!this.channel) { + await this.connect(); + } + const { wallet, address } = await this.hidWalletService.generateWallet( + granteeMnemonic, + ); + const msgUpdateCredentialStatus = await this.prepareUpdateCredentialStatus( + credentialStatus, + proofValue, + address, + ); + + const authExecMsg: MsgExec = { + grantee: address, + msgs: [ + { + typeUrl: '/hypersign.ssi.v1.MsgUpdateCredentialStatus', + value: MsgUpdateCredentialStatus.encode( + msgUpdateCredentialStatus, + ).finish(), + }, + ], + }; + + const fee = { + amount: [ + { + denom: 'uhid', + amount: '100', + }, + ], + gas: '500000', + granter: this.granterAddress, // NOTE: It is VERY IMPORTANT to explicitly pass granter's address + }; + + const txMsg = { + typeUrl: '/cosmos.authz.v1beta1.MsgExec', + value: authExecMsg, + }; + + const data = { + type: 'CRED_UPDATE', + txMsg, + }; + + const queue = 'TXN_QUEUE_' + address; + await this.channel.assertQueue(queue, { + durable: false, + }); + + const sendToQueue1 = await this.channel.sendToQueue( + queue, + Buffer.from(JSON.stringify(data)), + ); + + await this.invokeTxnController(address, granteeMnemonic); + } + + async sendVCTxn(credentialStatus, credentialStatusProof, granteeMnemonic) { + if (!this.channel) { + await this.connect(); + } + const { wallet, address } = await this.hidWalletService.generateWallet( + granteeMnemonic, + ); + + const msgRegisterCredentialStatus = + await this.prepareRegisterCredentialStatus( + credentialStatus, + credentialStatusProof, + address, + ); + const authExecMsg: MsgExec = { + grantee: address, + msgs: [ + { + typeUrl: '/hypersign.ssi.v1.MsgRegisterCredentialStatus', + value: MsgRegisterCredentialStatus.encode( + msgRegisterCredentialStatus, + ).finish(), + }, + ], + }; + + const fee = { + amount: [ + { + denom: 'uhid', + amount: '100', + }, + ], + gas: '500000', + granter: this.granterAddress, // NOTE: It is VERY IMPORTANT to explicitly pass granter's address + }; + + const txMsg = { + typeUrl: '/cosmos.authz.v1beta1.MsgExec', + value: authExecMsg, + }; + + const data = { + type: 'CRED_REGISTER', + txMsg, + }; + + const queue = 'TXN_QUEUE_' + address; + await this.channel.assertQueue(queue, { + durable: false, + }); + + const sendToQueue1 = await this.channel.sendToQueue( + queue, + Buffer.from(JSON.stringify(data)), + ); + + await this.invokeTxnController(address, granteeMnemonic); + } + + async prepareMsgUpdateDID(didDocument, signInfos, versionId, txAuthor) { + return MsgUpdateDID.fromPartial({ + didDocument, + didDocumentProofs: signInfos, + versionId, + txAuthor, + }); + } + + async sendDIDDeactivate( + didDocument: any, + signInfos: any, + versionId: any, + granteeMnemonic: any, + ) { + if (!this.channel) { + await this.connect(); + } + + const { wallet, address } = await this.hidWalletService.generateWallet( + granteeMnemonic, + ); + const msgDeactivateDID = await this.prepareMsgDeactivateDID( + didDocument, + signInfos, + versionId, + address, + ); + + const authExecMsg: MsgExec = { + grantee: address, + msgs: [ + { + typeUrl: '/hypersign.ssi.v1.MsgDeactivateDID', + value: MsgDeactivateDID.encode(msgDeactivateDID).finish(), + }, + ], + }; + + const fee = { + amount: [ + { + denom: 'uhid', + amount: '100', + }, + ], + gas: '500000', + granter: this.granterAddress, // NOTE: It is VERY IMPORTANT to explicitly pass granter's address + }; + const txMsg = { + typeUrl: '/cosmos.authz.v1beta1.MsgExec', + value: authExecMsg, + }; + const queue = 'TXN_QUEUE_' + address; + await this.channel.assertQueue(queue, { + durable: false, + }); + + const data = { + type: 'DID_DEACTIVATE', + txMsg, + }; + const sendToQueue1 = await this.channel.sendToQueue( + queue, + Buffer.from(JSON.stringify(data)), + ); + + await this.invokeTxnController(address, granteeMnemonic); + } + prepareMsgDeactivateDID( + didDocument: any, + signInfos: any, + versionId: any, + address: string, + ) { + return MsgDeactivateDID.fromPartial({ + didDocumentId: didDocument.id, + didDocumentProofs: signInfos, + txAuthor: address, + versionId, + }); + } + + async sendDIDUpdate(didDocument, signInfos, versionId, granteeMnemonic) { + if (!this.channel) { + await this.connect(); + } + + const { wallet, address } = await this.hidWalletService.generateWallet( + granteeMnemonic, + ); + const msgUpdateDID = await this.prepareMsgUpdateDID( + didDocument, + signInfos, + versionId, + address, + ); + const authExecMsg: MsgExec = { + grantee: address, + msgs: [ + { + typeUrl: '/hypersign.ssi.v1.MsgUpdateDID', + value: MsgUpdateDID.encode(msgUpdateDID).finish(), + }, + ], + }; + + const fee = { + amount: [ + { + denom: 'uhid', + amount: '100', + }, + ], + gas: '500000', + granter: this.granterAddress, // NOTE: It is VERY IMPORTANT to explicitly pass granter's address + }; + const txMsg = { + typeUrl: '/cosmos.authz.v1beta1.MsgExec', + value: authExecMsg, + }; + const queue = 'TXN_QUEUE_' + address; + await this.channel.assertQueue(queue, { + durable: false, + }); + + const data = { + type: 'DID_UPDATE', + txMsg, + }; + const sendToQueue1 = await this.channel.sendToQueue( + queue, + Buffer.from(JSON.stringify(data)), + ); + + await this.invokeTxnController(address, granteeMnemonic); + } + + async sendDIDTxn( + didDocument, + didDocumentSigned, + verificationMethodId, + granteeMnemonic, + ) { + if (!this.channel) { + await this.connect(); + } + + const { wallet, address } = await this.hidWalletService.generateWallet( + granteeMnemonic, + ); + const msgCreateDID = await this.prepareMsgCreateDID( + didDocument, + didDocumentSigned, + verificationMethodId, + address, + ); + + const authExecMsg: MsgExec = { + grantee: address, + msgs: [ + { + typeUrl: '/hypersign.ssi.v1.MsgRegisterDID', + value: MsgRegisterDID.encode(msgCreateDID).finish(), + }, + ], + }; + const fee = { + amount: [ + { + denom: 'uhid', + amount: '100', + }, + ], + gas: '500000', + granter: this.granterAddress, // NOTE: It is VERY IMPORTANT to explicitly pass granter's address + }; + const txMsg = { + typeUrl: '/cosmos.authz.v1beta1.MsgExec', + value: authExecMsg, + }; + const queue = 'TXN_QUEUE_' + address; + await this.channel.assertQueue(queue, { + durable: false, + }); + + const data = { + type: 'DID_REGISTER', + txMsg, + }; + const sendToQueue1 = await this.channel.sendToQueue( + queue, + Buffer.from(JSON.stringify(data)), + ); + + await this.invokeTxnController(address, granteeMnemonic); + } + + prepareSchemaMsg(schema, proof, txAuthor) { + return MsgRegisterCredentialSchema.fromPartial({ + credentialSchemaDocument: schema, + credentialSchemaProof: proof, + txAuthor: txAuthor, + }); + } + + async sendSchemaTxn(schema, proof, granteeMnemonic) { + if (!this.channel) { + await this.connect(); + } + + const { wallet, address } = await this.hidWalletService.generateWallet( + granteeMnemonic, + ); + const msgSchema = await this.prepareSchemaMsg(schema, proof, address); + + const authExecMsg: MsgExec = { + grantee: address, + msgs: [ + { + typeUrl: '/hypersign.ssi.v1.MsgRegisterCredentialSchema', + value: MsgRegisterCredentialSchema.encode(msgSchema).finish(), + }, + ], + }; + const fee = { + amount: [ + { + denom: 'uhid', + amount: '100', + }, + ], + gas: '500000', + granter: this.granterAddress, // NOTE: It is VERY IMPORTANT to explicitly pass granter's address + }; + const txMsg = { + typeUrl: '/cosmos.authz.v1beta1.MsgExec', + value: authExecMsg, + }; + const queue = 'TXN_QUEUE_' + address; + await this.channel.assertQueue(queue, { + durable: false, + }); + + const data = { + type: 'SCHEMA_REGISTER', + txMsg, + }; + const sendToQueue1 = await this.channel.sendToQueue( + queue, + Buffer.from(JSON.stringify(data)), + ); + + await this.invokeTxnController(address, granteeMnemonic); + return sendToQueue1; + } +} diff --git a/src/utils/middleware/cors.middleware.ts b/src/utils/middleware/cors.middleware.ts index 953e4f8b..bd0365a1 100644 --- a/src/utils/middleware/cors.middleware.ts +++ b/src/utils/middleware/cors.middleware.ts @@ -15,32 +15,33 @@ export class WhitelistSSICorsMiddleware implements NestMiddleware { 'WhitelistSSICorsMiddleware: checking if call is form whitelisted domain starts', 'Middleware', ); - let referer = req.header('Referer'); + const origin = req.header('Origin'); + // let referer = req.header('Referer'); // Extract the origin - if (referer) { - const referalUrl = new URL(referer); - referer = `${referalUrl.protocol}//${referalUrl.host}`; - } - const origin = req.header('Origin') || referer; + // if (referer) { + // const referalUrl = new URL(referer); + // referer = `${referalUrl.protocol}//${referalUrl.host}`; + // } + const host = req.header('Host'); Logger.debug( - `WhitelistSSICorsMiddleware: request is comming from ${origin}`, + `WhitelistSSICorsMiddleware: request is comming from ${host}`, 'Middleware', ); - let subdomain = - req.subdomains.length > 0 ? req.subdomains.at(-1) : undefined; + const subdomain = + req.subdomains.length > 0 ? req.subdomains.at(-1) : host.split('.')[0]; Logger.debug(`Subdomain ${subdomain} `, 'Middleware'); - Logger.debug(`Origin ${origin} `, 'Middleware'); + Logger.debug(`Host ${host} `, 'Middleware'); - if (!(origin.includes('localhost') || origin.includes('127.0.0.1'))) { - if (!subdomain) { - throw new BadRequestException(['Invalid subdomain']); - } - } else { - subdomain = origin.split('.')[0].split('://')[1]; - } + // if (!(origin.includes('localhost') || origin.includes('127.0.0.1'))) { + // if (!subdomain) { + // throw new BadRequestException(['Invalid subdomain']); + // } + // } else { + // subdomain = host.split('.')[0]; + // } if ( req.header('authorization') == undefined || @@ -66,6 +67,9 @@ export class WhitelistSSICorsMiddleware implements NestMiddleware { throw new UnauthorizedException([e]); } + if (decoded.grantType != 'access_service_ssi') { + throw new BadRequestException(['Invalid grant type for this service']); + } type App = { appId?: string; kmsId?: string;