Integrate socket.io ban check with GlobalBanDB
This commit is contained in:
parent
ed811db6ec
commit
b23a858a8c
36
src/io/globalban.js
Normal file
36
src/io/globalban.js
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import { LoggerFactory } from '@calzoneman/jsli';
|
||||||
|
import { getIPRange, getWideIPRange } from '../utilities';
|
||||||
|
|
||||||
|
const LOGGER = LoggerFactory.getLogger('CachingGlobalBanlist');
|
||||||
|
|
||||||
|
class CachingGlobalBanlist {
|
||||||
|
constructor(globalBanDB) {
|
||||||
|
this.globalBanDB = globalBanDB;
|
||||||
|
this.cache = new Set();
|
||||||
|
this.cacheTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshCache() {
|
||||||
|
return this.globalBanDB.listGlobalBans().then(bans => {
|
||||||
|
this.cache.clear();
|
||||||
|
bans.forEach(ban => {
|
||||||
|
this.cache.add(ban.ip);
|
||||||
|
});
|
||||||
|
}).catch(error => {
|
||||||
|
LOGGER.error('Unable to refresh global banlist cache: %s', error.stack);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
startCacheTimer(interval) {
|
||||||
|
clearInterval(this.cacheTimer);
|
||||||
|
this.cacheTimer = setInterval(this.refreshCache.bind(this), interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
isIPGlobalBanned(ip) {
|
||||||
|
return this.cache.has(ip)
|
||||||
|
|| this.cache.has(getIPRange(ip))
|
||||||
|
|| this.cache.has(getWideIPRange(ip));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { CachingGlobalBanlist };
|
|
@ -18,6 +18,7 @@ import Promise from 'bluebird';
|
||||||
import { LoggerFactory } from '@calzoneman/jsli';
|
import { LoggerFactory } from '@calzoneman/jsli';
|
||||||
const verifySession = Promise.promisify(session.verifySession);
|
const verifySession = Promise.promisify(session.verifySession);
|
||||||
const getAliases = Promise.promisify(db.getAliases);
|
const getAliases = Promise.promisify(db.getAliases);
|
||||||
|
import { CachingGlobalBanlist } from './globalban';
|
||||||
|
|
||||||
const LOGGER = LoggerFactory.getLogger('ioserver');
|
const LOGGER = LoggerFactory.getLogger('ioserver');
|
||||||
|
|
||||||
|
@ -197,6 +198,17 @@ function ipForwardingMiddleware(webConfig) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let globalIPBanlist = null;
|
||||||
|
function isIPGlobalBanned(ip) {
|
||||||
|
if (globalIPBanlist === null) {
|
||||||
|
globalIPBanlist = new CachingGlobalBanlist(db.getGlobalBanDB());
|
||||||
|
globalIPBanlist.refreshCache();
|
||||||
|
globalIPBanlist.startCacheTimer(60 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
return globalIPBanlist.isIPGlobalBanned(ip);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called after a connection is accepted
|
* Called after a connection is accepted
|
||||||
*/
|
*/
|
||||||
|
@ -226,7 +238,7 @@ function handleConnection(sock) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for global ban on the IP
|
// Check for global ban on the IP
|
||||||
if (db.isGlobalIPBanned(ip)) {
|
if (isIPGlobalBanned(ip)) {
|
||||||
LOGGER.info("Rejecting " + ip + " - global banned");
|
LOGGER.info("Rejecting " + ip + " - global banned");
|
||||||
sock.emit("kick", { reason: "Your IP is globally banned." });
|
sock.emit("kick", { reason: "Your IP is globally banned." });
|
||||||
sock.disconnect();
|
sock.disconnect();
|
||||||
|
|
53
test/io/globalban.js
Normal file
53
test/io/globalban.js
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
const assert = require('assert');
|
||||||
|
const sinon = require('sinon');
|
||||||
|
const GlobalBanDB = require('../../lib/db/globalban').GlobalBanDB;
|
||||||
|
const CachingGlobalBanlist = require('../../lib/io/globalban').CachingGlobalBanlist;
|
||||||
|
|
||||||
|
describe('CachingGlobalBanlist', () => {
|
||||||
|
let banlist = null;
|
||||||
|
let banDB = null;
|
||||||
|
beforeEach(() => {
|
||||||
|
banDB = new GlobalBanDB();
|
||||||
|
banlist = new CachingGlobalBanlist(banDB);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('refreshCache', () => {
|
||||||
|
it('caches bans', () => {
|
||||||
|
const bans = [{ ip: '1.1.1.1', reason: 'test' }];
|
||||||
|
sinon.stub(banDB, 'listGlobalBans').resolves(bans);
|
||||||
|
return banlist.refreshCache().then(() => {
|
||||||
|
assert(banlist.cache.has(bans[0].ip), 'Cache was not populated');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('clears removed bans', () => {
|
||||||
|
banlist.cache.add('1.1.1.1');
|
||||||
|
sinon.stub(banDB, 'listGlobalBans').resolves([]);
|
||||||
|
return banlist.refreshCache().then(() => {
|
||||||
|
assert(!banlist.cache.has('1.1.1.1'), 'Cache was not updated');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fails open', () => {
|
||||||
|
sinon.stub(banDB, 'listGlobalBans').rejects(new Error('Broken'));
|
||||||
|
return banlist.refreshCache();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isIPGlobalBanned', () => {
|
||||||
|
it('checks the full IP', () => {
|
||||||
|
banlist.cache.add('1.2.3.4');
|
||||||
|
assert(banlist.isIPGlobalBanned('1.2.3.4'), 'Expected IP to be banned');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('checks the range IP', () => {
|
||||||
|
banlist.cache.add('1.2.3');
|
||||||
|
assert(banlist.isIPGlobalBanned('1.2.3.4'), 'Expected IP to be banned');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('checks the wrange IP', () => {
|
||||||
|
banlist.cache.add('1.2');
|
||||||
|
assert(banlist.isIPGlobalBanned('1.2.3.4'), 'Expected IP to be banned');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in a new issue