import config from "config" import * as crypto from "./crypto" import S3 from "./aws/s3" s3 = new S3 config addEventListener 'fetch', (event) => event.respondWith handleRequest event handleRequest = ({ request }) -> if request.method is "PUT" return handlePUT request else if request.method is "HEAD" return handleHEAD request else if request.method is "GET" return handleGET request return new Response "Not Found", status: 404 handleHEAD = (request) -> url = new URL request.url if url.pathname.endsWith "/" return new Response "Invalid URL", status: 404 resp = await s3.getObject url.pathname[1...], {} return new Response null, status: resp.status statusText: resp.statusText headers: resp.headers handleGET = (request) -> url = new URL request.url if url.pathname.endsWith "/" return new Response "Invalid URL", status: 404 return await s3.getObject url.pathname[1...], {} handlePUT = (request) -> url = new URL request.url # Start from the highest version number valid = false if url.searchParams.has "v2" valid = await verifySignatureV2 url.searchParams.get("v2"), url, request else if url.searchParams.has "v" valid = await verifySignatureV1 url.searchParams.get("v"), url, request unless valid return verifyFailure() # Don't overwrite existing files resp = await s3.getObject url.pathname[1...], {} if resp.ok return new Response "File already exists", status: 400 try await s3.putObject url.pathname[1...], request.body, ContentType: request.headers.get "Content-Type" ContentLength: request.headers.get "Content-Length" catch err console.log err return new Response "Cannot upload", status: 400 return new Response "OK" verifyFailure = -> return new Response "Invalid signature", status: 403 verifySignatureV1 = (sig, url, request) -> content_length = request.headers.get "Content-Length" if not content_length? return false sign_str = url.pathname[1..] + " " + content_length local_sig = await crypto.HMAC_SHA256 crypto.utf8Bytes(config.xmpp_secret), sign_str local_sig = crypto.hex local_sig return local_sig is sig verifySignatureV2 = (sig, url, request) -> content_length = request.headers.get "Content-Length" content_type = request.headers.get "Content-Type" if not (content_length? and content_type?) return false sign_str = url.pathname[1..] + "\0" + content_length + "\0" + content_type local_sig = await crypto.HMAC_SHA256 crypto.utf8Bytes(config.xmpp_secret), sign_str local_sig = crypto.hex local_sig return local_sig is sig