Skip to content
This repository has been archived by the owner on May 15, 2021. It is now read-only.

Commit

Permalink
Ch1152/latest share kit (#2)
Browse files Browse the repository at this point in the history
* Remove env configuration from heroku app.json config

* Update share-kit to 4.0.1

* Add "dom" to lib in tsconfig for type `HTMLElement` in share-kit dep

* Delete a ton of code that was ported over to share-kit

* Add better error handling
  • Loading branch information
edhedges committed Apr 23, 2019
1 parent 335f78e commit 799758e
Show file tree
Hide file tree
Showing 7 changed files with 505 additions and 407 deletions.
5 changes: 1 addition & 4 deletions app.json
Expand Up @@ -2,8 +2,5 @@
"name": "receive-kit",
"description": "Easily receive and validate data from share-kit.",
"repository": "https://github.com/hellobloom/receive-kit",
"keywords": ["node", "express", "bloom", "receive-kit"],
"env": {
"WEB3_PROVIDER": true
}
"keywords": ["node", "express", "bloom", "receive-kit"]
}
151 changes: 41 additions & 110 deletions index.ts
@@ -1,131 +1,62 @@
import * as dotenv from "dotenv";
dotenv.config();

import express from "express";
import { ResponseData, util as shareKitUtil } from "@bloomprotocol/share-kit";
import { IVerifiedData } from "@bloomprotocol/share-kit/dist/src/types";
import { TDecodedLog, getDecodedTxEventLogs } from "./txUtils";
import { sortObject, isNullOrWhiteSpace } from "./utils";
import {
validateRequestFormat,
validateBasicOffChainProperties,
validateOnChainProperties
} from "./validation";
import express, { ErrorRequestHandler } from "express";
import { validateUntypedResponseData } from "@bloomprotocol/share-kit";

const app = express();
const port = process.env.PORT;
if (!port) {
throw Error("Missing required PORT environment variable");
}
const provider = process.env.WEB3_PROVIDER;
if (!provider) {
const validateOnChain =
typeof process.env.VALIDATE_ON_CHAIN === "string" &&
process.env.VALIDATE_ON_CHAIN.toLowerCase() === "true";
const web3Provider = process.env.WEB3_PROVIDER;
if (validateOnChain && !web3Provider) {
throw Error("Missing required WEB3_PROVIDER environment variable");
}

app.listen(port, () => console.log(`Express server running on port ${port}`));
app.use(express.json());

app.post(
"/api/receive",
async (req: express.Request, res: express.Response) => {
// Ensure the structure of the JSON is formatted properly
const reqFormatValidation = validateRequestFormat(req);
if (reqFormatValidation.length) {
console.log(
`reqFormatValidation: ${JSON.stringify(reqFormatValidation)}`
);
return res.status(400).json({ errors: reqFormatValidation });
}

const shareKitResData: ResponseData = sortObject(req.body);
shareKitResData.data = shareKitResData.data.map(d => sortObject(d));

// Validate the integrity of basic off-chain properties (subject, packedData)
const basicOffChainValidation = validateBasicOffChainProperties(
shareKitResData
);
if (basicOffChainValidation.length) {
console.log(
`basicOffChainValidation: ${JSON.stringify(basicOffChainValidation)}`
);
return res.status(400).json({
errors: basicOffChainValidation
try {
const output = await validateUntypedResponseData(req.body, {
validateOnChain,
web3Provider
});
}

// Verify the off-chain data integrity of each data node
const offChainValidation = shareKitResData.data.map(d => ({
layer2Hash: d.layer2Hash,
errors: shareKitUtil.verifyOffChainDataIntegrity(d)
}));
const hasOffChainVerificationErrors = !offChainValidation.every(
v => v.errors.length === 0
);
if (hasOffChainVerificationErrors) {
console.log(
`offChainVerifications: ${JSON.stringify(offChainValidation)}`
);
return res.status(400).json({
errors: offChainValidation
if (output.errors && output.errors.length > 0) {
return res.status(400).json({ errors: output.errors });
}
return res.status(200).json({
success: true,
token: req.body.token
});
}

// Verify the on-chain data integrity
const txReceiptRetrievalErrors: {
layer2Hash: string;
error: string;
}[] = [];
const decodedDataAndLogs: {
shareData: IVerifiedData;
logs: TDecodedLog[];
}[] = [];
await Promise.all(
shareKitResData.data
.filter(d => !isNullOrWhiteSpace(d.tx) && d.tx !== "0x")
.map(async shareData => {
try {
decodedDataAndLogs.push({
shareData,
logs: await getDecodedTxEventLogs(provider, shareData.tx)
});
} catch (err) {
txReceiptRetrievalErrors.push({
layer2Hash: shareData.layer2Hash,
error: `${err}`
});
}
})
);
if (txReceiptRetrievalErrors.length) {
console.log(
`txReceiptRetrievalErrors: ${JSON.stringify(txReceiptRetrievalErrors)}`
);
return res.status(400).json({
errors: txReceiptRetrievalErrors
} catch (err) {
console.log("/api/receive catch", err);
return res.status(500).json({
error:
err && err.message ? err.message : "An unexpected error has occurred."
});
}

if (
typeof process.env.VALIDATE_ON_CHAIN === "string" &&
process.env.VALIDATE_ON_CHAIN.toLowerCase() === "true"
) {
const onChainValidation = validateOnChainProperties(
shareKitResData.subject,
decodedDataAndLogs
);
if (onChainValidation.length) {
console.log(
`onChainVerifications: ${JSON.stringify(onChainValidation)}`
);
return res.status(400).json({
errors: onChainValidation
});
}
}

return res.status(200).json({
success: true,
token: req.body.token
});
}
);

const catchallErrorHandler: ErrorRequestHandler = (err, _req, res, next) => {
if (res.headersSent) {
return next(err);
}
return res.status(500).json({
error:
err && err.message ? err.message : "An unexpected error has occurred."
});
};
app.use(catchallErrorHandler);

process.on("unhandledRejection", error => {
if (error) {
console.log("unhandledRejection", error);
}
});

app.listen(port, () => console.log(`Express server running on port ${port}`));

0 comments on commit 799758e

Please sign in to comment.