Skip to content

Commit 72cd8e0

Browse files
authored
Inclusively cover account level probationary status using limiter values (#2076)
* Should provide additional protection from IP surfing. * Move limiter settings to settings JSON for ease of multiple import. * Use the earliest possible detected `now`. * Some console logging. Post #1893 and Applies to #2074 and Closes #2075 Auto-merge
1 parent 95cb616 commit 72cd8e0

3 files changed

Lines changed: 114 additions & 13 deletions

File tree

controllers/auth.js

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,17 @@ var isDbg = require('../libs/debug').isDbg;
88
//
99

1010
//--- Dependency inclusions
11+
var moment = require('moment');
1112
var passport = require('passport');
1213
var colors = require('ansi-colors');
1314

1415
//--- Model inclusions
1516
var Strategy = require('../models/strategy.js').Strategy;
1617
var User = require('../models/user').User;
1718

19+
//--- Configuration inclusions
20+
var settings = require('../models/settings.json');
21+
1822
//--- Controller inclusions
1923

2024
//--- Library inclusions
@@ -423,6 +427,12 @@ exports.callback = function (aReq, aRes, aNext) {
423427

424428
aReq.logIn(aUser, function (aErr) {
425429
var now = null;
430+
var lastAuthed = null;
431+
432+
var fudgeMin = settings.fudgeMin;
433+
var fudgeSec = settings.fudgeSec;
434+
435+
var waitAuthCapMin = isDev ? settings.waitAuthCapMin.dev: settings.waitAuthCapMin.pro;
426436

427437
if (aErr) {
428438
console.error('Not logged in');
@@ -447,6 +457,52 @@ exports.callback = function (aReq, aRes, aNext) {
447457
now.toISOString()
448458
);
449459

460+
lastAuthed = aUser.authed;
461+
462+
// Save the last date a user sucessfully logged in
463+
aUser.authed = now;
464+
465+
// Check probationary status vs lastAuthed for alt IP circumvention prevention
466+
if (aUser._probationary && lastAuthed) {
467+
if (!moment().isAfter(moment(lastAuthed).add(waitAuthCapMin, 'minutes'))) {
468+
aUser.save(function (aErr, aUser) {
469+
if (aErr) {
470+
// NOTE: A user could get back in quicker but still delayed from `authed`
471+
console.error(
472+
colors.red(
473+
'Probationary logged out failed to write current authentication date to aUser'),
474+
aUser.name,
475+
colors.red('at'),
476+
aReq.connection.remoteAddress,
477+
colors.red('on'),
478+
now.toISOString()
479+
);
480+
}
481+
});
482+
483+
console.log(
484+
colors.red('Logged out probationary User'),
485+
aUser.name,
486+
colors.red('at'),
487+
aReq.connection.remoteAddress,
488+
colors.red('on'),
489+
now.toISOString()
490+
);
491+
492+
statusCodePage(aReq, aRes, aNext, {
493+
statusCode: 429,
494+
statusMessage: 'Too many requests.',
495+
suppressNavigation: true,
496+
isCustomView: true,
497+
statusData: {
498+
isListView: true,
499+
retryAfter: waitAuthCapMin * 60 + (isDev ? fudgeSec : fudgeMin)
500+
}
501+
});
502+
return;
503+
}
504+
}
505+
450506
// Store the user info in the session
451507
aReq.session.user = aUser;
452508

@@ -463,8 +519,6 @@ exports.callback = function (aReq, aRes, aNext) {
463519
aReq.session.passport.oujsOptions.strategy = strategy;
464520
}
465521

466-
// Save the last date a user sucessfully logged in
467-
aUser.authed = new Date();
468522

469523
// Save consent
470524
aUser.consented = true;

models/settings.json

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,52 @@
2828
"charPreset": null
2929
},
3030

31-
"NOTE": "Requires DB migration for changing below settings",
31+
"NOTE1": "WATCHPOINT: ~60 second poll time in MongoDB",
32+
33+
"fudgeMin": 60,
34+
"fudgeSec": 5,
35+
"waitInstallCapMin": {
36+
"dev": 1,
37+
"pro": 60
38+
},
39+
"waitRateInstallSec": {
40+
"dev": 30,
41+
"pro": 60
42+
},
43+
"waitRateMetaSec": {
44+
"dev": 30,
45+
"pro": 60
46+
},
47+
"waitApiCapMin": {
48+
"dev": 1,
49+
"pro": 15
50+
},
51+
"waitAuthCapMin": {
52+
"dev": 1,
53+
"pro": 1440
54+
},
55+
"waitCaptchaCapMin": {
56+
"dev": 1,
57+
"pro": 1440
58+
},
59+
"waitListCapMin": {
60+
"dev": 1,
61+
"pro": 60
62+
},
63+
"waitListRateSec": {
64+
"dev": 2,
65+
"pro": 4
66+
},
67+
"waitListAnyQRateSec": {
68+
"dev": 20,
69+
"pro": 40
70+
},
71+
"waitListSameQCapMin": {
72+
"dev": 5,
73+
"pro": 15
74+
},
75+
76+
"NOTE2": "Requires DB migration for changing below settings",
3277

3378
"scriptSearchQueryStoreMaxDescription": 512,
3479
"scriptSearchQueryStoreMaxAbout": 256

routes.js

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ var statusTMR = function (aReq, aRes, aNext) {
5353
var fudgeMin = 60;
5454
var fudgeSec = 6;
5555

56-
var waitInstallCapMin = isDev ? 1 : 60;
56+
var waitInstallCapMin = isDev ? settings.waitInstallCapMin.dev : settings.waitInstallCapMin.pro;
5757
var installCapLimiter = rateLimit({
5858
store: (isDev ? undefined : new MongoStore({
5959
uri: appendUrlLeaf(limiter, '/installCapLimiter'),
@@ -119,7 +119,7 @@ var installCapLimiter = rateLimit({
119119
}
120120
});
121121

122-
var waitRateInstallSec = isDev ? 30 : 60;
122+
var waitRateInstallSec = isDev ? settings.waitRateInstallSec.dev : settings.waitRateInstallSec.pro;
123123
var installRateLimiter = rateLimit({
124124
store: (isDev ? undefined : new MongoStore({
125125
uri: appendUrlLeaf(limiter, '/installRateLimiter'),
@@ -167,7 +167,7 @@ var installRateLimiter = rateLimit({
167167
var install1Limiter = lockdown ? installCapLimiter : installRateLimiter;
168168
var install2Limiter = lockdown ? installRateLimiter : installCapLimiter;
169169

170-
var waitRateMetaSec = isDev ? 30 : 60;
170+
var waitRateMetaSec = isDev ? settings.waitRateMetaSec.dev : settings.waitRateMetaSec.pro;
171171
var metaRateLimiter = rateLimit({
172172
store: (isDev ? undefined : new MongoStore({
173173
uri: appendUrlLeaf(limiter, '/metaRateLimiter'),
@@ -212,7 +212,7 @@ var metaRateLimiter = rateLimit({
212212
}
213213
});
214214

215-
var waitApiCapMin = isDev ? 1: 15;
215+
var waitApiCapMin = isDev ? settings.waitApiCapMin.dev: settings.waitApiCapMin.pro;
216216
var apiCapLimiter = rateLimit({
217217
store: (isDev ? undefined : new MongoStore({
218218
uri: appendUrlLeaf(limiter, '/apiCapLimiter'),
@@ -235,7 +235,7 @@ var apiCapLimiter = rateLimit({
235235
}
236236
});
237237

238-
var waitAuthCapMin = isDev ? 1: 1440;
238+
var waitAuthCapMin = isDev ? settings.waitAuthCapMin.dev: settings.waitAuthCapMin.pro;
239239
var authCapLimiter = rateLimit({
240240
store: (isDev ? undefined : new MongoStore({
241241
uri: appendUrlLeaf(limiter, '/authCapLimiter'),
@@ -259,7 +259,7 @@ var authCapLimiter = rateLimit({
259259
}
260260
});
261261

262-
var waitCaptchaCapMin = isDev ? 1: 1440;
262+
var waitCaptchaCapMin = isDev ? settings.waitCaptchaCapMin.dev: settings.waitCaptchaCapMin.pro;
263263
var captchaCapLimiter = rateLimit({
264264
store: (isDev ? undefined : new MongoStore({
265265
uri: appendUrlLeaf(limiter, '/captchaCapLimiter'),
@@ -293,7 +293,7 @@ var captchaCapLimiter = rateLimit({
293293
}
294294
});
295295

296-
var waitListCapMin = isDev ? 1: 60;
296+
var waitListCapMin = isDev ? settings.waitListCapMin.dev: settings.waitListCapMin.pro;
297297
var listCapLimiter = rateLimit({
298298
store: (isDev ? undefined : new MongoStore({
299299
uri: appendUrlLeaf(limiter, '/listCapLimiter'),
@@ -359,7 +359,7 @@ var listCapLimiter = rateLimit({
359359
}
360360
});
361361

362-
var waitListRateSec = isDev ? parseInt(4 / 2) : 4;
362+
var waitListRateSec = isDev ? settings.waitListRateSec.dev : settings.waitListRateSec.pro;
363363
var listRateLimiter = rateLimit({
364364
store: (isDev ? undefined : undefined),
365365
windowMs: waitListRateSec * 1000, // n seconds for all stores
@@ -403,7 +403,8 @@ var list1Limiter = lockdown ? listCapLimiter : listRateLimiter;
403403
var list2Limiter = lockdown ? listRateLimiter : listCapLimiter;
404404

405405

406-
var waitListAnyQRateSec = isDev ? parseInt(40 / 2) : 40;
406+
var waitListAnyQRateSec = isDev
407+
? settings.waitListAnyQRateSec.dev : settings.waitListAnyQRateSec.pro;
407408
var listAnyQRateLimiter = rateLimit({
408409
store: (isDev ? undefined : undefined),
409410
windowMs: waitListAnyQRateSec * 1000, // n seconds for all stores
@@ -439,7 +440,8 @@ var listAnyQRateLimiter = rateLimit({
439440
}
440441
});
441442

442-
var waitListSameQCapMin = isDev ? 5 : 15;
443+
var waitListSameQCapMin = isDev
444+
? settings.waitListSameQCapMin.dev : settings.waitListSameQCapMin.pro;
443445
var listSameQRateLimiter = rateLimit({
444446
store: (isDev ? undefined : new MongoStore({
445447
uri: appendUrlLeaf(limiter, '/listSameQCapLimiter'),

0 commit comments

Comments
 (0)