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 |
|
63 | res.setHeader('Connection', 'close');
|
64 | req.on('end', function() {
|
65 | return the_proxy.end();
|
66 | });
|
67 | res.on('close', function() {
|
68 | return the_proxy.abort();
|
69 | });
|
70 | req.pipe(the_proxy).pipe(res);
|
71 | };
|
72 | ({pathname, searchParams} = new URL(req.url, our_proxy.url));
|
73 | token = searchParams.get(TOKEN);
|
74 | if (token == null) {
|
75 | return next('Invalid token');
|
76 | }
|
77 | rev = searchParams.get(REV);
|
78 | if (rev == null) {
|
79 | return next('Invalid rev');
|
80 | }
|
81 | limit = searchParams.get(UNTIL);
|
82 | if (!((limit != null ? limit.match(/^\d+$/) : void 0) && parseInt(limit) > Date.now())) {
|
83 | return next(`Invalid limit ${JSON.stringify(limit)}`);
|
84 | }
|
85 | switch (req.method) {
|
86 | case 'OPTIONS':
|
87 | return cors(req, res, next);
|
88 | case 'PUT':
|
89 | if (token === signature(UPLOAD, pathname, rev, limit)) {
|
90 | return proxy();
|
91 | } else {
|
92 | return next("Invalid token");
|
93 | }
|
94 | break;
|
95 | case 'GET':
|
96 | case 'HEAD':
|
97 | if (token === signature(DOWNLOAD, pathname, rev, limit)) {
|
98 | return proxy();
|
99 | } else {
|
100 | return next("Invalid token");
|
101 | }
|
102 | }
|
103 | next();
|
104 | };
|
105 | uri_maker = function(direction) {
|
106 | return function(path, rev) {
|
107 | var limit, url;
|
108 | url = new URL(path, our_proxy.url);
|
109 | url.searchParams.set(REV, rev);
|
110 | limit = Date.now() + timeout;
|
111 | url.searchParams.set(UNTIL, limit);
|
112 | url.searchParams.set(TOKEN, signature(direction, path, rev, limit.toString()));
|
113 | return url.toString();
|
114 | };
|
115 | };
|
116 | download_uri = uri_maker(DOWNLOAD);
|
117 | upload_uri = uri_maker(UPLOAD);
|
118 | return {handler, download_uri, upload_uri};
|
119 | };
|
120 |
|
121 | module.exports = attachments_proxy;
|
122 |
|
123 | ({URL} = require('url'));
|
124 |
|
125 | crypto = require('crypto');
|
126 |
|
127 | request = require('request');
|
128 |
|
129 | agent = request.defaults({
|
130 | pool: false
|
131 | });
|
132 |
|
133 | Cors = require('cors');
|
134 |
|
135 | ({strictEqual} = assert = require('assert'));
|
136 |
|
137 | }).call(this);
|