1 | Web 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.pipe the_proxy
|
57 | the_proxy.pipe res
|
58 | return
|
59 |
|
60 | {pathname,searchParams} = new URL req.url, our_proxy.url
|
61 |
|
62 | token = searchParams.get TOKEN
|
63 | return next 'Invalid token' unless token?
|
64 |
|
65 | rev = searchParams.get REV
|
66 | return next 'Invalid rev' unless rev?
|
67 |
|
68 | limit = searchParams.get UNTIL
|
69 | return next "Invalid limit #{JSON.stringify limit}" unless limit?.match(/^\d+$/) and parseInt(limit) > Date.now()
|
70 |
|
71 | switch req.method
|
72 | when 'OPTIONS'
|
73 | return cors req, res, next
|
74 |
|
75 | when 'PUT'
|
76 | if token is signature UPLOAD, pathname, rev, limit
|
77 | return proxy()
|
78 | else
|
79 | return next "Invalid token"
|
80 |
|
81 | when 'GET', 'HEAD'
|
82 | if token is signature DOWNLOAD, pathname, rev, limit
|
83 | return proxy()
|
84 | else
|
85 | return next "Invalid token"
|
86 |
|
87 | next()
|
88 | return
|
89 |
|
90 | uri_maker = (direction) ->
|
91 | (path,rev) ->
|
92 | url = new URL path, our_proxy.url
|
93 | url.searchParams.set REV, rev
|
94 | limit = Date.now() + timeout
|
95 | url.searchParams.set UNTIL, limit
|
96 | url.searchParams.set TOKEN, signature direction, path, rev, limit.toString()
|
97 | url.toString()
|
98 |
|
99 | download_uri = uri_maker DOWNLOAD
|
100 | upload_uri = uri_maker UPLOAD
|
101 |
|
102 | {handler,download_uri,upload_uri}
|
103 |
|
104 | module.exports = attachments_proxy
|
105 | {URL} = require 'url'
|
106 | crypto = require 'crypto'
|
107 | request = require 'request'
|
108 | agent = request.defaults()
|
109 | Cors = require 'cors'
|
110 | {strictEqual} = assert = require 'assert'
|