Skip to content

Commit 44a35b7

Browse files
committed
2 parents c9d06a9 + fad6446 commit 44a35b7

File tree

11 files changed

+216
-4221
lines changed

11 files changed

+216
-4221
lines changed

index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ const {
5353
eg010admin, eg011admin, eg012admin
5454
} = require('./lib/admin/controllers');
5555

56+
const { eg001connect } = require('./lib/connect/controllers');
57+
5658
const PORT = process.env.PORT || 3000;
5759
const HOST = process.env.HOST || 'localhost';
5860
const max_session_min = 180;
@@ -267,6 +269,9 @@ app.get('/eg001', eg001.getController)
267269
.get('/eg044', eg044.getController)
268270
.post('/eg044', eg044.createController);
269271

272+
app.get('/cneg001', eg001connect.getController)
273+
.post('/cneg001', eg001connect.createController);
274+
270275
function dsLoginCB1(req, res, next) { req.dsAuthCodeGrant.oauth_callback1(req, res, next); }
271276
function dsLoginCB2(req, res, next) { req.dsAuthCodeGrant.oauth_callback2(req, res, next); }
272277

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/**
2+
* @file
3+
* Example 001: Validate webhook message using HMAC
4+
* @author DocuSign
5+
*/
6+
7+
const path = require('path');
8+
const validator = require('validator');
9+
const { formatString, API_TYPES } = require('../../utils.js');
10+
const { getExampleByNumber } = require('../../manifestService');
11+
const dsConfig = require('../../../config/index.js').config;
12+
const { computeHash } = require('../examples/validateWebhookMessage');
13+
14+
const eg001ValidateWebhookMessage = exports;
15+
const exampleNumber = 1;
16+
const eg = `cneg00${exampleNumber}`; // This example reference.
17+
const api = API_TYPES.CONNECT;
18+
const mustAuthenticate = '/ds/mustAuthenticateJWT';
19+
20+
/**
21+
* Create the envelope
22+
* @param {object} req Request obj
23+
* @param {object} res Response obj
24+
*/
25+
eg001ValidateWebhookMessage.createController = async (req, res) => {
26+
// Call the worker method
27+
const { body } = req;
28+
const args = {
29+
secret: validator.escape(body.secret),
30+
payload: body.payload,
31+
};
32+
let results = null;
33+
34+
try {
35+
results = computeHash(args);
36+
} catch (error) {
37+
const errorCode = error?.code;
38+
const errorMessage = error?.message;
39+
// In production, may want to provide customized error messages and
40+
// remediation advice to the user.
41+
res.render('pages/error', { err: error, errorCode, errorMessage });
42+
}
43+
if (results) {
44+
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
45+
res.render('pages/example_done', {
46+
title: example.ExampleName,
47+
message: formatString(example.ResultsPageText, results),
48+
});
49+
}
50+
};
51+
52+
/**
53+
* Form page for this application
54+
*/
55+
eg001ValidateWebhookMessage.getController = (req, res) => {
56+
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
57+
const sourceFile =
58+
path.basename(__filename)[5].toLowerCase() +
59+
path.basename(__filename).substr(6);
60+
res.render('pages/connect-examples/eg001ValidateWebhookMessage', {
61+
eg: eg,
62+
csrfToken: req.csrfToken(),
63+
example: example,
64+
sourceFile: sourceFile,
65+
sourceUrl: dsConfig.githubExampleUrl + 'connect/examples/' + sourceFile,
66+
documentation: dsConfig.documentation + eg,
67+
showDoc: dsConfig.documentation,
68+
});
69+
};

lib/connect/controllers/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports.eg001connect = require('./eg001ValidateWebhookMessage');
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* @file
3+
* Example 001: Validate webhook message using HMAC
4+
* @author DocuSign
5+
*/
6+
7+
const crypto = require('crypto');
8+
9+
/**
10+
* This function computes the hash.
11+
* @param {object} args parameters for computing the hash.
12+
* @param {string} args.secret hmac secret key.
13+
* @param {string} args.payload plain text payload.
14+
* @return {string} Computed hash.
15+
*/
16+
const computeHash = (args) => {
17+
const hmac = crypto.createHmac('sha256', args.secret);
18+
hmac.write(args.payload);
19+
hmac.end();
20+
return hmac.read().toString('base64');
21+
};
22+
23+
/**
24+
* This function validates a webhook message.
25+
* @param {object} args parameters for validating the message.
26+
* @param {string} args.verify hash value as base64 string.
27+
* @param {string} args.secret hmac secret key.
28+
* @param {string} args.payload plain text payload.
29+
* @return {boolean} Returns true if the provided hash matches the computed hash, otherwise false.
30+
*/
31+
const isHashValid = (args) => {
32+
return crypto.timingSafeEqual(Buffer.from(args.verify, 'base64'), Buffer.from(computeHash(args), 'base64'));
33+
};
34+
35+
module.exports = { computeHash, isHashValid };

lib/utils.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const API_TYPES = {
1616
CLICK: 'Click',
1717
ROOMS: 'Rooms',
1818
ADMIN: 'Admin',
19+
CONNECT: 'Connect',
1920
};
2021

2122
async function isCFR(accessToken, accountId, basePath) {

0 commit comments

Comments
 (0)