Skip to content

Commit

Permalink
feat: ocsp responder
Browse files Browse the repository at this point in the history
  • Loading branch information
simboonlong committed Aug 21, 2023
1 parent 0fad127 commit fabc66e
Show file tree
Hide file tree
Showing 16 changed files with 817 additions and 35 deletions.
14 changes: 11 additions & 3 deletions .github/workflows/manual.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,24 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js
uses: actions/setup-node@v1
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: "16.x"
- name: Start containers
run: docker-compose up -d --build
- name: Install node dependancies
run: npm ci
- name: Check Prettier
run: npx prettier --check .
- name: Init fake AWS credentials
run: npm run aws:configure
- name: Init local AWS dynamodb
run: npm run aws:dynamodb
- name: Lint
run: npm run lint
- name: Integration test
run: npm run test:ci
- name: Stop containers
if: always() # always stop containers regardless of test results
run: docker-compose down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
docker
node_modules
tmp
.env
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ POST

#### Development

Download [docker desktop](https://www.docker.com/products/docker-desktop) and start it.

`npm i`
`npm run start`

#### Notes
Expand Down
11 changes: 11 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
version: "3.8"
services:
dynamodb-local:
command: "-jar DynamoDBLocal.jar -sharedDb -inMemory -cors '*'"
image: "amazon/dynamodb-local:latest"
container_name: dynamodb-local
ports:
- "8000:8000"
volumes:
- "./docker/dynamodb:/home/dynamodblocal/data"
working_dir: /home/dynamodblocal
23 changes: 23 additions & 0 deletions netlify/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,29 @@ export const ALLOWED_ORIGINS = [
"https://tradetrust.io",
];

export enum DYNAMODB_TABLE {
REVOCATION = "tradetrust-dev-ocsp-responder",
}

// https://datatracker.ietf.org/doc/html/rfc5280#page-69
export enum OCSP_RESPONDER_REVOCATION_REASON {
UNSPECIFIED = 0,
KEY_COMPROMISE = 1,
CA_COMPROMISE = 2,
AFFILIATION_CHANGED = 3,
SUPERSEDED = 4,
CESSATION_OF_OPERATION = 5,
CERTIFICATE_HOLD = 6,
REMOVE_FROM_CRL = 8,
PRIVILEGE_WITHDRAWN = 9,
A_A_COMPROMISE = 10,
}

export enum OCSP_RESPONDER_SUCCESS_MESSAGE {
ADDED = "documentHash added into revocation table.",
REMOVED = "documentHash removed from revocation table.",
}

export enum ERROR_MESSAGE {
CORS_UNALLOWED = "The CORS policy for this site does not allow access from the specified Origin.",
API_KEY_INVALID = "API key invalid.",
Expand Down
18 changes: 18 additions & 0 deletions netlify/functions/ocsp-responder/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import express from "express";
import cors from "cors";
import serverless from "serverless-http";
import bodyParser from "body-parser";
import { corsOrigin } from "../../utils";
import { MAX_REQUEST_BODY_SIZE } from "../../constants";
import { router } from "./router";

const app = express();

app.use(cors({ origin: corsOrigin }));
app.use(bodyParser.json({ limit: MAX_REQUEST_BODY_SIZE }));
app.use(
bodyParser.urlencoded({ limit: MAX_REQUEST_BODY_SIZE, extended: true }),
);
app.use("/.netlify/functions/ocsp-responder", router);

export const handler = serverless(app);
115 changes: 115 additions & 0 deletions netlify/functions/ocsp-responder/router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import express, { Request, Response } from "express";
import {
DYNAMODB_TABLE,
OCSP_RESPONDER_SUCCESS_MESSAGE,
OCSP_RESPONDER_REVOCATION_REASON,
} from "../../constants";
import { checkApiKey, normalizeHash } from "../../utils";
import { dynamoDbClient } from "../../services/dynamoDb";

const router = express.Router();

router.post("/", checkApiKey, async (req: Request, res: Response) => {
const { documentHash } = req.body;
const hash = normalizeHash(documentHash);

try {
await dynamoDbClient
.put({
TableName: DYNAMODB_TABLE.REVOCATION,
Item: {
documentHash: hash,
createdAt: new Date().toISOString(),
},
})
.promise();

res.status(200).json({
success: true,
message: OCSP_RESPONDER_SUCCESS_MESSAGE.ADDED,
});
} catch (err) {
res.status(400).json(err);
}
});

router.get("/", checkApiKey, async (req: Request, res: Response) => {
try {
const result = await dynamoDbClient
.scan({
TableName: DYNAMODB_TABLE.REVOCATION,
})
.promise();

res.status(200).json({
success: true,
data: result,
});
} catch (err) {
res.status(400).json(err);
}
});

router.delete(
"/:documentHash",
checkApiKey,
async (req: Request, res: Response) => {
const {
params: { documentHash },
} = req;
const hash = normalizeHash(documentHash);

try {
await dynamoDbClient
.delete({
TableName: DYNAMODB_TABLE.REVOCATION,
Key: {
documentHash: hash,
},
})
.promise();

res.status(200).json({
success: true,
messsage: OCSP_RESPONDER_SUCCESS_MESSAGE.REMOVED,
});
} catch (err) {
res.status(400).json(err);
}
},
);

router.get("/:documentHash", async (req: Request, res: Response) => {
const {
params: { documentHash },
} = req;
const hash = normalizeHash(documentHash);

try {
const result = await dynamoDbClient
.get({
TableName: DYNAMODB_TABLE.REVOCATION,
Key: {
documentHash: hash,
},
})
.promise();

if (Object.entries(result).length === 0 && result.constructor === Object) {
res.status(200).json({
revoked: false,
documentHash: hash,
});
} else {
res.status(200).json({
revoked: true,
documentHash: hash,
reasonCode: OCSP_RESPONDER_REVOCATION_REASON.AFFILIATION_CHANGED, // this response shape is required from oa-verify guard -> https://github.com/Open-Attestation/oa-verify/blob/9638ba5285dc85fc294283c5e5e531debaaa5c4b/src/verifiers/documentStatus/didSigned/didSignedDocumentStatus.type.ts#L44-L79
});
}
} catch (err) {
res.status(400).json(err);
}
});

export { router };
17 changes: 17 additions & 0 deletions netlify/services/dynamoDb/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import AWS from "aws-sdk";

const option =
process.env.NODE_ENV === "test"
? {
apiVersion: "2012-08-10",
region: "localhost",
endpoint: "http://localhost:8000",
accessKeyId: "fakeMyKeyId",
secretAccessKey: "fakeSecretAccessKey",
}
: {
accessKeyId: process.env.TT_OCSP_AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.TT_OCSP_AWS_SECRET_ACCESS_KEY,
};

export const dynamoDbClient = new AWS.DynamoDB.DocumentClient(option);
4 changes: 4 additions & 0 deletions netlify/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,7 @@ export const getEncryptedDocument = async ({

return { encryptedDocument, encryptedDocumentKey: key };
};

export const normalizeHash = (documentHash) => {
return documentHash.startsWith("0x") ? documentHash : `0x${documentHash}`;
};

0 comments on commit fabc66e

Please sign in to comment.