UNPKG

@transcend-io/typescript-webhook-example

Version:

Example of a webhook that can be integrated with Transcend.

116 lines 4.98 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const got_1 = __importDefault(require("got")); // Helpers const helpers_1 = require("./helpers"); // Constants const constants_1 = require("./constants"); const logger_1 = require("./logger"); const path = require('path'); const fs = require('fs'); // User data const FRIENDS = JSON.parse(fs.readFileSync(path.join(constants_1.MEDIA_FOLDER, 'friends.json'), 'utf8')); // Mock database // this is used for the purposes of demoing const MockDatabaseModel = { findAll: ({ limit, offset, }) => FRIENDS.slice(offset, offset + limit), }; /** * Process an access request for this user and upload the result to Transcend * * @param userIdentifier - User identifier * @param nonce - Nonce to respond with * @param requestLink - Link to request */ async function scheduleAccessChunkedRequest(userIdentifier, nonce, requestLink) { logger_1.logger.info(`Uploading data - ${requestLink}`); try { let hasMore = true; let offset = 0; const PAGE_SIZE = 300; // set this as high as you can without overwhelming your database let i = 0; while (hasMore) { const data = await MockDatabaseModel.findAll({ // where: { userId: userIdentifier }, // order: [['createdAt', 'DESC']], limit: PAGE_SIZE, offset, }); hasMore = data.length === PAGE_SIZE; await got_1.default.post({ url: `${constants_1.SOMBRA_URL}/v1/datapoint-chunked`, headers: { authorization: `Bearer ${constants_1.TRANSCEND_API_KEY}`, 'x-sombra-authorization': constants_1.SOMBRA_API_KEY ? `Bearer ${constants_1.SOMBRA_API_KEY}` : undefined, 'x-transcend-nonce': nonce, 'content-type': 'application/json', }, json: { fileId: `Page ${i} -- ${offset} - ${offset + data.length}`, dataPointName: 'friends', data, isLastPage: !hasMore, }, }); offset += PAGE_SIZE; i += 1; logger_1.logger.info(`Sent page ${i}`); } logger_1.logger.info(`Successfully uploaded data - ${requestLink}`); } catch (error) { const typedError = error; logger_1.logger.error(`Failed to upload data - ${requestLink} - ${typedError.message}`); } } /** * DSR webhook handler for large amounts of data that need to be paginated. * * @param req - Express request object * @param res - Express response object * @see https://docs.transcend.io/docs/api-reference/POST/v1/datapoint-chunked * @see https://docs.transcend.io/docs/api-reference/webhook/new-privacy-request-job */ async function handleDSRWebhookPaginated(req, res) { // Verify the incoming webhook is coming from Transcend, and via the Sombra gateway. try { await (0, helpers_1.verifyWebhook)(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!'); } logger_1.logger.info(`Received DSR webhook - ${req.body.extras.request.link}`); // Extract metadata from the body // req.body.extras.profile.type will tell you if this is an email vs username, vs other identifier const userIdentifier = req.body.extras.profile.identifier; const webhookType = req.body.type; // ACCESS, ERASURE, etc: https://docs.transcend.io/docs/receiving-webhooks#events let nonce = req.headers['x-transcend-nonce']; nonce = Array.isArray(nonce) ? nonce.join() : 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). scheduleAccessChunkedRequest(userIdentifier, nonce, req.body.extras.request.link); // Respond OK - webhook received properly. res.sendStatus(200); break; case 'ERASURE': res.sendStatus(204); break; default: logger_1.logger.warn(`This type of DSR webhook is unimplemented - ${req.body.extras.request.link}`); return res .status(400) .send('This type of privacy request is unimplemented.'); } logger_1.logger.info(`Successfully responded to DSR webhook - ${req.body.extras.request.link}`); return null; } exports.default = handleDSRWebhookPaginated; //# sourceMappingURL=handleDSRWebhookPaginated.js.map