-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
119 lines (99 loc) · 2.58 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/**
* Module dependencies
*/
var stack = require('simple-stack-common');
var proxy = require('simple-http-proxy');
var envs = require('envs');
/**
* Create a proxy
*/
exports = module.exports = function(db, opts) {
opts = opts || {};
opts.secret = opts.secret || envs('SHARED_SECRET');
if (!opts.secret) throw new Error('Must specify a secret');
var app = stack(opts);
installRoutes(app, db, opts);
return app;
};
/**
* Expose the express middleware
*/
stack.middleware(exports.middleware = {});
/**
* Install the route handlers
*/
function installRoutes(app, db, opts) {
app.get('/', function(req, res) {
res.json({
href: req.base,
update: {
action: req.base,
method: 'POST',
input: {
app: {
type: 'text',
required: true
},
manifest: {
type: 'application/x-simple-manifest',
required: true
}
}
}
});
});
var auth = opts.authenticate || authenticate;
app.post('/', auth(opts), function(req, res, next) {
var id = req.body.app;
var manifest = req.body.manifest;
if (typeof manifest === 'string') try {
manifest = JSON.parse(manifest);
} catch (err) {
return next(new Error('Could not read manifest'));
};
if (!manifest || !id) return next(new Error('missing required parameters'));
db.replace(id, manifest, function(err) {
if (err) return next(err);
res.send(204);
});
});
app.useBefore('router', '/assets', function lookup(req, res, next) {
var url = req.url.split('?')[0];
db.lookup(url.substr(1), function(err, endpoints) {
if (err) return next(err);
if (!endpoints || !endpoints.length) return res.send(404);
req.url = url;
pipe(endpoints, req, res, next);
});
});
app.use(function errorHandler(err, req, res, next) {
res.json({
href: req.base + req.url,
error: {
message: err.message,
stack: err.stack
}
});
});
}
/**
* Make the upstream requests
*
* TODO should we make a bunch of requests in parallel and
* return the first one?
*/
function pipe(endpoints, req, res, next) {
var endpoint = endpoints.shift();
proxy(endpoint)(req, res, function(err) {
if (err) pipe(endpoints, req, res, next);
res.send(404);
});
}
function authenticate(opts) {
return function (req, res, next) {
var auth = (req.get('authorization') || '').replace(/^bearer /i, '');
// TODO do a secure comparison
if (!auth || opts.secret !== auth) return res.send(401);
next();
};
}