backend: implement remote url fetching
This commit is contained in:
parent
aad3454f8d
commit
25f04b0c7e
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"comments": "This file contains configuration that will be load into the browser frontend. See src/util.coffee for details.",
|
"comments": "This file contains configuration that will be load into the browser frontend. See src/util.coffee for details.",
|
||||||
"max_upload_size": 10485760,
|
"max_upload_size": 10485760,
|
||||||
"file_lifetime": "7 days"
|
"file_lifetime": "7 days",
|
||||||
|
"remote_fetch_magic": "some_not_common_string"
|
||||||
}
|
}
|
|
@ -2,6 +2,7 @@ import * as util from './util'
|
||||||
import * as crypto from './crypto'
|
import * as crypto from './crypto'
|
||||||
import S3 from './aws/s3'
|
import S3 from './aws/s3'
|
||||||
import config from '../config.json'
|
import config from '../config.json'
|
||||||
|
import configInsec from '../config.insecure.json'
|
||||||
import indexHtml from '../worker/index.html'
|
import indexHtml from '../worker/index.html'
|
||||||
|
|
||||||
FRONTEND_PATHS = [
|
FRONTEND_PATHS = [
|
||||||
|
@ -67,7 +68,13 @@ handlePUT = (req, file) ->
|
||||||
if file.length > util.MAX_FILENAME_LENGTH
|
if file.length > util.MAX_FILENAME_LENGTH
|
||||||
return buildInvalidResponse "File name too long (max #{util.MAX_FILENAME_LENGTH})"
|
return buildInvalidResponse "File name too long (max #{util.MAX_FILENAME_LENGTH})"
|
||||||
|
|
||||||
# Generate a valid ID first
|
if file != configInsec.remote_fetch_magic
|
||||||
|
handleClientUpload req, file
|
||||||
|
else
|
||||||
|
# If the file name is magic, we fetch content from remote
|
||||||
|
handleRemoteFetch req
|
||||||
|
|
||||||
|
generateID = ->
|
||||||
id = null
|
id = null
|
||||||
path = null
|
path = null
|
||||||
loop
|
loop
|
||||||
|
@ -76,6 +83,11 @@ handlePUT = (req, file) ->
|
||||||
files = await s3.listObjects
|
files = await s3.listObjects
|
||||||
prefix: path
|
prefix: path
|
||||||
break if !files.Contents or files.Contents.length == 0
|
break if !files.Contents or files.Contents.length == 0
|
||||||
|
[id, path]
|
||||||
|
|
||||||
|
handleClientUpload = (req, file) ->
|
||||||
|
# Generate a valid ID first
|
||||||
|
[id, path] = await generateID()
|
||||||
|
|
||||||
path = path + "/" + file
|
path = path + "/" + file
|
||||||
len = req.headers.get "content-length"
|
len = req.headers.get "content-length"
|
||||||
|
@ -154,5 +166,69 @@ handleGET = (req, file) ->
|
||||||
status: resp.status
|
status: resp.status
|
||||||
headers: headers
|
headers: headers
|
||||||
|
|
||||||
|
handleRemoteFetch = (req) ->
|
||||||
|
# We support fetching files from a remote URL
|
||||||
|
# given that the length is within a separate constraint
|
||||||
|
# Determine if we are actually getting an URL first
|
||||||
|
if req.headers.get("content-type") != "text/plain"
|
||||||
|
return buildInvalidResponse "Invalid URL"
|
||||||
|
|
||||||
|
if !req.headers.has("content-length") or req.headers.get("content-length") >= 1024
|
||||||
|
return buildInvalidResponse "Invalid URL"
|
||||||
|
|
||||||
|
# Get the URL
|
||||||
|
url = await req.text()
|
||||||
|
|
||||||
|
# Validate URL first
|
||||||
|
try
|
||||||
|
url = new URL url
|
||||||
|
throw "WTF" if url.protocol != "http:" and url.protocol != "https:"
|
||||||
|
catch err
|
||||||
|
return buildInvalidResponse "Invalid URL"
|
||||||
|
|
||||||
|
# Request the remote content
|
||||||
|
remote_res = await fetch url,
|
||||||
|
redirect: "follow"
|
||||||
|
if remote_res.status != 200
|
||||||
|
return buildInvalidResponse "Remote server returned error status"
|
||||||
|
|
||||||
|
# Check the length first
|
||||||
|
# TODO: Maybe we need to limit another length for remote fetch pastes
|
||||||
|
if !remote_res.headers.has("content-length") or remote_res.headers.get("content-length") > util.MAX_UPLOAD_SIZE
|
||||||
|
return buildInvalidResponse "Remote file too large"
|
||||||
|
|
||||||
|
# Try to determine the file name
|
||||||
|
path_splitted = url.pathname.split '/'
|
||||||
|
fileName = path_splitted[path_splitted.length - 1]
|
||||||
|
if remote_res.headers.has "content-disposition"
|
||||||
|
dispos = remote_res.headers.get "content-disposition"
|
||||||
|
for item of dispos.split ';'
|
||||||
|
item = item.trim()
|
||||||
|
if item.startsWith("filename=") or item.startsWith("filename*=")
|
||||||
|
fileName = item.replace "filename=", ""
|
||||||
|
.replace "filename*=", ""
|
||||||
|
.replace "\"", ""
|
||||||
|
break
|
||||||
|
console.log fileName
|
||||||
|
|
||||||
|
if fileName.length > util.MAX_FILENAME_LENGTH
|
||||||
|
return buildInvalidResponse "Remote file name too long"
|
||||||
|
|
||||||
|
# Begin uploading
|
||||||
|
[id, path] = await generateID()
|
||||||
|
path = path + "/" + fileName
|
||||||
|
len = remote_res.headers.get "content-length"
|
||||||
|
|
||||||
|
try
|
||||||
|
await s3.putObject path, remote_res.body,
|
||||||
|
ContentType: remote_res.headers.get "content-type"
|
||||||
|
ContentLength: len
|
||||||
|
catch err
|
||||||
|
console.log err
|
||||||
|
return buildInvalidResponse err
|
||||||
|
|
||||||
|
# Simply return the path in body
|
||||||
|
new Response "/paste/" + id,
|
||||||
|
status: 200
|
||||||
|
|
||||||
export default main
|
export default main
|
Loading…
Reference in New Issue