Files
firefox-accounts-mirror/packages/fxa-customs-server/test/remote/too_many_authenticated_checks.js
Vijay Budhram 0e00017b0d fix(cache): Remove memcache service and references to it
feat(sync): Return estimated sync devices in recovery key exist route
2024-04-30 15:08:47 -04:00

231 lines
6.6 KiB
JavaScript

/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
var test = require('tap').test;
var TestServer = require('../test_server');
var Promise = require('bluebird');
var restifyClients = Promise.promisifyAll(require('restify-clients'));
var mcHelper = require('../cache-helper');
var TEST_IP = '192.0.2.1';
var TEST_UID = 'abc123';
var ACTION_ONE = 'action1';
var ACTION_A = 'actionA';
var ACTION_B = 'actionB';
// Override limit values for testing
const config = require('../../lib/config').getProperties();
config.limits.uidRateLimit.maxChecks = 3;
config.limits.uidRateLimit.limitIntervalSeconds = 2;
config.limits.uidRateLimit.banDurationSeconds = 2;
var testServer = new TestServer(config);
var client = restifyClients.createJsonClient({
url: 'http://localhost:' + config.listen.port,
});
Promise.promisifyAll(client, { multiArgs: true });
test('startup', async function (t) {
await testServer.start();
t.type(testServer.server, 'object', 'test server was started');
t.end();
});
test('clear everything', function (t) {
mcHelper.clearEverything(function (err) {
t.notOk(err, 'no errors were returned');
t.end();
});
});
test('/checkAuthenticated requires action', function (t) {
return client
.postAsync('/checkAuthenticated', { ip: TEST_IP, uid: TEST_UID })
.spread(function (req, res, obj) {
t.fail('Success response from request missing param.');
t.end();
})
.catch(function (err) {
t.equal(err.statusCode, 400, 'returns a 400');
t.equal(err.body.code, 'MissingParameters');
t.end();
});
});
test('/checkAuthenticated requires ip', function (t) {
return client
.postAsync('/checkAuthenticated', { action: ACTION_ONE, uid: TEST_UID })
.spread(function (req, res, obj) {
t.fail('Success response from request missing param.');
t.end();
})
.catch(function (err) {
t.equal(err.statusCode, 400, 'returns a 400');
t.equal(err.body.code, 'MissingParameters');
t.end();
});
});
test('/checkAuthenticated requires uid', function (t) {
return client
.postAsync('/checkAuthenticated', { action: ACTION_ONE, ip: TEST_IP })
.spread(function (req, res, obj) {
t.fail('Success response from request missing param.');
t.end();
})
.catch(function (err) {
t.equal(err.statusCode, 400, 'returns a 400');
t.equal(err.body.code, 'MissingParameters');
t.end();
});
});
test('/checkAuthenticated with same action', function (t) {
// Send requests until it blocks
return (
client
.postAsync('/checkAuthenticated', {
action: ACTION_ONE,
ip: TEST_IP,
uid: TEST_UID,
})
.spread(function (req, res, obj) {
t.equal(res.statusCode, 200, 'returns a 200 check1');
t.equal(obj.block, false, 'not rate limited');
return client.postAsync('/checkAuthenticated', {
action: ACTION_ONE,
ip: TEST_IP,
uid: TEST_UID,
});
})
.spread(function (req, res, obj) {
t.equal(res.statusCode, 200, 'returns a 200 check2');
t.equal(obj.block, false, 'not rate limited');
return client.postAsync('/checkAuthenticated', {
action: ACTION_ONE,
ip: TEST_IP,
uid: TEST_UID,
});
})
// uid should be now blocked
.spread(function (req, res, obj) {
t.equal(res.statusCode, 200, 'returns a 200 check3');
t.equal(obj.block, true, 'uid is rate limited');
// Delay ~2s for rate limit to go away
return Promise.delay(2010);
})
// uid should be now unblocked
.then(function () {
return client.postAsync('/checkAuthenticated', {
action: ACTION_ONE,
ip: TEST_IP,
uid: TEST_UID,
});
})
.spread(function (req, res, obj) {
t.equal(res.statusCode, 200, 'returns a 200');
t.equal(
obj.block,
false,
'is not rate limited after UID_RATE_LIMIT_BAN_DURATION_SECONDS'
);
t.end();
})
.catch(function (err) {
t.fail(err);
t.end();
})
);
});
test('/checkAuthenticated with different actions', function (t) {
// Send requests until one gets rate limited
return (
client
.postAsync('/checkAuthenticated', {
action: ACTION_A,
ip: TEST_IP,
uid: TEST_UID,
})
.spread(function (req, res, obj) {
t.equal(res.statusCode, 200, 'returns a 200');
t.equal(obj.block, false, 'not rate limited on check1, actionA');
return client.postAsync('/checkAuthenticated', {
action: ACTION_B,
ip: TEST_IP,
uid: TEST_UID,
});
})
.spread(function (req, res, obj) {
t.equal(res.statusCode, 200, 'returns a 200');
t.equal(obj.block, false, 'not rate limited on check1, actionB');
return client.postAsync('/checkAuthenticated', {
action: ACTION_A,
ip: TEST_IP,
uid: TEST_UID,
});
})
.spread(function (req, res, obj) {
t.equal(res.statusCode, 200, 'returns a 200');
t.equal(obj.block, false, 'not rate limited on check2, actionA');
return client.postAsync('/checkAuthenticated', {
action: ACTION_A,
ip: TEST_IP,
uid: TEST_UID,
});
})
// uid should be now blocked to action1
.spread(function (req, res, obj) {
t.equal(res.statusCode, 200, 'returns a 200');
t.equal(obj.block, true, 'uid is actionA rate limited after check3');
return client.postAsync('/checkAuthenticated', {
action: ACTION_B,
ip: TEST_IP,
uid: TEST_UID,
});
})
.spread(function (req, res, obj) {
t.equal(res.statusCode, 200, 'returns a 200');
t.equal(obj.block, false, 'not rate limited for actionB after check2');
// Delay ~2s for rate limit to go away
return Promise.delay(2010);
})
// uid should be now unblocked
.then(function () {
return client.postAsync('/checkAuthenticated', {
action: ACTION_A,
ip: TEST_IP,
uid: TEST_UID,
});
})
.spread(function (req, res, obj) {
t.equal(res.statusCode, 200, 'returns a 200');
t.equal(
obj.block,
false,
'is not rate limited after UID_RATE_LIMIT_BAN_DURATION_SECONDS'
);
t.end();
})
.catch(function (err) {
t.fail(err);
t.end();
})
);
});
test('teardown', async function (t) {
await testServer.stop();
t.end();
});