Skip to content

Commit

Permalink
fix(cmd-api-server): openapi spec validation
Browse files Browse the repository at this point in the history
add missing validation for plugin REST endpoints

fixes hyperledger-cacti#847

Signed-off-by: Elena Izaguirre <e.izaguirre.equiza@accenture.com>
  • Loading branch information
elenaizaguirre committed Aug 20, 2021
1 parent 4cc6f2c commit 6695dd7
Show file tree
Hide file tree
Showing 70 changed files with 5,628 additions and 816 deletions.
4 changes: 2 additions & 2 deletions packages/cactus-cmd-api-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
"express": "4.17.1",
"express-http-proxy": "1.6.0",
"express-jwt": "6.0.0",
"express-openapi-validator": "3.10.0",
"express-openapi-validator": "4.12.12",
"fs-extra": "10.0.0",
"jose": "1.28.1",
"lmify": "0.3.0",
Expand All @@ -109,7 +109,7 @@
"@types/express-http-proxy": "1.6.1",
"@types/express-jwt": "6.0.1",
"@types/jsonwebtoken": "8.5.1",
"@types/multer": "1.4.5",
"@types/multer": "1.4.6",
"@types/node-forge": "0.9.3",
"@types/passport": "1.0.6",
"@types/passport-oauth2": "1.4.10",
Expand Down
50 changes: 43 additions & 7 deletions packages/cactus-cmd-api-server/src/main/typescript/api-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,15 @@ import { gte } from "semver";
import lmify from "lmify";
import fs from "fs-extra";
import expressHttpProxy from "express-http-proxy";
import type { Application, Request, Response, RequestHandler } from "express";
import type {
Application,
Request,
Response,
RequestHandler,
NextFunction,
} from "express";
import express from "express";
import { OpenApiValidator } from "express-openapi-validator";
import * as OpenApiValidator from "express-openapi-validator";
import compression from "compression";
import bodyParser from "body-parser";
import cors from "cors";
Expand All @@ -37,7 +43,11 @@ import { Logger, LoggerProvider, Servers } from "@hyperledger/cactus-common";

import { ICactusApiServerOptions } from "./config/config-service";
import OAS from "../json/openapi.json";
import { OpenAPIV3 } from "express-openapi-validator/dist/framework/types";
import {
OpenApiRequestHandler,
OpenAPIV3,
OpenApiValidatorOpts,
} from "express-openapi-validator/dist/framework/types";

import { PrometheusExporter } from "./prometheus-exporter/prometheus-exporter";
import { AuthorizerFactory } from "./authzn/authorizer-factory";
Expand Down Expand Up @@ -536,7 +546,32 @@ export class ApiServer {
}

const openApiValidator = this.createOpenApiValidator();
await openApiValidator.install(app);
app.use(openApiValidator);
// manage errors caused by api validation
app.use(
(
err: {
status?: number;
errors: [
{
path: string;
message: string;
errorCode: string;
},
];
},
req: Request,
res: Response,
next: NextFunction,
) => {
if (err) {
res.status(err.status || 500);
res.send(err.errors);
} else {
next();
}
},
);

this.getOrCreateWebServices(app); // The API server's own endpoints

Expand Down Expand Up @@ -612,12 +647,13 @@ export class ApiServer {
}
}

createOpenApiValidator(): OpenApiValidator {
return new OpenApiValidator({
createOpenApiValidator(): OpenApiRequestHandler[] {
const options: OpenApiValidatorOpts = {
apiSpec: OAS as OpenAPIV3.Document,
validateRequests: true,
validateResponses: false,
});
};
return OpenApiValidator.middleware(options);
}

createCorsMiddleware(allowedDomains: string[]): RequestHandler {
Expand Down
2 changes: 2 additions & 0 deletions packages/cactus-core-api/src/main/json/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,7 @@
"key",
"value"
],
"additionalProperties": false,
"properties": {
"key": {
"type": "string",
Expand Down Expand Up @@ -544,6 +545,7 @@
"required": [
"key"
],
"additionalProperties": false,
"properties": {
"key": {
"type": "string",
Expand Down
1 change: 1 addition & 0 deletions packages/cactus-plugin-consortium-manual/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
"axios": "0.21.1",
"body-parser": "1.19.0",
"express": "4.17.1",
"express-openapi-validator": "4.12.12",
"jose": "1.28.1",
"json-stable-stringify": "1.0.1",
"prom-client": "13.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,6 @@
"url": "https://www.apache.org/licenses/LICENSE-2.0.html"
}
},
"servers": [
{
"url": "https://www.cactus.stream/{basePath}",
"description": "Public test instance",
"variables": {
"basePath": {
"default": ""
}
}
},
{
"url": "http://localhost:4000/{basePath}",
"description": "Local test instance",
"variables": {
"basePath": {
"default": ""
}
}
}
],
"components": {
"schemas": {
"GetNodeJwsResponse": {
Expand All @@ -39,7 +19,7 @@
"properties": {
"jws": {
"description": "The JSON Web Signature of the Cactus node.",
"$ref": "../../../../cactus-core-api/src/main/json/openapi.json#/components/schemas/JWSGeneral",
"$ref": "https://raw.githubusercontent.com/hyperledger/cactus/v0.8.0/packages/cactus-core-api/src/main/json/openapi.json#/components/schemas/JWSGeneral",
"nullable": false
}
}
Expand All @@ -52,7 +32,7 @@
"properties": {
"jws": {
"description": "The JSON Web Signature of the Cactus consortium.",
"$ref": "../../../../cactus-core-api/src/main/json/openapi.json#/components/schemas/JWSGeneral",
"$ref": "https://raw.githubusercontent.com/hyperledger/cactus/v0.8.0/packages/cactus-core-api/src/main/json/openapi.json#/components/schemas/JWSGeneral",
"nullable": false,
"format": "The general format which is a JSON object, not a string."
}
Expand All @@ -64,11 +44,13 @@
},
"GetNodeJwsRequest": {
"type": "object",
"additionalProperties": false,
"properties": {
}
},
"GetConsortiumJwsRequest": {
"type": "object",
"additionalProperties": false,
"properties": {
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { Configuration } from "./configuration";
// @ts-ignore
import globalAxios, { AxiosPromise, AxiosInstance } from 'axios';

export const BASE_PATH = "https://www.cactus.stream".replace(/\/+$/, "");
export const BASE_PATH = "http://localhost".replace(/\/+$/, "");

/**
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ import { Server } from "http";
import { Server as SecureServer } from "https";
import { Optional } from "typescript-optional";
import { promisify } from "util";
import express, { Express } from "express";
import express, { Express, NextFunction, Request, Response } from "express";
import bodyParser from "body-parser";
import { JWS, JWK } from "jose";
import jsonStableStringify from "json-stable-stringify";
import { v4 as uuidv4 } from "uuid";

import OAS from "../json/openapi.json";
import * as OpenApiValidator from "express-openapi-validator";
import { OpenAPIV3 } from "express-openapi-validator/dist/framework/types";

import {
ConsortiumDatabase,
IPluginWebService,
Expand Down Expand Up @@ -98,6 +102,10 @@ export class PluginConsortiumManual
this.prometheusExporter.setNodeCount(this.getNodeCount());
}

getOpenApiSpecs(): OpenAPIV3.Document {
return (OAS as unknown) as OpenAPIV3.Document;
}

public getInstanceId(): string {
return this.instanceId;
}
Expand Down Expand Up @@ -171,6 +179,39 @@ export class PluginConsortiumManual
}

const webServices = await this.getOrCreateWebServices();
const apiSpec = this.getOpenApiSpecs();
const openApiMiddleware = OpenApiValidator.middleware({
apiSpec,
validateApiSpec: false,
$refParser: {
mode: "dereference",
},
});
app.use(openApiMiddleware);
app.use(
(
err: {
status?: number;
errors: [
{
path: string;
message: string;
errorCode: string;
},
];
},
req: Request,
res: Response,
next: NextFunction,
) => {
if (err) {
res.status(err.status || 500);
res.send(err.errors);
} else {
next();
}
},
);
webServices.forEach((ws) => ws.registerExpress(webApp));
return webServices;
}
Expand Down
1 change: 1 addition & 0 deletions packages/cactus-plugin-htlc-eth-besu-erc20/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
"@hyperledger/cactus-plugin-ledger-connector-besu": "0.8.0",
"axios": "0.21.1",
"express": "4.17.1",
"express-openapi-validator": "4.12.12",
"joi": "14.3.1",
"openapi-types": "7.0.1",
"typescript-optional": "2.0.1"
Expand Down
Loading

0 comments on commit 6695dd7

Please sign in to comment.