This repository has been archived by the owner on May 15, 2021. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* 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
Showing
7 changed files
with
505 additions
and
407 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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}`)); |
Oops, something went wrong.