Created
May 24, 2020 05:42
-
-
Save stickfigure/af592b1ce7f888c5b8a4efbe5afb9d03 to your computer and use it in GitHub Desktop.
Cloudflare worker that proxies encrypted urls
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
addEventListener('fetch', event => { | |
event.respondWith(handleRequest(event.request)) | |
}) | |
const encoder = new TextEncoder(); | |
const decoder = new TextDecoder(); | |
const SECRET_KEY_DATA = encoder.encode('YOUR SECRET KEY'); | |
function normalizeBase64(base64urlencoded) { | |
return base64urlencoded.replace(/-/g, '+').replace(/_/g, '/'); | |
} | |
function base64Decode(str) { | |
const normal = normalizeBase64(str); | |
return Uint8Array.from(atob(normal), c => c.charCodeAt(0)); | |
} | |
async function decrypt(encrypted) { | |
const encryptedBytes = base64Decode(encrypted); | |
const iv = encryptedBytes.subarray(0, 16); | |
const cipherText = encryptedBytes.subarray(16); | |
const decryptKey = await crypto.subtle.importKey( | |
'raw', | |
SECRET_KEY_DATA, | |
'AES-CBC', | |
false, | |
['decrypt'] | |
); | |
const decrypted = await crypto.subtle.decrypt( | |
{name: "AES-CBC", iv: iv}, | |
decryptKey, | |
cipherText | |
); | |
return decoder.decode(decrypted); | |
} | |
async function verify(data, signature) { | |
const signatureBytes = base64Decode(signature); | |
const verifyKey = await crypto.subtle.importKey( | |
'raw', | |
SECRET_KEY_DATA, | |
{name: 'HMAC', hash: 'SHA-256'}, | |
false, | |
['verify'] | |
); | |
return crypto.subtle.verify( | |
'HMAC', | |
verifyKey, | |
signatureBytes, | |
encoder.encode(data) | |
); | |
} | |
async function handleRequest(request) { | |
// a request looks like: https://your.domain/encryptedurl/signature | |
// both encryptedurl and signature are hex encoded | |
const urlparts = request.url.split('/'); | |
const signature = urlparts[urlparts.length-1]; | |
const encrypted = urlparts[urlparts.length-2]; | |
// console.log(`encrypted url is ${encrypted}`); | |
// console.log(`signature is ${signature}`); | |
const url = await decrypt(encrypted); | |
// console.log(`url is ${url}`); | |
const verified = await verify(url, signature); | |
if (!verified) | |
return new Response('Invalid signature', { status: 400 }) | |
return fetch(url, request); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment