xmpp-s3-external/src/index.coffee

96 lines
2.6 KiB
CoffeeScript

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