-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 from transcend-io/bencmbrook/eshopit
eShopIt demo
- Loading branch information
Showing
19 changed files
with
2,165 additions
and
545 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,5 +5,6 @@ | |
"venv", | ||
"webhook", | ||
"webhooks" | ||
] | ||
} | ||
], | ||
"editor.formatOnSave": true | ||
} |
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 |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"printWidth": 100, | ||
"singleQuote": true, | ||
"trailingComma": "all" | ||
} |
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 |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"extends": ["airbnb", "plugin:prettier/recommended"], | ||
"plugins": ["prettier"], | ||
"rules": { | ||
"prettier/prettier": ["error"] | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
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,21 +1,32 @@ | ||
{ | ||
"name": "demo", | ||
"name": "eshopit", | ||
"version": "1.0.0", | ||
"description": "", | ||
"main": "index.js", | ||
"description": "Example of an application integrated with Transcend.", | ||
"main": "src/app.js", | ||
"scripts": { | ||
"start": "node index.js", | ||
"start": "node src/app.js", | ||
"dev": "nodemon src/app.js", | ||
"ngrok": "ngrok http 8081", | ||
"lint": "eslint", | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
}, | ||
"author": "", | ||
"author": "Transcend Inc.", | ||
"license": "ISC", | ||
"dependencies": { | ||
"body-parser": "^1.18.3", | ||
"express": "^4.16.4", | ||
"jws": "^4.0.0", | ||
"request": "^2.88.0" | ||
"body-parser": "^1.19.0", | ||
"dotenv": "^8.2.0", | ||
"express": "^4.17.1", | ||
"express-async-handler": "^1.1.4", | ||
"got": "^11.6.2", | ||
"jsonwebtoken": "^8.5.1", | ||
"morgan": "^1.10.0" | ||
}, | ||
"devDependencies": { | ||
"ngrok": "^3.1.0" | ||
"eslint": "^7.9.0", | ||
"eslint-config-airbnb": "^18.2.0", | ||
"eslint-config-prettier": "^6.11.0", | ||
"eslint-plugin-prettier": "^3.1.4", | ||
"nodemon": "^2.0.4", | ||
"prettier": "^2.1.2" | ||
} | ||
} |
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 |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/* | ||
* Developer note: this server is live at https://transcend-example.onrender.com for the eShopIt demo | ||
* https://e-shop-it.trsnd.co | ||
*/ | ||
|
||
// Load environment variables | ||
require('dotenv').config(); | ||
|
||
// Libraries | ||
const express = require('express'); | ||
const bodyParser = require('body-parser'); | ||
const morgan = require('morgan'); | ||
|
||
// Load webhook handling middlewares | ||
const handleEnrichmentWebhook = require('./handleEnrichmentWebhook'); | ||
const handleDSRWebhook = require('./handleDSRWebhook'); | ||
|
||
// Constants | ||
const { | ||
PORT | ||
} = require('./constants'); | ||
|
||
// Set up the server | ||
const app = express(); | ||
const port = PORT; | ||
app.all('/health', (_, res) => res.sendStatus(200)); | ||
|
||
// Middlewares | ||
app.use(morgan('tiny')); | ||
|
||
app.use( | ||
bodyParser.urlencoded({ | ||
extended: false, | ||
}), | ||
); | ||
|
||
app.use(bodyParser.json()); | ||
|
||
/* | ||
* Receive webhook for identity enrichment (optional) | ||
* This path is set by you in the Admin Dashboard. | ||
*/ | ||
app.post( | ||
'/transcend/enrichment', | ||
handleEnrichmentWebhook, | ||
); | ||
|
||
/* | ||
* Receive webhook (Transcend's notification to this server) | ||
* This path is set by you in the Admin Dashboard. | ||
*/ | ||
app.post( | ||
'/transcend/new-dsr', | ||
handleDSRWebhook, | ||
); | ||
|
||
app.listen(port, () => console.info(`Example custom data silo listening on port ${port}.`)); |
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 |
---|---|---|
@@ -0,0 +1,11 @@ | ||
const { | ||
TRANSCEND_API_KEY, | ||
ENRICHMENT_SIGNING_KEY, | ||
PORT, | ||
} = process.env; | ||
|
||
module.exports = { | ||
TRANSCEND_API_KEY, | ||
ENRICHMENT_SIGNING_KEY, | ||
PORT: PORT || 8081, | ||
} |
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 |
---|---|---|
@@ -0,0 +1,51 @@ | ||
const asyncHandler = require('express-async-handler'); | ||
|
||
// Helpers | ||
const { | ||
verifyAndExtractWebhook, | ||
} = require('./helpers'); | ||
|
||
const scheduleAccessRequest = require('./scheduleAccessRequest'); | ||
|
||
///////////////////// | ||
// WEBHOOK HANDLER // | ||
///////////////////// | ||
|
||
module.exports = asyncHandler(async (req, res, next) => { | ||
// Verify the incoming webhook is coming from Transcend, and via the Sombra gateway. | ||
try { | ||
await verifyAndExtractWebhook(req.headers['x-sombra-token']); | ||
} catch (error) { | ||
// If the webhook doesn't pass verification, reject it. | ||
return res.sendStatus(401).send('You are not Transcend!'); | ||
} | ||
|
||
console.info(`Received DSR webhook - https://app.transcend.io${req.body.extras.request.link}`); | ||
|
||
// Extract metadata from the webhook | ||
const userIdentifier = req.body.coreIdentifier.value; | ||
const webhookType = req.body.type; // ACCESS, ERASURE, etc: https://docs.transcend.io/docs/receiving-webhooks#events | ||
const nonce = req.headers['x-transcend-nonce']; | ||
|
||
// Depending on the type of webhook, respond accordingly. | ||
switch (webhookType) { | ||
case 'ACCESS': | ||
// Schedule the job to run. Results of the job are sent to Transcend separately (in a different HTTP request, in case the job is slow). | ||
scheduleAccessRequest(userIdentifier, nonce, req.body.extras.request.link); | ||
|
||
// Respond OK - webhook received properly. | ||
res.sendStatus(200); | ||
break; | ||
|
||
case 'ERASURE': | ||
// Respond with an early "no user found" signal. | ||
res.sendStatus(204); | ||
break; | ||
|
||
default: | ||
console.warn(`This type of DSR webhook is unimplemented - https://app.transcend.io${req.body.extras.request.link}`); | ||
return res.status(400).send('This type of privacy request is unimplemented.'); | ||
} | ||
|
||
console.info(`Successfully responded to DSR webhook - https://app.transcend.io${req.body.extras.request.link}`); | ||
}); |
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 |
---|---|---|
@@ -0,0 +1,69 @@ | ||
const asyncHandler = require('express-async-handler'); | ||
|
||
// Helpers | ||
const { | ||
createEnricherJwt, | ||
checkIfFraudster, | ||
checkForLegalHold, | ||
verifyAndExtractWebhook, | ||
} = require('./helpers'); | ||
|
||
///////////////////// | ||
// WEBHOOK HANDLER // | ||
///////////////////// | ||
|
||
module.exports = asyncHandler(async (req, res, next) => { | ||
// Verify the incoming webhook is coming from Transcend, and via the Sombra gateway. | ||
let signedBody; | ||
try { | ||
signedBody = await verifyAndExtractWebhook(req.headers['x-sombra-token']); | ||
} catch (error) { | ||
// If the webhook doesn't pass verification, reject it. | ||
return res.status(401).send('You are not Transcend!'); | ||
} | ||
|
||
console.info(`Received Enrichment webhook - https://app.transcend.io${req.body.extras.request.link}`); | ||
|
||
// Add new identifers | ||
const signedRequestIdentifiers = { | ||
email: [ | ||
createEnricherJwt({ | ||
value: '[email protected]', | ||
}), | ||
createEnricherJwt({ | ||
value: '[email protected]', | ||
}), | ||
], | ||
phone: [ | ||
createEnricherJwt({ | ||
countryCode: 'US', | ||
number: '+18609066012', | ||
}), | ||
], | ||
}; | ||
|
||
// Check if we should place a hold on this request | ||
const requestIdentifier = signedBody.value; | ||
const isFraudster = await checkIfFraudster(requestIdentifier); | ||
const hasLegalHold = await checkForLegalHold(requestIdentifier); | ||
|
||
// In this case, we are automatically cancelling requests from fraudsters. | ||
if (isFraudster) | ||
return res.json({ | ||
status: 'CANCELED', | ||
}); | ||
|
||
// In this case, we are putting a hold on the request so legal can review it. | ||
if (hasLegalHold) | ||
return res.json({ | ||
status: 'ON_HOLD', | ||
signedRequestIdentifiers, | ||
}); | ||
|
||
// Allow the request to proceed | ||
res.json({ | ||
signedRequestIdentifiers, | ||
}); | ||
|
||
console.info(`Successfully responded to Enrichment webhook - https://app.transcend.io${req.body.extras.request.link}`); | ||
}); |
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 |
---|---|---|
@@ -0,0 +1,10 @@ | ||
/** | ||
* Check user against legal hold | ||
* Is there a reason why we can't fulfill this request right now? | ||
* | ||
* Since this is a demo, it just checks for [email protected] | ||
*/ | ||
module.exports = async function checkForLegalHold(email) { | ||
const flag = email.split('@')[0].split('+')[1]; | ||
return ['legalhold'].includes(flag); | ||
} |
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 |
---|---|---|
@@ -0,0 +1,10 @@ | ||
/** | ||
* Check user against fraud systems | ||
* Is this user suspected of fraud? | ||
* | ||
* Since this is a demo, it just checks for [email protected] | ||
*/ | ||
module.exports = async function checkIfFraudster(email) { | ||
const flag = email.split('@')[0].split('+')[1]; | ||
return ['thefraudster', 'fraud', 'fraudster'].includes(flag); | ||
} |
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 |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// Libraries | ||
const jwt = require('jsonwebtoken'); | ||
|
||
// Constants | ||
const { | ||
ENRICHMENT_SIGNING_KEY, | ||
} = require('../constants'); | ||
|
||
// In this example, the signing key is stored as a base64-encoded env var | ||
const DECODED_ENRICHMENT_SIGNING_KEY = Buffer.from(ENRICHMENT_SIGNING_KEY, 'base64').toString(); | ||
|
||
/** | ||
* Sign an identifier with a JWT | ||
* @param {Object} content | ||
*/ | ||
module.exports = function createEnricherJwt(content) { | ||
return jwt.sign( | ||
// The content to sign | ||
content, | ||
// The private key for the enricher (you should have uploaded the public key) | ||
DECODED_ENRICHMENT_SIGNING_KEY, { | ||
algorithm: 'ES384', | ||
expiresIn: '1d', | ||
// organization URI from https://app.transcend.io/settings#OrganizationSettings | ||
audience: 'e-shop-it', | ||
} | ||
) | ||
}; |
Oops, something went wrong.