232 lines
9.2 KiB
JavaScript
232 lines
9.2 KiB
JavaScript
/* eslint-env mocha */
|
|
|
|
var createRateLimitChecker = require('../lib/rate-limit');
|
|
|
|
var lolex = require('lolex');
|
|
var assert = require('assert');
|
|
|
|
function assertNotLimited(rateLimitReturnValue) {
|
|
if (rateLimitReturnValue) {
|
|
assert.fail('Expected no limit, but got ' + rateLimitReturnValue);
|
|
}
|
|
}
|
|
|
|
function assertLimited(rateLimitReturnValue, limit, period) {
|
|
var msg;
|
|
if (period === 1) {
|
|
msg = 'The number of requests is limited to ' + limit + ' per minute. ';
|
|
} else {
|
|
msg = 'The number of requests is limited to ' + limit + ' per ' + period + ' minutes. ';
|
|
}
|
|
msg += 'Please self-host CORS Anywhere if you need more quota. ' +
|
|
'See https://github.com/Rob--W/cors-anywhere#demo-server';
|
|
assert.equal(rateLimitReturnValue, msg);
|
|
}
|
|
|
|
describe('Rate limit', function() {
|
|
var clock;
|
|
beforeEach(function() {
|
|
clock = lolex.install();
|
|
});
|
|
afterEach(function() {
|
|
clock.uninstall();
|
|
});
|
|
it('is unlimited by default', function() {
|
|
var checkRateLimit = createRateLimitChecker();
|
|
assertNotLimited(checkRateLimit('http://example.com'));
|
|
assertNotLimited(checkRateLimit('https://example.com'));
|
|
assertNotLimited(checkRateLimit('https://example.com:1234'));
|
|
|
|
checkRateLimit = createRateLimitChecker('');
|
|
assertNotLimited(checkRateLimit('http://example.com'));
|
|
|
|
checkRateLimit = createRateLimitChecker(' ');
|
|
assertNotLimited(checkRateLimit('http://example.com'));
|
|
});
|
|
|
|
it('zero per minute / 5 minutes', function() {
|
|
var checkRateLimit = createRateLimitChecker('0 1');
|
|
assertLimited(checkRateLimit('http://example.com'), 0, 1);
|
|
assertLimited(checkRateLimit('https://example.com'), 0, 1);
|
|
|
|
checkRateLimit = createRateLimitChecker('0 5');
|
|
assertLimited(checkRateLimit('http://example.com'), 0, 5);
|
|
assertLimited(checkRateLimit('https://example.com'), 0, 5);
|
|
});
|
|
|
|
it('one per minute', function() {
|
|
var checkRateLimit = createRateLimitChecker('1 1');
|
|
assertNotLimited(checkRateLimit('http://example.com'));
|
|
assertLimited(checkRateLimit('http://example.com'), 1, 1);
|
|
assertNotLimited(checkRateLimit('http://example.com:1234'));
|
|
assertLimited(checkRateLimit('http://example.com:1234'), 1, 1);
|
|
|
|
clock.tick(59000);
|
|
assertLimited(checkRateLimit('http://example.com'), 1, 1);
|
|
|
|
clock.tick(1000);
|
|
assertNotLimited(checkRateLimit('http://example.com'));
|
|
assertLimited(checkRateLimit('http://example.com'), 1, 1);
|
|
assertNotLimited(checkRateLimit('http://example.com:1234'));
|
|
assertLimited(checkRateLimit('http://example.com:1234'), 1, 1);
|
|
});
|
|
|
|
it('different domains, one per minute', function() {
|
|
var checkRateLimit = createRateLimitChecker('1 1');
|
|
assertNotLimited(checkRateLimit('http://example.com'));
|
|
assertNotLimited(checkRateLimit('http://example.net'));
|
|
assertNotLimited(checkRateLimit('http://wexample.net'));
|
|
assertNotLimited(checkRateLimit('http://xample.net'));
|
|
assertNotLimited(checkRateLimit('http://www.example.net'));
|
|
assertLimited(checkRateLimit('http://example.com'), 1, 1);
|
|
assertLimited(checkRateLimit('http://example.net'), 1, 1);
|
|
assertLimited(checkRateLimit('http://wexample.net'), 1, 1);
|
|
assertLimited(checkRateLimit('http://xample.net'), 1, 1);
|
|
assertLimited(checkRateLimit('http://www.example.net'), 1, 1);
|
|
|
|
clock.tick(60000); // 1 minute
|
|
assertNotLimited(checkRateLimit('http://example.com'));
|
|
assertNotLimited(checkRateLimit('http://example.net'));
|
|
assertNotLimited(checkRateLimit('http://wexample.net'));
|
|
assertNotLimited(checkRateLimit('http://xample.net'));
|
|
assertNotLimited(checkRateLimit('http://www.example.net'));
|
|
});
|
|
|
|
it('unlimited domains, string', function() {
|
|
var checkRateLimit = createRateLimitChecker('1 2 example.com');
|
|
assertNotLimited(checkRateLimit('http://example.com'));
|
|
assertNotLimited(checkRateLimit('http://example.com'));
|
|
|
|
assertNotLimited(checkRateLimit('http://wexample.com'));
|
|
assertNotLimited(checkRateLimit('http://xample.com'));
|
|
assertNotLimited(checkRateLimit('http://www.example.com'));
|
|
assertLimited(checkRateLimit('http://wexample.com'), 1, 2);
|
|
assertLimited(checkRateLimit('http://xample.com'), 1, 2);
|
|
assertLimited(checkRateLimit('http://www.example.com'), 1, 2);
|
|
});
|
|
|
|
it('unlimited domains, RegExp', function() {
|
|
var checkRateLimit = createRateLimitChecker('1 2 /example\\.com/');
|
|
assertNotLimited(checkRateLimit('http://example.com'));
|
|
assertNotLimited(checkRateLimit('http://example.com'));
|
|
|
|
assertNotLimited(checkRateLimit('http://wexample.com'));
|
|
assertNotLimited(checkRateLimit('http://xample.com'));
|
|
assertNotLimited(checkRateLimit('http://www.example.com'));
|
|
assertLimited(checkRateLimit('http://wexample.com'), 1, 2);
|
|
assertLimited(checkRateLimit('http://xample.com'), 1, 2);
|
|
assertLimited(checkRateLimit('http://www.example.com'), 1, 2);
|
|
});
|
|
|
|
it('multiple domains, string', function() {
|
|
var checkRateLimit = createRateLimitChecker('1 2 a b cc ');
|
|
assertNotLimited(checkRateLimit('http://a'));
|
|
assertNotLimited(checkRateLimit('http://a'));
|
|
assertNotLimited(checkRateLimit('http://b'));
|
|
assertNotLimited(checkRateLimit('http://b'));
|
|
assertNotLimited(checkRateLimit('http://cc'));
|
|
assertNotLimited(checkRateLimit('http://cc'));
|
|
assertNotLimited(checkRateLimit('http://c'));
|
|
assertLimited(checkRateLimit('http://c'), 1, 2);
|
|
});
|
|
|
|
it('multiple domains, RegExp', function() {
|
|
var checkRateLimit = createRateLimitChecker('1 2 /a/ /b/ /cc/ ');
|
|
assertNotLimited(checkRateLimit('http://a'));
|
|
assertNotLimited(checkRateLimit('http://a'));
|
|
assertNotLimited(checkRateLimit('http://b'));
|
|
assertNotLimited(checkRateLimit('http://b'));
|
|
assertNotLimited(checkRateLimit('http://cc'));
|
|
assertNotLimited(checkRateLimit('http://cc'));
|
|
assertNotLimited(checkRateLimit('http://ccc'));
|
|
assertLimited(checkRateLimit('http://ccc'), 1, 2);
|
|
});
|
|
|
|
it('multiple domains, string and RegExp', function() {
|
|
var checkRateLimit = createRateLimitChecker('1 2 a /b/');
|
|
assertNotLimited(checkRateLimit('http://a'));
|
|
assertNotLimited(checkRateLimit('http://a'));
|
|
assertNotLimited(checkRateLimit('http://b'));
|
|
assertNotLimited(checkRateLimit('http://b'));
|
|
assertNotLimited(checkRateLimit('http://ab'));
|
|
assertLimited(checkRateLimit('http://ab'), 1, 2);
|
|
});
|
|
|
|
it('multiple domains, RegExp and string', function() {
|
|
var checkRateLimit = createRateLimitChecker('1 2 /a/ b');
|
|
assertNotLimited(checkRateLimit('http://a'));
|
|
assertNotLimited(checkRateLimit('http://a'));
|
|
assertNotLimited(checkRateLimit('http://b'));
|
|
assertNotLimited(checkRateLimit('http://b'));
|
|
assertNotLimited(checkRateLimit('http://ab'));
|
|
assertLimited(checkRateLimit('http://ab'), 1, 2);
|
|
});
|
|
|
|
it('wildcard subdomains', function() {
|
|
var checkRateLimit = createRateLimitChecker('0 1 /(.*\\.)?example\\.com/');
|
|
assertNotLimited(checkRateLimit('http://example.com'));
|
|
assertNotLimited(checkRateLimit('http://www.example.com'));
|
|
assertLimited(checkRateLimit('http://xexample.com'), 0, 1);
|
|
assertLimited(checkRateLimit('http://example.com.br'), 0, 1);
|
|
});
|
|
|
|
it('wildcard ports', function() {
|
|
var checkRateLimit = createRateLimitChecker('0 1 /example\\.com(:\\d{1,5})?/');
|
|
assertNotLimited(checkRateLimit('http://example.com'));
|
|
assertNotLimited(checkRateLimit('http://example.com:1234'));
|
|
});
|
|
|
|
it('empty host', function() {
|
|
var checkRateLimit = createRateLimitChecker('0 1');
|
|
assertLimited(checkRateLimit(''), 0, 1);
|
|
// Empty host actually means empty origin. But let's also test for 'http://'.
|
|
assertLimited(checkRateLimit('http://'), 0, 1);
|
|
|
|
checkRateLimit = createRateLimitChecker('0 1 ');
|
|
assertLimited(checkRateLimit(''), 0, 1);
|
|
assertLimited(checkRateLimit('http://'), 0, 1);
|
|
|
|
checkRateLimit = createRateLimitChecker('0 1 //');
|
|
assertNotLimited(checkRateLimit(''));
|
|
assertNotLimited(checkRateLimit('http://'));
|
|
});
|
|
|
|
it('null origin', function() {
|
|
var checkRateLimit = createRateLimitChecker('0 1');
|
|
assertLimited(checkRateLimit('null'), 0, 1);
|
|
assertLimited(checkRateLimit('http://null'), 0, 1);
|
|
|
|
checkRateLimit = createRateLimitChecker('0 1 null');
|
|
assertNotLimited(checkRateLimit('null'));
|
|
assertNotLimited(checkRateLimit('http://null'));
|
|
|
|
checkRateLimit = createRateLimitChecker('0 1 /null/');
|
|
assertNotLimited(checkRateLimit('null'));
|
|
assertNotLimited(checkRateLimit('http://null'));
|
|
});
|
|
|
|
it('case-insensitive', function() {
|
|
var checkRateLimit = createRateLimitChecker('0 1 NULL');
|
|
assertNotLimited(checkRateLimit('null'));
|
|
assertNotLimited(checkRateLimit('http://null'));
|
|
|
|
checkRateLimit = createRateLimitChecker('0 1 /NULL/');
|
|
assertNotLimited(checkRateLimit('null'));
|
|
assertNotLimited(checkRateLimit('http://null'));
|
|
});
|
|
|
|
it('bad input', function() {
|
|
assert.throws(function() {
|
|
createRateLimitChecker('0 1 /');
|
|
}, /Invalid CORSANYWHERE_RATELIMIT\. Regex at index 0 must start and end with a slash \("\/"\)\./);
|
|
|
|
assert.throws(function() {
|
|
createRateLimitChecker('0 1 a /');
|
|
}, /Invalid CORSANYWHERE_RATELIMIT\. Regex at index 1 must start and end with a slash \("\/"\)\./);
|
|
|
|
assert.throws(function() {
|
|
createRateLimitChecker('0 1 /(/');
|
|
}, /Invalid regular expression/);
|
|
});
|
|
});
|