2018-02-25 03:47:50 +00:00
|
|
|
const assert = require('assert');
|
|
|
|
const KickbanModule = require('../../lib/channel/kickban');
|
|
|
|
const database = require('../../lib/database');
|
|
|
|
const Promise = require('bluebird');
|
|
|
|
const testDB = require('../testutil/db').testDB;
|
|
|
|
|
|
|
|
database.init(testDB);
|
|
|
|
|
|
|
|
describe('KickbanModule', () => {
|
|
|
|
const channelName = `test_${Math.random().toString(31).substring(2)}`;
|
|
|
|
|
|
|
|
let mockChannel;
|
|
|
|
let mockUser;
|
|
|
|
let kickban;
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
mockChannel = {
|
|
|
|
name: channelName,
|
2021-01-09 21:03:38 +00:00
|
|
|
refCounter: {
|
|
|
|
ref() { },
|
|
|
|
unref() { }
|
|
|
|
},
|
2018-02-25 03:47:50 +00:00
|
|
|
logger: {
|
|
|
|
log() { }
|
|
|
|
},
|
|
|
|
modules: {
|
|
|
|
permissions: {
|
|
|
|
canBan() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
users: []
|
|
|
|
};
|
|
|
|
|
|
|
|
mockUser = {
|
|
|
|
getName() {
|
|
|
|
return 'The_Admin';
|
|
|
|
},
|
|
|
|
|
|
|
|
getLowerName() {
|
|
|
|
return 'the_admin';
|
|
|
|
},
|
|
|
|
|
|
|
|
socket: {
|
|
|
|
emit(frame) {
|
|
|
|
if (frame === 'errorMsg') {
|
|
|
|
throw new Error(arguments[1].msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
account: {
|
|
|
|
effectiveRank: 3
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
kickban = new KickbanModule(mockChannel);
|
|
|
|
});
|
|
|
|
|
|
|
|
afterEach(async () => {
|
|
|
|
await database.getDB().runTransaction(async tx => {
|
|
|
|
await tx.table('channel_bans')
|
|
|
|
.where({ channel: channelName })
|
|
|
|
.del();
|
|
|
|
await tx.table('channel_ranks')
|
|
|
|
.where({ channel: channelName })
|
|
|
|
.del();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('#handleCmdBan', () => {
|
|
|
|
it('inserts a valid ban', done => {
|
|
|
|
let kicked = false;
|
|
|
|
|
2021-01-09 21:03:38 +00:00
|
|
|
mockChannel.refCounter.unref = () => {
|
2018-02-25 03:47:50 +00:00
|
|
|
assert(kicked, 'Expected user to be kicked');
|
|
|
|
|
|
|
|
database.getDB().runTransaction(async tx => {
|
|
|
|
const ban = await tx.table('channel_bans')
|
|
|
|
.where({
|
|
|
|
channel: channelName,
|
|
|
|
name: 'test_user'
|
|
|
|
})
|
|
|
|
.first();
|
|
|
|
|
|
|
|
assert.strictEqual(ban.ip, '*');
|
|
|
|
assert.strictEqual(ban.reason, 'because reasons');
|
|
|
|
assert.strictEqual(ban.bannedby, mockUser.getName());
|
|
|
|
|
|
|
|
done();
|
|
|
|
});
|
2021-01-09 21:03:38 +00:00
|
|
|
};
|
2018-02-25 03:47:50 +00:00
|
|
|
|
|
|
|
mockChannel.users = [{
|
|
|
|
getLowerName() {
|
|
|
|
return 'test_user';
|
|
|
|
},
|
|
|
|
|
|
|
|
kick(reason) {
|
|
|
|
assert.strictEqual(reason, "You're banned!");
|
|
|
|
kicked = true;
|
|
|
|
}
|
|
|
|
}];
|
|
|
|
|
|
|
|
kickban.handleCmdBan(
|
|
|
|
mockUser,
|
|
|
|
'/ban test_user because reasons',
|
|
|
|
{}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2023-01-12 01:57:02 +00:00
|
|
|
it('rejects if the username is invalid', done => {
|
|
|
|
mockUser.socket.emit = (frame, obj) => {
|
|
|
|
if (frame === 'errorMsg') {
|
|
|
|
assert.strictEqual(
|
|
|
|
obj.msg,
|
|
|
|
'Invalid username'
|
|
|
|
);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
kickban.handleCmdBan(
|
|
|
|
mockUser,
|
|
|
|
'/ban test_user<>%$# because reasons',
|
|
|
|
{}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2018-02-25 03:47:50 +00:00
|
|
|
it('rejects if the user does not have ban permission', done => {
|
|
|
|
mockUser.socket.emit = (frame, obj) => {
|
|
|
|
if (frame === 'errorMsg') {
|
|
|
|
assert.strictEqual(
|
|
|
|
obj.msg,
|
|
|
|
'You do not have ban permissions on this channel'
|
|
|
|
);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
mockChannel.modules.permissions.canBan = () => false;
|
|
|
|
|
|
|
|
kickban.handleCmdBan(
|
|
|
|
mockUser,
|
|
|
|
'/ban test_user because reasons',
|
|
|
|
{}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('rejects if the user tries to ban themselves', done => {
|
|
|
|
let costanza = false;
|
|
|
|
|
|
|
|
mockUser.socket.emit = (frame, obj) => {
|
|
|
|
if (frame === 'errorMsg') {
|
|
|
|
assert.strictEqual(
|
|
|
|
obj.msg,
|
|
|
|
'You cannot ban yourself'
|
|
|
|
);
|
|
|
|
|
|
|
|
if (!costanza) {
|
|
|
|
throw new Error('Expected costanza for banning self');
|
|
|
|
}
|
|
|
|
|
|
|
|
done();
|
|
|
|
} else if (frame === 'costanza') {
|
|
|
|
assert.strictEqual(
|
|
|
|
obj.msg,
|
|
|
|
"You can't ban yourself"
|
|
|
|
);
|
|
|
|
|
|
|
|
costanza = true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
kickban.handleCmdBan(
|
|
|
|
mockUser,
|
|
|
|
'/ban the_Admin because reasons',
|
|
|
|
{}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('rejects if the user is ranked below the ban recipient', done => {
|
|
|
|
database.getDB().runTransaction(tx => {
|
|
|
|
return tx.table('channel_ranks')
|
|
|
|
.insert({
|
|
|
|
channel: channelName,
|
|
|
|
name: 'test_user',
|
|
|
|
rank: 5
|
|
|
|
});
|
|
|
|
}).then(() => {
|
|
|
|
mockUser.socket.emit = (frame, obj) => {
|
|
|
|
if (frame === 'errorMsg') {
|
|
|
|
assert.strictEqual(
|
|
|
|
obj.msg,
|
|
|
|
"You don't have permission to ban test_user"
|
|
|
|
);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
kickban.handleCmdBan(
|
|
|
|
mockUser,
|
|
|
|
'/ban test_user because reasons',
|
|
|
|
{}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('rejects if the the ban recipient is already banned', done => {
|
|
|
|
database.getDB().runTransaction(tx => {
|
|
|
|
return tx.table('channel_bans')
|
|
|
|
.insert({
|
|
|
|
channel: channelName,
|
|
|
|
name: 'test_user',
|
|
|
|
ip: '*',
|
|
|
|
bannedby: 'somebody',
|
|
|
|
reason: 'I dunno'
|
|
|
|
});
|
|
|
|
}).then(() => {
|
|
|
|
mockUser.socket.emit = (frame, obj) => {
|
|
|
|
if (frame === 'errorMsg') {
|
|
|
|
assert.strictEqual(
|
|
|
|
obj.msg,
|
|
|
|
'test_user is already banned'
|
|
|
|
);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
kickban.handleCmdBan(
|
|
|
|
mockUser,
|
|
|
|
'/ban test_user because reasons',
|
|
|
|
{}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('#handleCmdIPBan', () => {
|
|
|
|
beforeEach(async () => {
|
|
|
|
await database.getDB().runTransaction(async tx => {
|
|
|
|
await tx.table('aliases')
|
|
|
|
.insert([{
|
|
|
|
name: 'test_user',
|
2019-04-28 18:18:04 +00:00
|
|
|
ip: '1.2.3.4',
|
|
|
|
time: Date.now()
|
2018-02-25 03:47:50 +00:00
|
|
|
}]);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
afterEach(async () => {
|
|
|
|
await database.getDB().runTransaction(async tx => {
|
|
|
|
await tx.table('aliases')
|
|
|
|
.where({ name: 'test_user' })
|
|
|
|
.orWhere({ ip: '1.2.3.4' })
|
|
|
|
.del();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('inserts a valid ban', done => {
|
|
|
|
let firstUserKicked = false;
|
|
|
|
let secondUserKicked = false;
|
|
|
|
|
2021-01-09 21:03:38 +00:00
|
|
|
mockChannel.refCounter.unref = () => {
|
2018-02-25 03:47:50 +00:00
|
|
|
assert(firstUserKicked, 'Expected banned user to be kicked');
|
|
|
|
assert(
|
|
|
|
secondUserKicked,
|
|
|
|
'Expected user with banned IP to be kicked'
|
|
|
|
);
|
|
|
|
|
|
|
|
database.getDB().runTransaction(async tx => {
|
|
|
|
const nameBan = await tx.table('channel_bans')
|
|
|
|
.where({
|
|
|
|
channel: channelName,
|
|
|
|
name: 'test_user',
|
|
|
|
ip: '*'
|
|
|
|
})
|
|
|
|
.first();
|
|
|
|
|
|
|
|
assert.strictEqual(nameBan.reason, 'because reasons');
|
|
|
|
assert.strictEqual(nameBan.bannedby, mockUser.getName());
|
|
|
|
|
|
|
|
const ipBan = await tx.table('channel_bans')
|
|
|
|
.where({
|
|
|
|
channel: channelName,
|
|
|
|
ip: '1.2.3.4'
|
|
|
|
})
|
|
|
|
.first();
|
|
|
|
|
|
|
|
assert.strictEqual(ipBan.name, 'test_user');
|
|
|
|
assert.strictEqual(ipBan.reason, 'because reasons');
|
|
|
|
assert.strictEqual(ipBan.bannedby, mockUser.getName());
|
|
|
|
|
|
|
|
done();
|
|
|
|
});
|
2021-01-09 21:03:38 +00:00
|
|
|
};
|
2018-02-25 03:47:50 +00:00
|
|
|
|
|
|
|
mockChannel.users = [{
|
|
|
|
getLowerName() {
|
|
|
|
return 'test_user';
|
|
|
|
},
|
|
|
|
|
|
|
|
realip: '1.2.3.4',
|
|
|
|
|
|
|
|
kick(reason) {
|
|
|
|
assert.strictEqual(reason, "You're banned!");
|
|
|
|
firstUserKicked = true;
|
|
|
|
}
|
|
|
|
}, {
|
|
|
|
getLowerName() {
|
|
|
|
return 'second_user_same_ip';
|
|
|
|
},
|
|
|
|
|
|
|
|
realip: '1.2.3.4',
|
|
|
|
|
|
|
|
kick(reason) {
|
|
|
|
assert.strictEqual(reason, "You're banned!");
|
|
|
|
secondUserKicked = true;
|
|
|
|
}
|
|
|
|
}];
|
|
|
|
|
|
|
|
kickban.handleCmdIPBan(
|
|
|
|
mockUser,
|
|
|
|
'/ipban test_user because reasons',
|
|
|
|
{}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('inserts a valid range ban', done => {
|
2021-01-09 21:03:38 +00:00
|
|
|
mockChannel.refCounter.unref = () => {
|
2018-02-25 03:47:50 +00:00
|
|
|
database.getDB().runTransaction(async tx => {
|
|
|
|
const ipBan = await tx.table('channel_bans')
|
|
|
|
.where({
|
|
|
|
channel: channelName,
|
|
|
|
ip: '1.2.3'
|
|
|
|
})
|
|
|
|
.first();
|
|
|
|
|
|
|
|
assert.strictEqual(ipBan.name, 'test_user');
|
|
|
|
assert.strictEqual(ipBan.reason, 'because reasons');
|
|
|
|
assert.strictEqual(ipBan.bannedby, mockUser.getName());
|
|
|
|
|
|
|
|
done();
|
|
|
|
});
|
2021-01-09 21:03:38 +00:00
|
|
|
};
|
2018-02-25 03:47:50 +00:00
|
|
|
|
|
|
|
kickban.handleCmdIPBan(
|
|
|
|
mockUser,
|
|
|
|
'/ipban test_user range because reasons',
|
|
|
|
{}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('inserts a valid wide-range ban', done => {
|
2021-01-09 21:03:38 +00:00
|
|
|
mockChannel.refCounter.unref = () => {
|
2018-02-25 03:47:50 +00:00
|
|
|
database.getDB().runTransaction(async tx => {
|
|
|
|
const ipBan = await tx.table('channel_bans')
|
|
|
|
.where({
|
|
|
|
channel: channelName,
|
|
|
|
ip: '1.2'
|
|
|
|
})
|
|
|
|
.first();
|
|
|
|
|
|
|
|
assert.strictEqual(ipBan.name, 'test_user');
|
|
|
|
assert.strictEqual(ipBan.reason, 'because reasons');
|
|
|
|
assert.strictEqual(ipBan.bannedby, mockUser.getName());
|
|
|
|
|
|
|
|
done();
|
|
|
|
});
|
2021-01-09 21:03:38 +00:00
|
|
|
};
|
2018-02-25 03:47:50 +00:00
|
|
|
|
|
|
|
kickban.handleCmdIPBan(
|
|
|
|
mockUser,
|
|
|
|
'/ipban test_user wrange because reasons',
|
|
|
|
{}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('inserts a valid IPv6 ban', done => {
|
|
|
|
const longIP = require('../../lib/utilities').expandIPv6('::abcd');
|
|
|
|
|
2021-01-09 21:03:38 +00:00
|
|
|
mockChannel.refCounter.unref = () => {
|
2018-02-25 03:47:50 +00:00
|
|
|
database.getDB().runTransaction(async tx => {
|
|
|
|
const ipBan = await tx.table('channel_bans')
|
|
|
|
.where({
|
|
|
|
channel: channelName,
|
|
|
|
ip: longIP
|
|
|
|
})
|
|
|
|
.first();
|
|
|
|
|
|
|
|
assert.strictEqual(ipBan.name, 'test_user');
|
|
|
|
assert.strictEqual(ipBan.reason, 'because reasons');
|
|
|
|
assert.strictEqual(ipBan.bannedby, mockUser.getName());
|
|
|
|
|
|
|
|
done();
|
|
|
|
});
|
2021-01-09 21:03:38 +00:00
|
|
|
};
|
2018-02-25 03:47:50 +00:00
|
|
|
|
|
|
|
database.getDB().runTransaction(async tx => {
|
|
|
|
await tx.table('aliases')
|
|
|
|
.insert({
|
|
|
|
name: 'test_user',
|
2019-04-28 18:18:04 +00:00
|
|
|
ip: longIP,
|
|
|
|
time: Date.now()
|
2018-02-25 03:47:50 +00:00
|
|
|
});
|
|
|
|
}).then(() => {
|
|
|
|
kickban.handleCmdIPBan(
|
|
|
|
mockUser,
|
|
|
|
'/ipban test_user because reasons',
|
|
|
|
{}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('rejects if the user does not have ban permission', done => {
|
|
|
|
mockUser.socket.emit = (frame, obj) => {
|
|
|
|
if (frame === 'errorMsg') {
|
|
|
|
assert.strictEqual(
|
|
|
|
obj.msg,
|
|
|
|
'You do not have ban permissions on this channel'
|
|
|
|
);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
mockChannel.modules.permissions.canBan = () => false;
|
|
|
|
|
|
|
|
kickban.handleCmdIPBan(
|
|
|
|
mockUser,
|
|
|
|
'/ipban test_user because reasons',
|
|
|
|
{}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('rejects if the user tries to ban themselves', done => {
|
|
|
|
let costanza = false;
|
|
|
|
|
|
|
|
mockUser.socket.emit = (frame, obj) => {
|
|
|
|
if (frame === 'errorMsg') {
|
|
|
|
assert.strictEqual(
|
|
|
|
obj.msg,
|
|
|
|
'You cannot ban yourself'
|
|
|
|
);
|
|
|
|
|
|
|
|
if (!costanza) {
|
|
|
|
throw new Error('Expected costanza for banning self');
|
|
|
|
}
|
|
|
|
|
|
|
|
done();
|
|
|
|
} else if (frame === 'costanza') {
|
|
|
|
assert.strictEqual(
|
|
|
|
obj.msg,
|
|
|
|
"You can't ban yourself"
|
|
|
|
);
|
|
|
|
|
|
|
|
costanza = true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
kickban.handleCmdIPBan(
|
|
|
|
mockUser,
|
|
|
|
'/ipban the_Admin because reasons',
|
|
|
|
{}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('rejects if the user is ranked below the ban recipient', done => {
|
|
|
|
database.getDB().runTransaction(tx => {
|
|
|
|
return tx.table('channel_ranks')
|
|
|
|
.insert({
|
|
|
|
channel: channelName,
|
|
|
|
name: 'test_user',
|
|
|
|
rank: 5
|
|
|
|
});
|
|
|
|
}).then(() => {
|
|
|
|
mockUser.socket.emit = (frame, obj) => {
|
|
|
|
if (frame === 'errorMsg') {
|
|
|
|
assert.strictEqual(
|
|
|
|
obj.msg,
|
|
|
|
"You don't have permission to ban IP " +
|
|
|
|
"09l.TFb.5To.HBB"
|
|
|
|
);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
kickban.handleCmdIPBan(
|
|
|
|
mockUser,
|
|
|
|
'/ipban test_user because reasons',
|
|
|
|
{}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('rejects if the user is ranked below an alias of the ban recipient', done => {
|
|
|
|
database.getDB().runTransaction(async tx => {
|
|
|
|
await tx.table('channel_ranks')
|
|
|
|
.insert({
|
|
|
|
channel: channelName,
|
|
|
|
name: 'another_user',
|
|
|
|
rank: 5
|
|
|
|
});
|
|
|
|
await tx.table('aliases')
|
|
|
|
.insert({
|
|
|
|
name: 'another_user',
|
2019-04-28 18:18:04 +00:00
|
|
|
ip: '1.2.3.3', // different IP, same /24 range
|
|
|
|
time: Date.now()
|
2018-02-25 03:47:50 +00:00
|
|
|
});
|
|
|
|
}).then(() => {
|
|
|
|
mockUser.socket.emit = (frame, obj) => {
|
|
|
|
if (frame === 'errorMsg') {
|
|
|
|
assert.strictEqual(
|
|
|
|
obj.msg,
|
|
|
|
"You don't have permission to ban IP " +
|
|
|
|
"09l.TFb.5To.*"
|
|
|
|
);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
kickban.handleCmdIPBan(
|
|
|
|
mockUser,
|
|
|
|
'/ipban test_user range because reasons',
|
|
|
|
{}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('rejects if the the ban recipient IP is already banned', done => {
|
|
|
|
database.getDB().runTransaction(tx => {
|
|
|
|
return tx.table('channel_bans')
|
|
|
|
.insert({
|
|
|
|
channel: channelName,
|
|
|
|
name: 'another_user',
|
|
|
|
ip: '1.2.3.4',
|
|
|
|
bannedby: 'somebody',
|
|
|
|
reason: 'I dunno'
|
|
|
|
});
|
|
|
|
}).then(() => {
|
|
|
|
mockUser.socket.emit = (frame, obj) => {
|
|
|
|
if (frame === 'errorMsg') {
|
|
|
|
assert.strictEqual(
|
|
|
|
obj.msg,
|
|
|
|
'09l.TFb.5To.HBB is already banned'
|
|
|
|
);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
kickban.handleCmdIPBan(
|
|
|
|
mockUser,
|
|
|
|
'/ipban test_user because reasons',
|
|
|
|
{}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('still adds the IP ban even if the name is already banned', done => {
|
2021-01-09 21:03:38 +00:00
|
|
|
mockChannel.refCounter.unref = () => {
|
2018-02-25 03:47:50 +00:00
|
|
|
database.getDB().runTransaction(async tx => {
|
|
|
|
const ipBan = await tx.table('channel_bans')
|
|
|
|
.where({
|
|
|
|
channel: channelName,
|
|
|
|
ip: '1.2.3.4'
|
|
|
|
})
|
|
|
|
.first();
|
|
|
|
|
|
|
|
assert.strictEqual(ipBan.name, 'test_user');
|
|
|
|
assert.strictEqual(ipBan.reason, 'because reasons');
|
|
|
|
assert.strictEqual(ipBan.bannedby, mockUser.getName());
|
|
|
|
|
|
|
|
done();
|
|
|
|
});
|
2021-01-09 21:03:38 +00:00
|
|
|
};
|
2018-02-25 03:47:50 +00:00
|
|
|
|
|
|
|
database.getDB().runTransaction(tx => {
|
|
|
|
return tx.table('channel_bans')
|
|
|
|
.insert({
|
|
|
|
channel: channelName,
|
|
|
|
name: 'test_user',
|
|
|
|
ip: '*',
|
|
|
|
bannedby: 'somebody',
|
|
|
|
reason: 'I dunno'
|
|
|
|
});
|
|
|
|
}).then(() => {
|
|
|
|
kickban.handleCmdIPBan(
|
|
|
|
mockUser,
|
|
|
|
'/ipban test_user because reasons',
|
|
|
|
{}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|