Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/continuous-delivery.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,5 @@ jobs:
tags: |
${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.SERVICE }}:${{ env.TAG }}
${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.SERVICE }}:latest


Comment on lines +45 to +46
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix formatting issues: remove trailing spaces and extra blank line.

The static analysis tools correctly identified formatting issues:

  • Line 45 has trailing spaces
  • Line 46 has an unnecessary blank line

Apply this diff to fix the formatting:

-            ${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.SERVICE }}:latest
-          
-
+            ${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.SERVICE }}:latest
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.SERVICE }}:latest
🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 45-45: trailing spaces

(trailing-spaces)


[warning] 46-46: too many blank lines

(1 > 0) (empty-lines)

🤖 Prompt for AI Agents
In .github/workflows/continuous-delivery.yml at lines 45 and 46, remove any
trailing spaces at line 45 and delete the extra blank line at line 46 to fix the
formatting issues.

132 changes: 128 additions & 4 deletions src/controllers/multi-tenancy/MultiTenancyController.ts
Original file line number Diff line number Diff line change
@@ -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 { CustomW3cJsonLdSignCredentialOptions, RecipientKeyOption, SafeW3cJsonLdVerifyCredentialOptions, SchemaMetadata } from '../types'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Clean up imports: remove unused and fix type imports.

Apply these diffs to fix the import issues:

  1. Move SignDataOptions and VerifyDataOptions to type imports (line 4):
-import type { CustomW3cJsonLdSignCredentialOptions, RecipientKeyOption, SafeW3cJsonLdVerifyCredentialOptions, SchemaMetadata } from '../types'
+import type { CustomW3cJsonLdSignCredentialOptions, RecipientKeyOption, SafeW3cJsonLdVerifyCredentialOptions, SchemaMetadata, SignDataOptions, VerifyDataOptions } from '../types'
  1. Remove unused imports (lines 19, 51):
   W3cJsonLdSignCredentialOptions,
-  W3cVerifiableCredential} from '@credo-ts/core'
+} from '@credo-ts/core'
   W3cJsonLdVerifiableCredential,
-  W3cCredential,
   ClaimFormat} from '@credo-ts/core'
  1. Remove from regular imports (line 96):
- VerifyDataOptions , SignDataOptions } from '../types'
+} from '../types'

Also applies to: 19-19, 51-52, 96-96

🤖 Prompt for AI Agents
In src/controllers/multi-tenancy/MultiTenancyController.ts around lines 4, 19,
51-52, and 96, clean up the imports by moving SignDataOptions and
VerifyDataOptions to type-only imports on line 4, removing any unused imports on
lines 19 and 51-52, and removing certain imports from the regular import
statements on line 96 as specified. This will ensure only necessary types and
modules are imported correctly and unused imports are eliminated.

import type { PolygonDidCreateOptions } from '@ayanworks/credo-polygon-w3c-module/build/dids'
import type {
AcceptProofRequestOptions,
Expand All @@ -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'
Expand All @@ -27,6 +28,7 @@ import {
parseIndyCredentialDefinitionId,
parseIndySchemaId,
} from '@credo-ts/anoncreds'
import { assertAskarWallet } from '@credo-ts/askar/build/utils/assertAskarWallet'
import {
AcceptCredentialOfferOptions,
Agent,
Expand All @@ -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'
Expand Down Expand Up @@ -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'

Expand Down Expand Up @@ -1913,4 +1917,124 @@ export class MultiTenancyController extends Controller {
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)
}
}

Comment on lines +1931 to +1949
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add input validation for verify method parameters.

The method implementation is solid, but consider adding validation for the input parameters to prevent potential issues with invalid data.

Add validation before processing:

 public async verify(@Path('tenantId') tenantId: string, @Body() request: VerifyDataOptions) {
   try {
+    // Validate input parameters
+    if (!request.data || !request.publicKeyBase58 || !request.signature || !request.keyType) {
+      throw new BadRequestError('Missing required parameters: data, publicKeyBase58, signature, and keyType are required')
+    }
+
     const isValidSignature = await this.agent.modules.tenants.withTenantAgent({ tenantId }, async (tenantAgent) => {
🤖 Prompt for AI Agents
In src/controllers/multi-tenancy/MultiTenancyController.ts around lines 1931 to
1949, the verify method lacks input validation for tenantId and the request body
parameters. Add validation checks to ensure tenantId is a non-empty string and
that request contains valid base64-encoded data, a valid publicKeyBase58 string,
a recognized keyType, and a base64-encoded signature before proceeding with the
verification logic. This will prevent processing invalid or malformed inputs and
improve method robustness.

@Security('apiKey')
@Post('/credential/sign/:tenantId')
public async signCredential(
@Path('tenantId') tenantId: string,
@Query('storeCredential') storeCredential: boolean,
@Query('dataTypeToSign') dataTypeToSign: 'rawData' | 'jsonLd',
@Body() data: CustomW3cJsonLdSignCredentialOptions | SignDataOptions | any
) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid using any type for the data parameter.

The data parameter accepts multiple types but using any removes type safety.

Consider using a union type:

-    @Body() data: CustomW3cJsonLdSignCredentialOptions | SignDataOptions | any
+    @Body() data: CustomW3cJsonLdSignCredentialOptions | SignDataOptions
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
) {
signCredential(
@Body() data: CustomW3cJsonLdSignCredentialOptions | SignDataOptions
) {
// …
}
🤖 Prompt for AI Agents
In src/controllers/multi-tenancy/MultiTenancyController.ts at line 1957, the
data parameter is currently typed as any, which removes type safety. Replace the
any type with a union type that accurately reflects all possible types data can
accept to improve type safety and maintainability.

try {
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

if (storeCredential) {
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)
})
} catch (error) {
throw ErrorHandlingService.handle(error)
}
}

@Security('apiKey')
@Post('/credential/verify/:tenantId')
public async verifyCredential(
@Path('tenantId') tenantId: string,
@Body() credentialToVerify: SafeW3cJsonLdVerifyCredentialOptions | any
) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove any type for better type safety.

Apply this diff to improve type safety:

-    @Body() credentialToVerify: SafeW3cJsonLdVerifyCredentialOptions | any
+    @Body() credentialToVerify: SafeW3cJsonLdVerifyCredentialOptions

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/controllers/multi-tenancy/MultiTenancyController.ts at line 2025, the use
of the `any` type reduces type safety. Replace `any` with a more specific type
that accurately represents the expected data structure or interface for the
variable or parameter in question. Review the context to determine the correct
type and update the code accordingly to enhance type safety.

let formattedCredential
try {
await this.agent.modules.tenants.withTenantAgent({ tenantId }, async (tenantAgent) => {
const {credential, ...credentialOptions}= credentialToVerify
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove unused destructured variable.

The credential variable is destructured but never used.

Apply this diff to fix the issue:

-        const {credential,  ...credentialOptions}= credentialToVerify
+        const { ...credentialOptions } = credentialToVerify
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const {credential, ...credentialOptions}= credentialToVerify
const { ...credentialOptions } = credentialToVerify
🧰 Tools
🪛 ESLint

[error] 2029-2029: 'credential' is assigned a value but never used.

(@typescript-eslint/no-unused-vars)

🤖 Prompt for AI Agents
In src/controllers/multi-tenancy/MultiTenancyController.ts at line 2029, the
variable 'credential' is destructured from 'credentialToVerify' but never used.
Remove 'credential' from the destructuring assignment and only extract
'credentialOptions' to eliminate the unused variable warning.

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)
}
}
}

57 changes: 53 additions & 4 deletions src/controllers/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,16 @@ import type {
Attachment,
KeyType,
JsonLdCredentialFormat,
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'
import { LinkedDataProofOptions } from '@credo-ts/core/build/modules/vc/data-integrity/models/LinkedDataProof'
Comment on lines +35 to +37
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix import formatting and use type imports for type-only imports.

Apply this diff to fix the import issues:

 } 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'
+import type { LinkedDataProofOptions } from '@credo-ts/core/build/modules/vc/data-integrity/models/LinkedDataProof'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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'
import type { SingleOrArray } from '@credo-ts/core/build/utils'
import type { DIDDocument } from 'did-resolver'
import type { LinkedDataProofOptions } from '@credo-ts/core/build/modules/vc/data-integrity/models/LinkedDataProof'
🧰 Tools
🪛 ESLint

[error] 36-36: There should be at least one empty line between import groups

(import/order)


[error] 37-37: All imports in the declaration are only used as types. Use import type.

(@typescript-eslint/consistent-type-imports)

🤖 Prompt for AI Agents
In src/controllers/types.ts around lines 35 to 37, the imports include type-only
imports that are not using the 'import type' syntax consistently. Change all
imports that are only used for types to use 'import type' to improve clarity and
enable better tree-shaking. Ensure the import statements are formatted
consistently, using 'import type' for SingleOrArray, DIDDocument, and
LinkedDataProofOptions since they are types.


export type TenantConfig = Pick<InitConfig, 'label' | 'connectionImageUrl'> & {
walletConfig: Pick<WalletConfig, 'id' | 'key' | 'keyDerivationMethod'>
Expand All @@ -37,10 +45,6 @@ export interface AgentInfo {
endpoints: string[]
isInitialized: boolean
publicDid: void
// publicDid?: {
// did: string
// verkey: string
// }
}

export interface AgentMessageType {
Expand Down Expand Up @@ -388,3 +392,48 @@ export interface SchemaMetadata {
* @example "ea4e5e69-fc04-465a-90d2-9f8ff78aa71d"
*/
export type ThreadId = string

export type SignDataOptions = {
data: string
keyType: KeyType
publicKeyBase58: string
did?: string
method?: string
}

export type VerifyDataOptions = {
data: string
keyType: KeyType
publicKeyBase58: string
signature: string
}

export interface jsonLdCredentialOptions {
'@context': Array<string | JsonObject>
type: Array<string>
credentialSubject: SingleOrArray<JsonObject>
proofType: string
}

Comment on lines +412 to +417
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Use PascalCase for type names to maintain consistency.

The type name jsonLdCredentialOptions should follow TypeScript naming conventions.

Apply this diff to fix the naming:

-export interface jsonLdCredentialOptions {
+export interface JsonLdCredentialOptions {
   '@context': Array<string | JsonObject>
   type: Array<string>
   credentialSubject: SingleOrArray<JsonObject>
   proofType: string
 }

Also update the reference in line 421:

-  credential: jsonLdCredentialOptions // TODO: add support for other credential format
+  credential: JsonLdCredentialOptions // TODO: add support for other credential format
🤖 Prompt for AI Agents
In src/controllers/types.ts around lines 412 to 417, the type name
jsonLdCredentialOptions should be renamed to PascalCase as
JsonLdCredentialOptions to follow TypeScript naming conventions. Rename the type
declaration and update all references to this type, including the one at line
421, to use the new PascalCase name.

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<Omit<LinkedDataProofOptions, "cryptosuite"> | DataIntegrityProofOptions>
}

export type ExtensibleW3cCredentialSubject = W3cCredentialSubject & {
[key: string]: unknown
}

export type ExtensibleW3cCredential = W3cCredential & {
[key: string]: unknown
credentialSubject: SingleOrArray<ExtensibleW3cCredentialSubject>
}

export type CustomW3cJsonLdSignCredentialOptions = Omit<W3cJsonLdSignCredentialOptions, 'format'> & {
[key: string]: unknown
}
Loading
Loading