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