UNPKG

3.23 kBMarkdownView Raw
1Web server
2----------
3
4 DOWNLOAD = 'get'
5 UPLOAD = 'put'
6 TOKEN = 'token'
7 REV = 'rev'
8 UNTIL = 'until'
9
10 attachments_proxy = ( our_proxy ) ->
11
12 {secret,hash,timeout} = our_proxy
13
14 cors = Cors()
15
16 hash ?= 'sha256'
17 timeout ?= 3600*1000 # one hour
18
19 signature = (method,pathname,rev,limit) ->
20 strictEqual 'string', typeof method, 'method'
21 strictEqual 'string', typeof pathname, 'pathname'
22 strictEqual 'string', typeof rev, 'rev'
23 strictEqual 'string', typeof limit, 'limit'
24 crypto
25 .createHmac hash, secret
26 .update method
27 .update pathname
28 .update rev
29 .update limit
30 .digest 'hex'
31
32 handler = (req,res,next) ->
33
34 next ?= (msg) ->
35 res.writeHead 404
36 res.end msg
37 return
38
39 proxy = ->
40 {method} = req
41 options = our_proxy.target pathname
42 return next() unless options?.url?
43
44 options.url.searchParams.set 'rev', rev
45 options.url = options.url.toString()
46
47 the_proxy = agent Object.assign {
48 method
49 followRedirects: false
50 maxRedirects: 0
51 headers:
52 Connection: 'close'
53 }, options
54 the_proxy.on 'error', (error) ->
55 console.error 'Proxy', method, options.url, error
56 # req.socket.setKeepAlive true
57 res.setHeader 'Connection', 'close'
58 req.on 'end', -> the_proxy.end()
59 res.on 'close', -> the_proxy.abort() # this is the main one
60 req
61 .pipe the_proxy
62 .pipe res
63 return
64
65 {pathname,searchParams} = new URL req.url, our_proxy.url
66
67 token = searchParams.get TOKEN
68 return next 'Invalid token' unless token?
69
70 rev = searchParams.get REV
71 return next 'Invalid rev' unless rev?
72
73 limit = searchParams.get UNTIL
74 return next "Invalid limit #{JSON.stringify limit}" unless limit?.match(/^\d+$/) and parseInt(limit) > Date.now()
75
76 switch req.method
77 when 'OPTIONS'
78 return cors req, res, next
79
80 when 'PUT'
81 if token is signature UPLOAD, pathname, rev, limit
82 return proxy()
83 else
84 return next "Invalid token"
85
86 when 'GET', 'HEAD'
87 if token is signature DOWNLOAD, pathname, rev, limit
88 return proxy()
89 else
90 return next "Invalid token"
91
92 next()
93 return
94
95 uri_maker = (direction) ->
96 (path,rev) ->
97 url = new URL path, our_proxy.url
98 url.searchParams.set REV, rev
99 limit = Date.now() + timeout
100 url.searchParams.set UNTIL, limit
101 url.searchParams.set TOKEN, signature direction, path, rev, limit.toString()
102 url.toString()
103
104 download_uri = uri_maker DOWNLOAD
105 upload_uri = uri_maker UPLOAD
106
107 {handler,download_uri,upload_uri}
108
109 module.exports = attachments_proxy
110 {URL} = require 'url'
111 crypto = require 'crypto'
112 request = require 'request'
113 agent = request.defaults
114 pool: false
115 Cors = require 'cors'
116 {strictEqual} = assert = require 'assert'