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
118 changes: 114 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 { RecipientKeyOption, SafeW3cJsonLdVerifyCredentialOptions, SchemaMetadata } from '../types'
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 {
Comment on lines +31 to 32
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Importing assertAskarWallet from internal build path is brittle

@credo-ts/askar/build/utils/assertAskarWallet is an internal bundle path.
Use the public re-export to avoid future breakage:

-import { assertAskarWallet } from '@credo-ts/askar/build/utils/assertAskarWallet'
+import { assertAskarWallet } from '@credo-ts/askar'
📝 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 { assertAskarWallet } from '@credo-ts/askar/build/utils/assertAskarWallet'
import {
import { assertAskarWallet } from '@credo-ts/askar'
import {
🤖 Prompt for AI Agents
In src/controllers/multi-tenancy/MultiTenancyController.ts at lines 32-33, the
import of assertAskarWallet is done from an internal build path
'@credo-ts/askar/build/utils/assertAskarWallet', which is brittle. Change the
import to use the public re-export path provided by the '@credo-ts/askar'
package to ensure stability and avoid breakage in future updates.

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

39 changes: 35 additions & 4 deletions src/controllers/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<InitConfig, 'label' | 'connectionImageUrl'> & {
walletConfig: Pick<WalletConfig, 'id' | 'key' | 'keyDerivationMethod'>
Expand All @@ -37,10 +42,6 @@ export interface AgentInfo {
endpoints: string[]
isInitialized: boolean
publicDid: void
// publicDid?: {
// did: string
// verkey: string
// }
}

export interface AgentMessageType {
Expand Down Expand Up @@ -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<string | JsonObject>
type: Array<string>
credentialSubject: SingleOrArray<JsonObject>
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<Omit<LinkedDataProofOptions, "cryptosuite"> | DataIntegrityProofOptions>
}
Loading