Skip to content

Commit 679ffa8

Browse files
Merge pull request #277 from credebl/qa
Qa - sign and verify methods
2 parents 3b83e49 + 8f40640 commit 679ffa8

File tree

5 files changed

+1224
-16
lines changed

5 files changed

+1224
-16
lines changed

.github/workflows/continuous-delivery.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,5 @@ jobs:
4242
tags: |
4343
${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.SERVICE }}:${{ env.TAG }}
4444
${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.SERVICE }}:latest
45+
46+

src/controllers/multi-tenancy/MultiTenancyController.ts

Lines changed: 128 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable prettier/prettier */
22
import type { RestAgentModules, RestMultiTenantAgentModules } from '../../cliAgent'
33
import type { Version } from '../examples'
4-
import type { RecipientKeyOption, SchemaMetadata } from '../types'
4+
import type { CustomW3cJsonLdSignCredentialOptions, RecipientKeyOption, SafeW3cJsonLdVerifyCredentialOptions, SchemaMetadata } from '../types'
55
import type { PolygonDidCreateOptions } from '@ayanworks/credo-polygon-w3c-module/build/dids'
66
import type {
77
AcceptProofRequestOptions,
@@ -15,7 +15,8 @@ import type {
1515
ProofExchangeRecordProps,
1616
ProofsProtocolVersionType,
1717
Routing,
18-
} from '@credo-ts/core'
18+
W3cJsonLdSignCredentialOptions,
19+
W3cVerifiableCredential} from '@credo-ts/core'
1920
import type { IndyVdrDidCreateOptions, IndyVdrDidCreateResult } from '@credo-ts/indy-vdr'
2021
import type { QuestionAnswerRecord, ValidResponse } from '@credo-ts/question-answer'
2122
import type { TenantRecord } from '@credo-ts/tenants'
@@ -27,6 +28,7 @@ import {
2728
parseIndyCredentialDefinitionId,
2829
parseIndySchemaId,
2930
} from '@credo-ts/anoncreds'
31+
import { assertAskarWallet } from '@credo-ts/askar/build/utils/assertAskarWallet'
3032
import {
3133
AcceptCredentialOfferOptions,
3234
Agent,
@@ -45,7 +47,9 @@ import {
4547
injectable,
4648
createPeerDidDocumentFromServices,
4749
PeerDidNumAlgo,
48-
} from '@credo-ts/core'
50+
W3cJsonLdVerifiableCredential,
51+
W3cCredential,
52+
ClaimFormat} from '@credo-ts/core'
4953
import { QuestionAnswerRole, QuestionAnswerState } from '@credo-ts/question-answer'
5054
import axios from 'axios'
5155
import * as fs from 'fs'
@@ -89,7 +93,7 @@ import {
8993
CreateProofRequestOobOptions,
9094
CreateOfferOobOptions,
9195
CreateSchemaInput,
92-
} from '../types'
96+
VerifyDataOptions , SignDataOptions } from '../types'
9397

9498
import { Body, Controller, Delete, Get, Post, Query, Route, Tags, Path, Example, Security, Response } from 'tsoa'
9599

@@ -1913,4 +1917,124 @@ export class MultiTenancyController extends Controller {
19131917
throw ErrorHandlingService.handle(error)
19141918
}
19151919
}
1920+
1921+
/**
1922+
* Verify data using a key
1923+
*
1924+
* @param tenantId Tenant identifier
1925+
* @param request Verify options
1926+
* data - Data has to be in base64 format
1927+
* publicKeyBase58 - Public key in base58 format
1928+
* signature - Signature in base64 format
1929+
* @returns isValidSignature - true if signature is valid, false otherwise
1930+
*/
1931+
@Security('apiKey')
1932+
@Post('/verify/:tenantId')
1933+
public async verify(@Path('tenantId') tenantId: string, @Body() request: VerifyDataOptions) {
1934+
try {
1935+
const isValidSignature = await this.agent.modules.tenants.withTenantAgent({ tenantId }, async (tenantAgent) => {
1936+
assertAskarWallet(tenantAgent.context.wallet)
1937+
const isValidSignature = await tenantAgent.context.wallet.verify({
1938+
data: TypedArrayEncoder.fromBase64(request.data),
1939+
key: Key.fromPublicKeyBase58(request.publicKeyBase58, request.keyType),
1940+
signature: TypedArrayEncoder.fromBase64(request.signature),
1941+
})
1942+
return isValidSignature
1943+
})
1944+
return isValidSignature
1945+
} catch (error) {
1946+
throw ErrorHandlingService.handle(error)
1947+
}
1948+
}
1949+
1950+
@Security('apiKey')
1951+
@Post('/credential/sign/:tenantId')
1952+
public async signCredential(
1953+
@Path('tenantId') tenantId: string,
1954+
@Query('storeCredential') storeCredential: boolean,
1955+
@Query('dataTypeToSign') dataTypeToSign: 'rawData' | 'jsonLd',
1956+
@Body() data: CustomW3cJsonLdSignCredentialOptions | SignDataOptions | any
1957+
) {
1958+
try {
1959+
return await this.agent.modules.tenants.withTenantAgent({ tenantId }, async (tenantAgent) => {
1960+
// JSON-LD VC Signing
1961+
if (dataTypeToSign === 'jsonLd') {
1962+
const credentialData = data as unknown as W3cJsonLdSignCredentialOptions
1963+
credentialData.format = ClaimFormat.LdpVc
1964+
1965+
const signedCredential = await tenantAgent.w3cCredentials.signCredential(credentialData) as W3cJsonLdVerifiableCredential
1966+
1967+
if (storeCredential) {
1968+
return await tenantAgent.w3cCredentials.storeCredential({ credential: signedCredential })
1969+
}
1970+
1971+
return signedCredential.toJson()
1972+
}
1973+
1974+
// Raw Data Signing
1975+
const rawData = data as SignDataOptions
1976+
1977+
if (!rawData.data) throw new BadRequestError('Missing "data" for raw data signing.')
1978+
1979+
const hasDidOrMethod = rawData.did || rawData.method
1980+
const hasPublicKey = rawData.publicKeyBase58 && rawData.keyType
1981+
1982+
if (!hasDidOrMethod && !hasPublicKey) {
1983+
throw new BadRequestError('Either (did or method) OR (publicKeyBase58 and keyType) must be provided.')
1984+
}
1985+
1986+
let keyToUse: Key
1987+
1988+
if (hasDidOrMethod) {
1989+
const dids = await tenantAgent.dids.getCreatedDids({
1990+
method: rawData.method || undefined,
1991+
did: rawData.did || undefined,
1992+
})
1993+
1994+
const verificationMethod = dids[0]?.didDocument?.verificationMethod?.[0]?.publicKeyBase58
1995+
if (!verificationMethod) {
1996+
throw new BadRequestError('No publicKeyBase58 found for the given DID or method.')
1997+
}
1998+
1999+
keyToUse = Key.fromPublicKeyBase58(verificationMethod, rawData.keyType)
2000+
} else {
2001+
keyToUse = Key.fromPublicKeyBase58(rawData.publicKeyBase58, rawData.keyType)
2002+
}
2003+
2004+
if (!keyToUse) {
2005+
throw new Error('Unable to construct signing key.')
2006+
}
2007+
2008+
const signature = await tenantAgent.context.wallet.sign({
2009+
data: TypedArrayEncoder.fromBase64(rawData.data),
2010+
key: keyToUse,
2011+
})
2012+
2013+
return TypedArrayEncoder.toBase64(signature)
2014+
})
2015+
} catch (error) {
2016+
throw ErrorHandlingService.handle(error)
2017+
}
2018+
}
2019+
2020+
@Security('apiKey')
2021+
@Post('/credential/verify/:tenantId')
2022+
public async verifyCredential(
2023+
@Path('tenantId') tenantId: string,
2024+
@Body() credentialToVerify: SafeW3cJsonLdVerifyCredentialOptions | any
2025+
) {
2026+
let formattedCredential
2027+
try {
2028+
await this.agent.modules.tenants.withTenantAgent({ tenantId }, async (tenantAgent) => {
2029+
const {credential, ...credentialOptions}= credentialToVerify
2030+
const transformedCredential = JsonTransformer.fromJSON(credentialToVerify?.credential, W3cJsonLdVerifiableCredential)
2031+
const signedCred = await tenantAgent.w3cCredentials.verifyCredential({credential: transformedCredential, ...credentialOptions})
2032+
formattedCredential = signedCred
2033+
})
2034+
return formattedCredential
2035+
} catch (error) {
2036+
throw ErrorHandlingService.handle(error)
2037+
}
2038+
}
19162039
}
2040+

src/controllers/types.ts

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,16 @@ import type {
2525
Attachment,
2626
KeyType,
2727
JsonLdCredentialFormat,
28+
JsonObject,
29+
W3cJsonLdVerifyCredentialOptions,
30+
DataIntegrityProofOptions,
31+
W3cJsonLdSignCredentialOptions,
32+
W3cCredential,
33+
W3cCredentialSubject,
2834
} from '@credo-ts/core'
35+
import type { SingleOrArray } from '@credo-ts/core/build/utils'
2936
import type { DIDDocument } from 'did-resolver'
37+
import { LinkedDataProofOptions } from '@credo-ts/core/build/modules/vc/data-integrity/models/LinkedDataProof'
3038

3139
export type TenantConfig = Pick<InitConfig, 'label' | 'connectionImageUrl'> & {
3240
walletConfig: Pick<WalletConfig, 'id' | 'key' | 'keyDerivationMethod'>
@@ -37,10 +45,6 @@ export interface AgentInfo {
3745
endpoints: string[]
3846
isInitialized: boolean
3947
publicDid: void
40-
// publicDid?: {
41-
// did: string
42-
// verkey: string
43-
// }
4448
}
4549

4650
export interface AgentMessageType {
@@ -388,3 +392,48 @@ export interface SchemaMetadata {
388392
* @example "ea4e5e69-fc04-465a-90d2-9f8ff78aa71d"
389393
*/
390394
export type ThreadId = string
395+
396+
export type SignDataOptions = {
397+
data: string
398+
keyType: KeyType
399+
publicKeyBase58: string
400+
did?: string
401+
method?: string
402+
}
403+
404+
export type VerifyDataOptions = {
405+
data: string
406+
keyType: KeyType
407+
publicKeyBase58: string
408+
signature: string
409+
}
410+
411+
export interface jsonLdCredentialOptions {
412+
'@context': Array<string | JsonObject>
413+
type: Array<string>
414+
credentialSubject: SingleOrArray<JsonObject>
415+
proofType: string
416+
}
417+
418+
export interface credentialPayloadToSign {
419+
issuerDID: string
420+
method: string
421+
credential: jsonLdCredentialOptions // TODO: add support for other credential format
422+
}
423+
export interface SafeW3cJsonLdVerifyCredentialOptions extends W3cJsonLdVerifyCredentialOptions {
424+
// Ommited due to issues with TSOA
425+
proof: SingleOrArray<Omit<LinkedDataProofOptions, "cryptosuite"> | DataIntegrityProofOptions>
426+
}
427+
428+
export type ExtensibleW3cCredentialSubject = W3cCredentialSubject & {
429+
[key: string]: unknown
430+
}
431+
432+
export type ExtensibleW3cCredential = W3cCredential & {
433+
[key: string]: unknown
434+
credentialSubject: SingleOrArray<ExtensibleW3cCredentialSubject>
435+
}
436+
437+
export type CustomW3cJsonLdSignCredentialOptions = Omit<W3cJsonLdSignCredentialOptions, 'format'> & {
438+
[key: string]: unknown
439+
}

0 commit comments

Comments
 (0)