Skip to content

Commit a100dda

Browse files
committed
📱 Get remoteAddress from Forwarded header
1 parent b9811c9 commit a100dda

5 files changed

Lines changed: 69 additions & 3 deletions

File tree

lib/utils.js

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
'use strict';
22

33
var crypto = require('crypto');
4+
var parseForwarded = require('forwarded-parse');
5+
var ipaddr = require('ipaddr.js');
6+
var _ = require('underscore');
47

58
exports.hookNameMapping = {
69
beforeSave: '__before_save_for_',
@@ -70,9 +73,37 @@ exports.prepareResponseObject = function(res, callback) {
7073
};
7174

7275
var getRemoteAddress = exports.getRemoteAddress = function(req) {
73-
return req.headers['x-real-ip'] || req.headers['x-forwarded-for'] || req.connection.remoteAddress
76+
var forwardedClient = exports.getForwardedClient(req)
77+
78+
if (forwardedClient) {
79+
return forwardedClient.for
80+
} else {
81+
return req.headers['x-real-ip'] || req.headers['x-forwarded-for'] || req.connection.remoteAddress
82+
}
7483
};
7584

7685
exports.endsWith = function(str, suffix) {
7786
return str.indexOf(suffix, str.length - suffix.length) !== -1;
7887
};
88+
89+
exports.getForwardedClient = function getForwardedClient(req) {
90+
if (req.headers['forwarded']) {
91+
try {
92+
const forwards = parseForwarded(req.headers['forwarded']).reverse()
93+
94+
for (var i = 0; i < forwards.length; i++) {
95+
if (!forwards[i].for) {
96+
return
97+
}
98+
99+
var range = ipaddr.parse(forwards[i].for).range()
100+
101+
if (!_.include(['loopback', 'private'], range) || i === forwards.length - 1) {
102+
return _.extend(forwards[i], {range: range})
103+
}
104+
}
105+
} catch (err) {
106+
console.error('LeanEngine: parse Forwarded header failed', req.headers['forwarded'], err.stack)
107+
}
108+
}
109+
}

package-lock.json

Lines changed: 6 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
"connect-timeout": "^1.8.0",
1313
"cookies": "^0.6.2",
1414
"debug": "^2.6.0",
15+
"forwarded-parse": "^2.1.0",
16+
"ipaddr.js": "^1.9.1",
1517
"leancloud-cors-headers": "^0.1.0",
1618
"on-headers": "^1.0.1",
1719
"underscore": "^1.8.3"

test/fixtures/functions.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,10 @@ AV.Cloud.define('testTimeout', function(req, res) {
231231
}, req.params.delay);
232232
});
233233

234+
AV.Cloud.define('remoteAddress', function(request) {
235+
return request.meta.remoteAddress
236+
})
237+
234238
AV.Cloud.onIMMessageReceived(function(request, response) {
235239
response.success('ok');
236240
});

test/function-test.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,31 @@ describe('functions', function() {
452452
});
453453
});
454454

455+
it('remoteAddress', function(done) {
456+
request(app)
457+
.post('/1.1/functions/remoteAddress')
458+
.set('X-AVOSCloud-Application-Id', appId)
459+
.set('X-AVOSCloud-Application-Key', appKey)
460+
.set('Forwarded', 'for=1.2.3.4; proto=https, for=10.0.0.1')
461+
.expect(200, (err, res) => {
462+
res.body.result.should.equal('1.2.3.4')
463+
done(err)
464+
});
465+
})
466+
467+
it('remoteAddress invalid Forwarded header', function(done) {
468+
request(app)
469+
.post('/1.1/functions/remoteAddress')
470+
.set('X-AVOSCloud-Application-Id', appId)
471+
.set('X-AVOSCloud-Application-Key', appKey)
472+
.set('Forwarded', 'for=1.2.3.456; proto=https, for=10.0.0.1')
473+
.set('X-Real-IP', '5.6.7.8')
474+
.expect(200, (err, res) => {
475+
res.body.result.should.equal('5.6.7.8')
476+
done(err)
477+
});
478+
})
479+
455480
it('_metadatas', function(done) {
456481
request(app)
457482
.get('/1/functions/_ops/metadatas')

0 commit comments

Comments
 (0)