106 lines
No EOL
2.8 KiB
CoffeeScript
106 lines
No EOL
2.8 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
|
|
|
|
resp = await s3.getObject url.pathname[1...], {}
|
|
|
|
if not resp.ok
|
|
headers = new Headers resp.headers
|
|
headers.set "Content-Length", 0
|
|
return new Response null,
|
|
status: resp.status
|
|
statusText: resp.statusText
|
|
headers: headers
|
|
else
|
|
return resp
|
|
|
|
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 |