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
94 changes: 54 additions & 40 deletions src/controllers/multi-tenancy/MultiTenancyController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down Expand Up @@ -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)
}
Expand Down
20 changes: 19 additions & 1 deletion src/controllers/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -394,6 +397,8 @@ export type SignDataOptions = {
data: string
keyType: KeyType
publicKeyBase58: string
did?: string
method?: string
}

export type VerifyDataOptions = {
Expand All @@ -418,4 +423,17 @@ export interface credentialPayloadToSign {
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
}
100 changes: 28 additions & 72 deletions src/routes/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down Expand Up @@ -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_": {
Expand Down Expand Up @@ -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": {
Expand Down Expand Up @@ -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":{}},
Expand Down Expand Up @@ -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<RequestHandler>(MultiTenancyController)),
...(fetchMiddlewares<RequestHandler>(MultiTenancyController.prototype.sign)),

async function MultiTenancyController_sign(request: ExRequest, response: ExResponse, next: any) {
const args: Record<string, TsoaRoute.ParameterSchema> = {
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>(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<RequestHandler>(MultiTenancyController)),
Expand Down Expand Up @@ -3828,7 +3783,8 @@ export function RegisterRoutes(app: Router) {
const args: Record<string, TsoaRoute.ParameterSchema> = {
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
Expand Down
Loading