Skip to content

Commit c694f43

Browse files
Additional implementation examples
1 parent 7967b6c commit c694f43

4 files changed

Lines changed: 250 additions & 0 deletions

File tree

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
"use strict";
2+
//include crowdhandler-sdk
3+
const crowdhandler = require("crowdhandler-sdk");
4+
const publicKey = "YOUR_PUBLIC_KEY_HERE";
5+
6+
let ch_client = new crowdhandler.PublicClient(publicKey, { timeout: 2000 });
7+
8+
module.exports.viewerRequest = async (event) => {
9+
//extract the request from the event
10+
let request = event.Records[0].cf.request;
11+
let decodedBody;
12+
let chToken;
13+
let sourceURL;
14+
15+
//if the request is not a POST or PUT request, return the request unmodified
16+
if (request.method !== "POST" || request.method !== "PUT" ) {
17+
return request;
18+
}
19+
20+
if (request.body && request.body.encoding === "base64") {
21+
// Decode the base64 encoded body
22+
decodedBody = Buffer.from(request.body.data, "base64").toString("utf8");
23+
24+
// Parse the JSON encoded body
25+
try {
26+
// Parse the decoded body into a JSON object
27+
decodedBody = JSON.parse(decodedBody);
28+
//destructure sourceURL, chToken from the decoded body
29+
chToken = decodedBody.chToken;
30+
sourceURL = decodedBody.sourceURL;
31+
32+
// Now you can work with the JSON object
33+
} catch (error) {
34+
console.error("Error parsing JSON:", error);
35+
36+
// Handle the error or return the request object unmodified
37+
return request;
38+
}
39+
}
40+
41+
//extract host & path from sourceURL using URL API
42+
let url = new URL(sourceURL);
43+
let temporaryHost = url.host;
44+
let temporaryPath = url.pathname;
45+
46+
//Filter the event through the Request Context class
47+
let ch_context = new crowdhandler.RequestContext({ lambdaEvent: event });
48+
//Instantiate the Gatekeeper class
49+
let ch_gatekeeper = new crowdhandler.Gatekeeper(
50+
ch_client,
51+
ch_context,
52+
{
53+
publicKey: publicKey,
54+
},
55+
{ debug: true }
56+
);
57+
58+
//Override the gatekeeper host with the sourceURL
59+
ch_gatekeeper.overrideHost(temporaryHost);
60+
//Override the gatekeeper path with the sourceURL
61+
ch_gatekeeper.overridePath(temporaryPath);
62+
63+
//If there's a token in the body provide gatekeeper with a pseudo cookie so that it can check that the provided token is valid/promoted
64+
if (chToken) {
65+
ch_gatekeeper.overrideCookie(`crowdhandler=${chToken}`);
66+
}
67+
68+
//Validate the request
69+
let ch_status = await ch_gatekeeper.validateRequest();
70+
71+
//If the request is not promoted, reject the request
72+
if (!ch_status.promoted) {
73+
return {
74+
status: "403",
75+
statusDescription: "Forbidden",
76+
headers: {
77+
"content-type": [
78+
{
79+
key: "Content-Type",
80+
value: "text/plain",
81+
},
82+
],
83+
"cache-control": [
84+
{
85+
key: "Cache-Control",
86+
value: "max-age=0",
87+
},
88+
],
89+
},
90+
body: "Access to this resource is forbidden.",
91+
};
92+
}
93+
94+
//If the request is promoted, allow it to proceed normally
95+
//set customer headers for recording performance on the request before passing it through
96+
request.headers["x-crowdhandler-responseID"] = [
97+
{ key: "x-crowdhandler-responseID", value: `${ch_status.responseID}` },
98+
];
99+
request.headers["x-crowdhandler-startTime"] = [
100+
{ key: "x-crowdhandler-startTime", value: `${Date.now()}` },
101+
];
102+
103+
//return the request
104+
return request;
105+
};
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
const crowdhandler = require("crowdhandler-sdk");
2+
const publicKey = "YOUR_PUBLIC_KEY_HERE";
3+
4+
let ch_client = new crowdhandler.PublicClient(publicKey, { timeout: 2000 });
5+
6+
module.exports.originResponse = async (event) => {
7+
let request = event.Records[0].cf.request;
8+
let requestHeaders = event.Records[0].cf.request.headers;
9+
let response = event.Records[0].cf.response;
10+
let responseStatus = response.status;
11+
12+
//convert response status to number
13+
responseStatus = parseInt(responseStatus);
14+
15+
//extract the custom headers that we passed through from the viewerRequest event
16+
let responseID;
17+
let startTime;
18+
19+
try {
20+
responseID = requestHeaders["x-crowdhandler-responseid"][0].value;
21+
} catch (e) {}
22+
23+
try {
24+
startTime = requestHeaders["x-crowdhandler-starttime"][0].value;
25+
} catch (e) {}
26+
27+
//Work out how long we spent processing at the origin
28+
let elapsed = Date.now() - startTime;
29+
30+
let ch_context = new crowdhandler.RequestContext({ lambdaEvent: event });
31+
32+
//Instantiate the Gatekeeper class
33+
let ch_gatekeeper = new crowdhandler.Gatekeeper(
34+
ch_client,
35+
ch_context,
36+
{
37+
publicKey: publicKey,
38+
},
39+
{ debug: true }
40+
);
41+
42+
//If we don't have a responseID or a startTime, we can't record the performance
43+
if (!responseID || !startTime) {
44+
return response;
45+
}
46+
47+
//This is a throw away request. We don't need to wait for a response.
48+
await ch_gatekeeper.recordPerformance({
49+
overrideElapsed: elapsed,
50+
responseID: responseID,
51+
sample: 1,
52+
statusCode: responseStatus,
53+
});
54+
55+
//Fin
56+
return response;
57+
};
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
const express = require("express");
2+
const router = express.Router();
3+
const crowdhandler = require("crowdhandler-sdk");
4+
const { URL } = require("url");
5+
6+
// Middleware to handle CrowdHandler logic for POST and PUT methods
7+
const crowdHandlerMiddleware = async (req, res, next) => {
8+
const method = req.method;
9+
10+
// Check if the request method is POST or PUT
11+
if (method === "POST" || method === "PUT") {
12+
const publicKey = "YOUR_PUBLIC_KEY";
13+
const public_client = new crowdhandler.PublicClient(publicKey);
14+
const ch_context = new crowdhandler.RequestContext(req, res);
15+
const ch_gatekeeper = new crowdhandler.Gatekeeper(
16+
public_client,
17+
ch_context,
18+
publicKey
19+
);
20+
21+
let decodedBody;
22+
let chToken;
23+
let sourceURL;
24+
25+
if (req.body) {
26+
try {
27+
decodedBody = JSON.parse(req.body);
28+
chToken = decodedBody.chToken;
29+
sourceURL = decodedBody.sourceURL;
30+
31+
// Extract host & path from sourceURL
32+
let url = new URL(sourceURL);
33+
let temporaryHost = url.host;
34+
let temporaryPath = url.pathname;
35+
36+
// Override the gatekeeper host and path with the sourceURL
37+
ch_gatekeeper.overrideHost(temporaryHost);
38+
ch_gatekeeper.overridePath(temporaryPath);
39+
40+
// If there's a token in the body, provide gatekeeper with a pseudo cookie
41+
if (chToken) {
42+
ch_gatekeeper.overrideCookie(`crowdhandler=${chToken}`);
43+
}
44+
} catch (error) {
45+
console.error("Error parsing JSON:", error);
46+
return next(error);
47+
}
48+
}
49+
50+
const ch_status = await ch_gatekeeper.validateRequest();
51+
52+
// If the request is not promoted, send a 403 Forbidden response and do not proceed to the next middleware
53+
if (!ch_status.promoted) {
54+
res.status(403).send("Forbidden");
55+
return;
56+
} else {
57+
// If the request is promoted, save the ch_gatekeeper instance in res.locals for later use
58+
res.locals.ch_gatekeeper = ch_gatekeeper;
59+
}
60+
}
61+
// Continue to the next middleware or route handler
62+
next();
63+
};
64+
65+
// Add the CrowdHandler middleware to the router
66+
router.use(crowdHandlerMiddleware);
67+
68+
// Route handler for all request methods and paths
69+
router.all("*", (req, res, next) => {
70+
// Render the view and send the HTML
71+
res.render("index", { title: "hello" }, (err, html) => {
72+
// Handle any errors during rendering
73+
if (err) {
74+
return next(err);
75+
}
76+
77+
// Send the rendered HTML to the client
78+
res.send(html);
79+
80+
// If the ch_gatekeeper instance exists in res.locals, record the performance
81+
if (res.locals.ch_gatekeeper) {
82+
res.locals.ch_gatekeeper.recordPerformance();
83+
}
84+
});
85+
});
86+
87+
// Export the router
88+
module.exports = router;
File renamed without changes.

0 commit comments

Comments
 (0)