Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,13 @@
"webpack:dev:web": "webpack --env=dev --target=web --config ../../webpack.config.js"
},
"dependencies": {
"@apidevtools/json-schema-ref-parser": "12.0.1",
"@ethereumjs/common": "4.0.0",
"@ethereumjs/tx": "5.0.0",
"@hyperledger/cactus-common": "2.1.0",
"@hyperledger/cactus-core": "2.1.0",
"@hyperledger/cactus-core-api": "2.1.0",
"ajv": "8.17.1",
"axios": "1.8.4",
"ethers": "6.8.1",
"express": "5.1.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Express, Request, Response } from "express";
import { Ajv } from "ajv";
import RefParser from "@apidevtools/json-schema-ref-parser";

import {
IWebServiceEndpoint,
Expand All @@ -22,6 +24,53 @@ import OAS from "../../json/openapi.json";
import { ERR_INVALID_RESPONSE } from "web3";
import { isWeb3Error } from "../public-api";

async function preprocessSchema() {
const resolvedSchema = await RefParser.dereference(OAS);
function adjustNullable(obj: Record<string, unknown>) {
if (typeof obj !== "object" || obj === null) return;
if ("nullable" in obj && !("type" in obj)) {
delete obj.nullable;
}
if (obj.nullable === true && obj.type && typeof obj.type === "string") {
obj.type = [obj.type, "null"];
delete obj.nullable;
}
if (obj.nullable === false) {
delete obj.nullable;
}
for (const key in obj) {
if (typeof obj[key] === "object" && obj[key] !== null) {
adjustNullable(obj[key] as Record<string, unknown>);
}
}
}

adjustNullable(resolvedSchema as Record<string, unknown>);
return resolvedSchema;
}

let validateDeployContract: ReturnType<Ajv["compile"]> | undefined;
async function getValidateDeployContract(): Promise<
ReturnType<Ajv["compile"]>
> {
if (validateDeployContract) {
return validateDeployContract;
}

const ajv = new Ajv({
allErrors: true,
strict: false,
allowMatchingProperties: true,
});
const processedSchema = await preprocessSchema();
ajv.addSchema(processedSchema, "openapi.json");

validateDeployContract = ajv.compile({
$ref: "openapi.json#/components/schemas/DeployContractV1Request",
});
return validateDeployContract;
}

export interface IDeployContractSolidityBytecodeOptions {
logLevel?: LogLevelDesc;
connector: PluginLedgerConnectorEthereum;
Expand Down Expand Up @@ -88,6 +137,18 @@ export class DeployContractEndpoint implements IWebServiceEndpoint {
public async handleRequest(req: Request, res: Response): Promise<void> {
const reqTag = `${this.getVerbLowerCase()} - ${this.getPath()}`;
this.log.debug(reqTag);

const validate = await getValidateDeployContract();
const isValid = validate(req.body);
if (!isValid) {
const errorDetails = JSON.stringify(validate.errors);
this.log.debug(`Validation failed for ${reqTag}: ${errorDetails}`);
res.status(400).json({
message: "Invalid request body",
errors: validate.errors,
});
return;
}
try {
res
.status(200)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,8 @@ describe("Ethereum contract deploy and invoke using keychain tests", () => {
});

test("deployContract with additional parameters should fail", async () => {
try {
await apiClient.deployContract({
await expect(
apiClient.deployContract({
contract: {
contractJSON: HelloWorldContractJson,
},
Expand All @@ -255,11 +255,15 @@ describe("Ethereum contract deploy and invoke using keychain tests", () => {
},
gas: 1000000,
fake: 4,
} as DeployContractV1Request);
fail("Expected deployContract call to fail but it succeeded.");
} catch (error) {
console.log("deployContract failed as expected");
}
} as DeployContractV1Request),
).rejects.toMatchObject({
response: {
status: 400,
data: {
message: expect.stringContaining("Invalid request body"),
},
},
});
});

//////////////////////////////////
Expand Down
13 changes: 13 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,17 @@ __metadata:
languageName: node
linkType: hard

"@apidevtools/json-schema-ref-parser@npm:12.0.1":
version: 12.0.1
resolution: "@apidevtools/json-schema-ref-parser@npm:12.0.1"
dependencies:
"@jsdevtools/ono": "npm:^7.1.3"
"@types/json-schema": "npm:^7.0.15"
js-yaml: "npm:^4.1.0"
checksum: 10/1ebe4b623dc841ac7137abb68e573a91350fcca38185379da52e1ab888fcb4cf706026bc41436dbb61a82ca830c8221e04b8432252bbb34815cfee5f290d0a22
languageName: node
linkType: hard

"@apidevtools/json-schema-ref-parser@npm:^11.6.2":
version: 11.6.4
resolution: "@apidevtools/json-schema-ref-parser@npm:11.6.4"
Expand Down Expand Up @@ -10616,6 +10627,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@hyperledger/cactus-plugin-ledger-connector-ethereum@workspace:packages/cactus-plugin-ledger-connector-ethereum"
dependencies:
"@apidevtools/json-schema-ref-parser": "npm:12.0.1"
"@ethereumjs/common": "npm:4.0.0"
"@ethereumjs/tx": "npm:5.0.0"
"@hyperledger/cactus-common": "npm:2.1.0"
Expand All @@ -10630,6 +10642,7 @@ __metadata:
"@types/minimist": "npm:1.2.2"
"@types/sanitize-html": "npm:2.9.5"
"@types/uuid": "npm:10.0.0"
ajv: "npm:8.17.1"
axios: "npm:1.8.4"
body-parser: "npm:1.20.3"
chalk: "npm:4.1.2"
Expand Down
Loading