forked from gadicc/meteor-headers
-
Notifications
You must be signed in to change notification settings - Fork 0
/
headers-server.js
88 lines (78 loc) · 2.85 KB
/
headers-server.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
var HEADERS_CLEANUP_TIME = 300000; // 5 minutes
/*
* Returns an array describing the suspected IP route the connection has taken.
* This is in order of trust, see the README.md for which value to use
*/
function ipChain(headers, connection) {
var chain = [];
if (headers['x-forwarded-for'])
_.each(headers['x-forwarded-for'].split(','), function(ip) {
chain.push(ip.replace('/\s*/g', ''));
});
if (chain.length == 0 || chain[chain.length-1] != connection.remoteAddress)
chain.push(connection.remoteAddress);
return chain;
}
/*
* The client will request this "script", and send a unique token with it,
* which we later use to re-associate the headers from this request with
* the user's livedata session (since XHR requests only send a subset of
* all the regular headers).
*/
WebApp.connectHandlers.use('/headersHelper.js', function(req, res, next) {
var token = req.query.token;
req.headers['x-ip-chain'] = ipChain(req.headers, req.connection).join(',');
headers.list[token] = req.headers;
res.writeHead(200, { 'Content-type': 'application/javascript' });
res.end("Package.headers.headers.store(" + JSON.stringify(req.headers) + ");", 'utf8');
});
/*
* After user has requested the headers (which were stored in headers.list
* at the same time with the client's token, the below is called, which we
* use to re-associate with the user's livedata session (see above)
*/
Meteor.methods({
'headersToken': function(token) {
if (headers.list[token]) {
this._sessionData.headers = headers.list[token];
delete headers.list[token];
}
}
});
/*
* Cleanup unclaimed headers
*/
Meteor.setInterval(function() {
for (key in headers.list)
if (parseInt(key) < new Date().getTime() - HEADERS_CLEANUP_TIME)
delete(headers.list[key]);
}, HEADERS_CLEANUP_TIME);
/*
* Usage in a Meteor method: headers.get(this, 'host')
*/
headers.get = function(self, key) {
return key ? self._sessionData.headers[key] : self._sessionData.headers;
}
headers.getClientIP = function(self, proxyCount) {
var chain = self._sessionData.headers['x-ip-chain'].split(',');
if (typeof(proxyCount) == 'undefined')
proxyCount = this.proxyCount;
return chain[chain.length - proxyCount - 1];
}
/*
* Get the IP for the livedata connection used by a Method (see README.md)
*/
headers.methodClientIP = function(self, proxyCount) {
// convoluted way to find our session
// TODO, open an issue with Meteor to see if we can get easier access
var token, session;
token = new Date().getTime() + Math.random();
self._sessionData.tmpToken = token;
session = _.find(Meteor.server.sessions, function(session) {
return session.sessionData.tmpToken == token;
});
var chain = ipChain(session.socket.headers, session.socket);
if (typeof(proxyCount) == 'undefined')
proxyCount = this.proxyCount;
return chain[chain.length - proxyCount - 1];
}