-
Notifications
You must be signed in to change notification settings - Fork 4
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 #106 from edgio-docs/ef-request-signing
Add request signing example
- Loading branch information
Showing
28 changed files
with
13,241 additions
and
5,896 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 |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"extends": "next/core-web-vitals" | ||
} |
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,5 +1,45 @@ | ||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||
|
||
# dependencies | ||
/node_modules | ||
/.pnp | ||
.pnp.js | ||
.yarn/install-state.gz | ||
|
||
# testing | ||
/coverage | ||
|
||
# next.js | ||
/.next/ | ||
/out/ | ||
|
||
# production | ||
/build | ||
|
||
# misc | ||
.DS_Store | ||
*.pem | ||
|
||
# debug | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
|
||
# local env files | ||
.env*.local | ||
|
||
# vercel | ||
.vercel | ||
|
||
# typescript | ||
*.tsbuildinfo | ||
next-env.d.ts | ||
|
||
# Temporary Edgio files | ||
.edgio | ||
|
||
# Node.js modules | ||
node_modules | ||
|
||
# Edgio generated build directory | ||
.edgio |
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,16 @@ | ||
import '../../utils/polyfills/URL'; | ||
|
||
export async function handleHttpRequest(request, context) { | ||
// Retrieve the client's IP address from the context object | ||
const clientIP = context.client.dst_addr; | ||
|
||
const newRequest = new Request(request.url, request); | ||
|
||
// Add the true-client-ip header to the incoming request | ||
newRequest.headers.set('true-client-ip', clientIP); | ||
|
||
// Continue with the modified request | ||
return fetch(newRequest, { | ||
edgio: { origin: 'echo' }, | ||
}); | ||
} |
18 changes: 18 additions & 0 deletions
18
examples/v7-edge-functions/functions/general/redirect-country.js
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,18 @@ | ||
export async function handleHttpRequest(request, context) { | ||
const country = 'DE'; // Choose a country code | ||
const newUrl = `${request.url}/${country}`; // Change the redirect URL to your choice | ||
|
||
if (context.geo.country === country) { | ||
return new Response(null, { | ||
status: 302, | ||
statusText: 'Found', | ||
headers: { | ||
Location: newUrl, | ||
}, | ||
}); | ||
} | ||
|
||
return fetch(request.url, { | ||
edgio: { origin: 'echo' }, | ||
}); | ||
} |
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
25 changes: 25 additions & 0 deletions
25
examples/v7-edge-functions/functions/general/security-response-headers.js
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,25 @@ | ||
export async function handleHttpRequest(request, context) { | ||
// Fetch the response from the 'echo' origin | ||
const response = await fetch(new Request(request.url, request), { | ||
edgio: { | ||
origin: 'echo', | ||
}, | ||
}); | ||
|
||
// Set HTTP security headers | ||
response.headers.set( | ||
'strict-transport-security', | ||
'max-age=63072000; includeSubdomains; preload' | ||
); | ||
response.headers.set( | ||
'content-security-policy', | ||
"default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self'; object-src 'none'; frame-ancestors 'none'" | ||
); | ||
response.headers.set('x-content-type-options', 'nosniff'); | ||
response.headers.set('x-frame-options', 'DENY'); | ||
response.headers.set('x-xss-protection', '1; mode=block'); | ||
response.headers.set('referrer-policy', 'same-origin'); | ||
|
||
// Return the response to the client | ||
return response; | ||
} |
110 changes: 110 additions & 0 deletions
110
examples/v7-edge-functions/functions/general/signed-request/main.js
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,110 @@ | ||
import { URL } from 'whatwg-url'; | ||
import HmacSHA1 from 'crypto-js/hmac-sha1'; | ||
import Base64 from 'crypto-js/enc-base64'; | ||
import createFetchForOrigin from '../../../utils/createFetchForOrigin'; | ||
|
||
const fetch = createFetchForOrigin('echo', { | ||
edgio: { | ||
caching: { | ||
bypass_cache: true, | ||
}, | ||
}, | ||
}); | ||
|
||
export async function handleHttpRequest(request, context) { | ||
// ** IMPORTANT ** | ||
// Secret key should be defined as an environment variable in the Edgio console | ||
const secretKey = '$0m3th!ngS3cr3t'; // context.environmentVars.REQ_SIGNING_SECRET_KEY; | ||
|
||
if (request.url.includes('/sign/')) { | ||
return generateSignedUrl(request, secretKey); | ||
} | ||
|
||
return verifyAndFetch(request, secretKey); | ||
} | ||
|
||
/** | ||
* Generates a signed URL for the given URL and secret key | ||
* @param {URL} url | ||
* @param {string} secretKey | ||
*/ | ||
async function generateSignedUrl(request, key) { | ||
const url = new URL(request.url); | ||
|
||
// Replace /sign/ with /verify/ in the URL since we are generating a signed URL for verification | ||
url.pathname = url.pathname.replace('/sign/', '/verify/'); | ||
|
||
const expirationMs = 1000 * 60 * 5; // 5 minutes | ||
const expiry = Date.now() + expirationMs; | ||
const dataToAuthenticate = url.pathname + expiry; | ||
|
||
const hash = HmacSHA1(dataToAuthenticate, key); | ||
const base64Mac = Base64.stringify(hash); | ||
|
||
url.searchParams.set('mac', base64Mac); | ||
url.searchParams.set('expiry', expiry.toString()); | ||
|
||
const validUrl = url.toString(); | ||
const modifiedExpiryUrl = new URL(validUrl); | ||
modifiedExpiryUrl.searchParams.set('expiry', `${expiry + 5}`); | ||
const modifiedMacUrl = new URL(validUrl); | ||
modifiedMacUrl.searchParams.set('mac', `${base64Mac}x`); | ||
|
||
console.log('Valid URL:\n', validUrl); | ||
console.log('Modified expiry URL:\n', modifiedExpiryUrl.toString()); | ||
console.log('Modified MAC URL:\n', modifiedMacUrl.toString()); | ||
|
||
const htmlResponse = ` | ||
<html> | ||
<body> | ||
<p>Click the following links for verification:</p> | ||
<ul> | ||
<li><a href="${validUrl}">Valid URL</a><pre>(${validUrl})</pre></li> | ||
<li><a href="${modifiedExpiryUrl}">Invalid with modified Expiry URL</a><pre>(${modifiedExpiryUrl})</pre></li> | ||
<li><a href="${modifiedMacUrl}">Invalid with modified Mac URL</a><pre>(${modifiedMacUrl})</pre></li> | ||
</ul> | ||
</body> | ||
</html> | ||
`; | ||
|
||
return new Response(htmlResponse, { | ||
headers: { 'Content-Type': 'text/html' }, | ||
}); | ||
} | ||
|
||
/** | ||
* Verifies the MAC and expiry of the given URL. If the URL is valid, the request is forwarded to the origin. | ||
*/ | ||
async function verifyAndFetch(request, key) { | ||
const invalidResponse = (reason) => | ||
new Response(`Invalid request - ${reason}`, { status: 403 }); | ||
const url = new URL(request.url); | ||
|
||
if (!url.searchParams.has('mac') || !url.searchParams.has('expiry')) { | ||
return invalidResponse('Missing MAC or expiry'); | ||
} | ||
|
||
const expiry = Number(url.searchParams.get('expiry')); | ||
const dataToAuthenticate = url.pathname + expiry; | ||
|
||
const receivedMacBase64 = url.searchParams.get('mac'); | ||
const receivedMac = Base64.parse(receivedMacBase64); | ||
|
||
const hash = HmacSHA1(dataToAuthenticate, key); | ||
const hashInBase64 = Base64.stringify(hash); | ||
|
||
// Ensure that the MAC is valid | ||
if (hashInBase64 !== receivedMacBase64) { | ||
return invalidResponse('Invalid MAC'); | ||
} | ||
|
||
// Ensure that the URL has not expired | ||
if (Date.now() > expiry) { | ||
return invalidResponse('URL has expired'); | ||
} | ||
|
||
// Forward the remaining request path after **/verify/* to the origin | ||
url.pathname = url.pathname.split('/verify/')[1]; | ||
|
||
return fetch(url.toString()); | ||
} |
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,8 @@ | ||
{ | ||
"compilerOptions": { | ||
"jsx": "react", | ||
"paths": { | ||
"@/*": ["./src/*"] | ||
} | ||
} | ||
} |
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,13 @@ | ||
// This file was automatically added by edgio init. | ||
// You should commit this file to source control. | ||
const { withEdgio } = require('@edgio/next/config') | ||
|
||
/** @type {import('next').NextConfig} */ | ||
const nextConfig = {} | ||
|
||
const _preEdgioExport = nextConfig;; | ||
|
||
module.exports = (phase, config) => | ||
withEdgio({ | ||
..._preEdgioExport | ||
}) |
Oops, something went wrong.