mirror of https://github.com/calzoneman/sync.git
deps: remove "q" (#731)
Insert Star Trek joke here. Also did significant refactoring of the surrounding logic for the things that depended on Q.
This commit is contained in:
parent
d5f5c91b05
commit
79556d9365
|
@ -0,0 +1,581 @@
|
|||
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,
|
||||
refCounter: {
|
||||
ref() { },
|
||||
unref() { }
|
||||
},
|
||||
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;
|
||||
|
||||
mockChannel.refCounter.unref = () => {
|
||||
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();
|
||||
});
|
||||
};
|
||||
|
||||
mockChannel.users = [{
|
||||
getLowerName() {
|
||||
return 'test_user';
|
||||
},
|
||||
|
||||
kick(reason) {
|
||||
assert.strictEqual(reason, "You're banned!");
|
||||
kicked = true;
|
||||
}
|
||||
}];
|
||||
|
||||
kickban.handleCmdBan(
|
||||
mockUser,
|
||||
'/ban 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.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',
|
||||
ip: '1.2.3.4'
|
||||
}]);
|
||||
});
|
||||
});
|
||||
|
||||
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;
|
||||
|
||||
mockChannel.refCounter.unref = () => {
|
||||
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();
|
||||
});
|
||||
};
|
||||
|
||||
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 => {
|
||||
mockChannel.refCounter.unref = () => {
|
||||
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();
|
||||
});
|
||||
};
|
||||
|
||||
kickban.handleCmdIPBan(
|
||||
mockUser,
|
||||
'/ipban test_user range because reasons',
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('inserts a valid wide-range ban', done => {
|
||||
mockChannel.refCounter.unref = () => {
|
||||
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();
|
||||
});
|
||||
};
|
||||
|
||||
kickban.handleCmdIPBan(
|
||||
mockUser,
|
||||
'/ipban test_user wrange because reasons',
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('inserts a valid IPv6 ban', done => {
|
||||
const longIP = require('../../lib/utilities').expandIPv6('::abcd');
|
||||
|
||||
mockChannel.refCounter.unref = () => {
|
||||
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();
|
||||
});
|
||||
};
|
||||
|
||||
database.getDB().runTransaction(async tx => {
|
||||
await tx.table('aliases')
|
||||
.insert({
|
||||
name: 'test_user',
|
||||
ip: longIP
|
||||
});
|
||||
}).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',
|
||||
ip: '1.2.3.3' // different IP, same /24 range
|
||||
});
|
||||
}).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 => {
|
||||
mockChannel.refCounter.unref = () => {
|
||||
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();
|
||||
});
|
||||
};
|
||||
|
||||
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',
|
||||
{}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -2,7 +2,7 @@
|
|||
"author": "Calvin Montgomery",
|
||||
"name": "CyTube",
|
||||
"description": "Online media synchronizer and chat",
|
||||
"version": "3.54.0",
|
||||
"version": "3.55.0",
|
||||
"repository": {
|
||||
"url": "http://github.com/calzoneman/sync"
|
||||
},
|
||||
|
@ -33,7 +33,6 @@
|
|||
"prom-client": "^10.0.2",
|
||||
"proxy-addr": "^2.0.2",
|
||||
"pug": "^2.0.0-beta3",
|
||||
"q": "^1.4.1",
|
||||
"redis": "^2.4.2",
|
||||
"sanitize-html": "^1.14.1",
|
||||
"serve-static": "^1.13.2",
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
var db = require("./database");
|
||||
var Q = require("q");
|
||||
import db from './database';
|
||||
import Promise from 'bluebird';
|
||||
|
||||
const dbGetGlobalRank = Promise.promisify(db.users.getGlobalRank);
|
||||
const dbMultiGetGlobalRank = Promise.promisify(db.users.getGlobalRanks);
|
||||
const dbGetChannelRank = Promise.promisify(db.channels.getRank);
|
||||
const dbMultiGetChannelRank = Promise.promisify(db.channels.getRanks);
|
||||
const dbGetAliases = Promise.promisify(db.getAliases);
|
||||
|
||||
const DEFAULT_PROFILE = Object.freeze({ image: '', text: '' });
|
||||
|
||||
|
@ -33,71 +39,21 @@ class Account {
|
|||
|
||||
module.exports.Account = Account;
|
||||
|
||||
module.exports.rankForName = function (name, opts, cb) {
|
||||
if (!cb) {
|
||||
cb = opts;
|
||||
opts = {};
|
||||
}
|
||||
module.exports.rankForName = async function rankForNameAsync(name, channel) {
|
||||
const [globalRank, channelRank] = await Promise.all([
|
||||
dbGetGlobalRank(name),
|
||||
dbGetChannelRank(channel, name)
|
||||
]);
|
||||
|
||||
var rank = 0;
|
||||
Q.fcall(function () {
|
||||
return Q.nfcall(db.users.getGlobalRank, name);
|
||||
}).then(function (globalRank) {
|
||||
rank = globalRank;
|
||||
if (opts.channel) {
|
||||
return Q.nfcall(db.channels.getRank, opts.channel, name);
|
||||
} else {
|
||||
return globalRank > 0 ? 1 : 0;
|
||||
}
|
||||
}).then(function (chanRank) {
|
||||
setImmediate(function () {
|
||||
cb(null, Math.max(rank, chanRank));
|
||||
});
|
||||
}).catch(function (err) {
|
||||
cb(err, 0);
|
||||
}).done();
|
||||
return Math.max(globalRank, channelRank);
|
||||
};
|
||||
|
||||
module.exports.rankForIP = function (ip, opts, cb) {
|
||||
if (!cb) {
|
||||
cb = opts;
|
||||
opts = {};
|
||||
}
|
||||
module.exports.rankForIP = async function rankForIP(ip, channel) {
|
||||
const aliases = await dbGetAliases(ip);
|
||||
const [globalRanks, channelRanks] = await Promise.all([
|
||||
dbMultiGetGlobalRank(aliases),
|
||||
dbMultiGetChannelRank(channel, aliases)
|
||||
]);
|
||||
|
||||
var globalRank, rank, names;
|
||||
|
||||
var promise = Q.nfcall(db.getAliases, ip)
|
||||
.then(function (_names) {
|
||||
names = _names;
|
||||
return Q.nfcall(db.users.getGlobalRanks, names);
|
||||
}).then(function (ranks) {
|
||||
ranks.push(0);
|
||||
globalRank = Math.max.apply(Math, ranks);
|
||||
rank = globalRank;
|
||||
});
|
||||
|
||||
if (!opts.channel) {
|
||||
promise.then(function () {
|
||||
setImmediate(function () {
|
||||
cb(null, globalRank);
|
||||
});
|
||||
}).catch(function (err) {
|
||||
cb(err, null);
|
||||
}).done();
|
||||
} else {
|
||||
promise.then(function () {
|
||||
return Q.nfcall(db.channels.getRanks, opts.channel, names);
|
||||
}).then(function (ranks) {
|
||||
ranks.push(globalRank);
|
||||
rank = Math.max.apply(Math, ranks);
|
||||
}).then(function () {
|
||||
setImmediate(function () {
|
||||
cb(null, rank);
|
||||
});
|
||||
}).catch(function (err) {
|
||||
setImmediate(function () {
|
||||
cb(err, null);
|
||||
});
|
||||
}).done();
|
||||
}
|
||||
return Math.max.apply(Math, globalRanks.concat(channelRanks));
|
||||
};
|
||||
|
|
|
@ -3,7 +3,12 @@ var db = require("../database");
|
|||
var Flags = require("../flags");
|
||||
var util = require("../utilities");
|
||||
var Account = require("../account");
|
||||
var Q = require("q");
|
||||
import Promise from 'bluebird';
|
||||
|
||||
const dbIsNameBanned = Promise.promisify(db.channels.isNameBanned);
|
||||
const dbIsIPBanned = Promise.promisify(db.channels.isIPBanned);
|
||||
const dbAddBan = Promise.promisify(db.channels.ban);
|
||||
const dbGetIPs = Promise.promisify(db.getIPs);
|
||||
|
||||
const TYPE_UNBAN = {
|
||||
id: "number",
|
||||
|
@ -234,7 +239,11 @@ KickBanModule.prototype.handleCmdBan = function (user, msg, meta) {
|
|||
|
||||
const chan = this.channel;
|
||||
chan.refCounter.ref("KickBanModule::handleCmdBan");
|
||||
this.banName(user, name, reason, function (err) {
|
||||
|
||||
this.banName(user, name, reason).catch(error => {
|
||||
const message = error.message || error;
|
||||
user.socket.emit("errorMsg", { msg: message });
|
||||
}).finally(() => {
|
||||
chan.refCounter.unref("KickBanModule::handleCmdBan");
|
||||
});
|
||||
};
|
||||
|
@ -261,23 +270,29 @@ KickBanModule.prototype.handleCmdIPBan = function (user, msg, meta) {
|
|||
|
||||
const chan = this.channel;
|
||||
chan.refCounter.ref("KickBanModule::handleCmdIPBan");
|
||||
this.banAll(user, name, range, reason, function (err) {
|
||||
|
||||
this.banAll(user, name, range, reason).catch(error => {
|
||||
//console.log('!!!', error.stack);
|
||||
const message = error.message || error;
|
||||
user.socket.emit("errorMsg", { msg: message });
|
||||
}).finally(() => {
|
||||
chan.refCounter.unref("KickBanModule::handleCmdIPBan");
|
||||
});
|
||||
};
|
||||
|
||||
KickBanModule.prototype.banName = function (actor, name, reason, cb) {
|
||||
var self = this;
|
||||
KickBanModule.prototype.checkChannelAlive = function checkChannelAlive() {
|
||||
if (!this.channel || this.channel.dead) {
|
||||
throw new Error("Channel not live");
|
||||
}
|
||||
};
|
||||
|
||||
KickBanModule.prototype.banName = async function banName(actor, name, reason) {
|
||||
reason = reason.substring(0, 255);
|
||||
|
||||
var chan = this.channel;
|
||||
var error = function (what) {
|
||||
actor.socket.emit("errorMsg", { msg: what });
|
||||
cb(what);
|
||||
};
|
||||
|
||||
if (!chan.modules.permissions.canBan(actor)) {
|
||||
return error("You do not have ban permissions on this channel");
|
||||
throw new Error("You do not have ban permissions on this channel");
|
||||
}
|
||||
|
||||
name = name.toLowerCase();
|
||||
|
@ -285,129 +300,126 @@ KickBanModule.prototype.banName = function (actor, name, reason, cb) {
|
|||
actor.socket.emit("costanza", {
|
||||
msg: "You can't ban yourself"
|
||||
});
|
||||
return cb("Attempted to ban self");
|
||||
|
||||
throw new Error("You cannot ban yourself");
|
||||
}
|
||||
|
||||
Q.nfcall(Account.rankForName, name, { channel: chan.name })
|
||||
.then(function (rank) {
|
||||
if (rank >= actor.account.effectiveRank) {
|
||||
throw "You don't have permission to ban " + name;
|
||||
}
|
||||
const rank = await Account.rankForName(name, chan.name);
|
||||
this.checkChannelAlive();
|
||||
|
||||
return Q.nfcall(db.channels.isNameBanned, chan.name, name);
|
||||
}).then(function (banned) {
|
||||
if (banned) {
|
||||
throw name + " is already banned";
|
||||
}
|
||||
if (rank >= actor.account.effectiveRank) {
|
||||
throw new Error("You don't have permission to ban " + name);
|
||||
}
|
||||
|
||||
if (chan.dead) { throw null; }
|
||||
const isBanned = await dbIsNameBanned(chan.name, name);
|
||||
this.checkChannelAlive();
|
||||
|
||||
return Q.nfcall(db.channels.ban, chan.name, "*", name, reason, actor.getName());
|
||||
}).then(function () {
|
||||
chan.logger.log("[mod] " + actor.getName() + " namebanned " + name);
|
||||
if (chan.modules.chat) {
|
||||
chan.modules.chat.sendModMessage(actor.getName() + " namebanned " + name,
|
||||
chan.modules.permissions.permissions.ban);
|
||||
}
|
||||
return true;
|
||||
}).then(function () {
|
||||
self.kickBanTarget(name, null);
|
||||
setImmediate(function () {
|
||||
cb(null);
|
||||
});
|
||||
}).catch(error).done();
|
||||
if (isBanned) {
|
||||
throw new Error(name + " is already banned");
|
||||
}
|
||||
|
||||
await dbAddBan(chan.name, "*", name, reason, actor.getName());
|
||||
this.checkChannelAlive();
|
||||
|
||||
chan.logger.log("[mod] " + actor.getName() + " namebanned " + name);
|
||||
|
||||
if (chan.modules.chat) {
|
||||
chan.modules.chat.sendModMessage(
|
||||
actor.getName() + " namebanned " + name,
|
||||
chan.modules.permissions.permissions.ban
|
||||
);
|
||||
}
|
||||
|
||||
this.kickBanTarget(name, null);
|
||||
};
|
||||
|
||||
KickBanModule.prototype.banIP = function (actor, ip, name, reason, cb) {
|
||||
var self = this;
|
||||
KickBanModule.prototype.banIP = async function banIP(actor, ip, name, reason) {
|
||||
reason = reason.substring(0, 255);
|
||||
var masked = util.cloakIP(ip);
|
||||
|
||||
var chan = this.channel;
|
||||
var error = function (what) {
|
||||
actor.socket.emit("errorMsg", { msg: what });
|
||||
cb(what);
|
||||
};
|
||||
|
||||
if (!chan.modules.permissions.canBan(actor)) {
|
||||
return error("You do not have ban permissions on this channel");
|
||||
throw new Error("You do not have ban permissions on this channel");
|
||||
}
|
||||
|
||||
Q.nfcall(Account.rankForIP, ip, { channel: chan.name }).then(function (rank) {
|
||||
if (rank >= actor.account.effectiveRank) {
|
||||
throw "You don't have permission to ban IP " + masked;
|
||||
}
|
||||
const rank = await Account.rankForIP(ip, chan.name);
|
||||
this.checkChannelAlive();
|
||||
|
||||
return Q.nfcall(db.channels.isIPBanned, chan.name, ip);
|
||||
}).then(function (banned) {
|
||||
if (banned) {
|
||||
throw masked + " is already banned";
|
||||
}
|
||||
if (rank >= actor.account.effectiveRank) {
|
||||
// TODO: this message should be made friendlier
|
||||
throw new Error("You don't have permission to ban IP " + masked);
|
||||
}
|
||||
|
||||
if (chan.dead) { throw null; }
|
||||
const isBanned = await dbIsIPBanned(chan.name, ip);
|
||||
this.checkChannelAlive();
|
||||
|
||||
return Q.nfcall(db.channels.ban, chan.name, ip, name, reason, actor.getName());
|
||||
}).then(function () {
|
||||
var cloaked = util.cloakIP(ip);
|
||||
chan.logger.log("[mod] " + actor.getName() + " banned " + cloaked + " (" + name + ")");
|
||||
if (chan.modules.chat) {
|
||||
chan.modules.chat.sendModMessage(actor.getName() + " banned " +
|
||||
cloaked + " (" + name + ")",
|
||||
chan.modules.permissions.permissions.ban);
|
||||
}
|
||||
}).then(function () {
|
||||
self.kickBanTarget(name, ip);
|
||||
setImmediate(function () {
|
||||
cb(null);
|
||||
});
|
||||
}).catch(error).done();
|
||||
if (isBanned) {
|
||||
// TODO: this message should be made friendlier
|
||||
throw new Error(masked + " is already banned");
|
||||
}
|
||||
|
||||
await dbAddBan(chan.name, ip, name, reason, actor.getName());
|
||||
this.checkChannelAlive();
|
||||
|
||||
var cloaked = util.cloakIP(ip);
|
||||
chan.logger.log(
|
||||
"[mod] " + actor.getName() + " banned " + cloaked +
|
||||
" (" + name + ")"
|
||||
);
|
||||
|
||||
if (chan.modules.chat) {
|
||||
chan.modules.chat.sendModMessage(
|
||||
actor.getName() + " banned " + cloaked + " (" + name + ")",
|
||||
chan.modules.permissions.permissions.ban
|
||||
);
|
||||
}
|
||||
|
||||
this.kickBanTarget(name, ip);
|
||||
};
|
||||
|
||||
KickBanModule.prototype.banAll = function (actor, name, range, reason, cb) {
|
||||
var self = this;
|
||||
KickBanModule.prototype.banAll = async function banAll(
|
||||
actor,
|
||||
name,
|
||||
range,
|
||||
reason
|
||||
) {
|
||||
reason = reason.substring(0, 255);
|
||||
|
||||
var chan = self.channel;
|
||||
var error = function (what) {
|
||||
cb(what);
|
||||
};
|
||||
var chan = this.channel;
|
||||
|
||||
if (!chan.modules.permissions.canBan(actor)) {
|
||||
return error("You do not have ban permissions on this channel");
|
||||
throw new Error("You do not have ban permissions on this channel");
|
||||
}
|
||||
|
||||
self.banName(actor, name, reason, function (err) {
|
||||
if (err && err.indexOf("is already banned") === -1) {
|
||||
cb(err);
|
||||
} else {
|
||||
db.getIPs(name, function (err, ips) {
|
||||
if (err) {
|
||||
return error(err);
|
||||
}
|
||||
const ips = await dbGetIPs(name);
|
||||
this.checkChannelAlive();
|
||||
|
||||
var seenIPs = {};
|
||||
var all = ips.map(function (ip) {
|
||||
if (range === "range") {
|
||||
ip = util.getIPRange(ip);
|
||||
} else if (range === "wrange") {
|
||||
ip = util.getWideIPRange(ip);
|
||||
}
|
||||
|
||||
if (seenIPs.hasOwnProperty(ip)) {
|
||||
return;
|
||||
} else {
|
||||
seenIPs[ip] = true;
|
||||
}
|
||||
|
||||
return Q.nfcall(self.banIP.bind(self), actor, ip, name, reason);
|
||||
});
|
||||
|
||||
Q.all(all).then(function () {
|
||||
setImmediate(cb);
|
||||
}).catch(error).done();
|
||||
});
|
||||
const toBan = new Set();
|
||||
for (let ip of ips) {
|
||||
switch (range) {
|
||||
case "range":
|
||||
toBan.add(util.getIPRange(ip));
|
||||
break;
|
||||
case "wrange":
|
||||
toBan.add(util.getWideIPRange(ip));
|
||||
break;
|
||||
default:
|
||||
toBan.add(ip);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const promises = Array.from(toBan).map(ip =>
|
||||
this.banIP(actor, ip, name, reason)
|
||||
);
|
||||
|
||||
if (!await dbIsNameBanned(chan.name, name)) {
|
||||
promises.push(this.banName(actor, name, reason));
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
this.checkChannelAlive();
|
||||
};
|
||||
|
||||
KickBanModule.prototype.kickBanTarget = function (name, ip) {
|
||||
|
|
|
@ -2,6 +2,9 @@ var ChannelModule = require("./module");
|
|||
var Flags = require("../flags");
|
||||
var Account = require("../account");
|
||||
var db = require("../database");
|
||||
import Promise from 'bluebird';
|
||||
|
||||
const dbSetChannelRank = Promise.promisify(db.channels.setRank);
|
||||
|
||||
const TYPE_SET_CHANNEL_RANK = {
|
||||
name: "string",
|
||||
|
@ -177,17 +180,20 @@ RankModule.prototype.handleRankChange = function (user, data) {
|
|||
|
||||
RankModule.prototype.updateDatabase = function (data, cb) {
|
||||
var chan = this.channel;
|
||||
Account.rankForName(data.name, { channel: this.channel.name }, function (err, rank) {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
Account.rankForName(data.name, this.channel.name).then(rank => {
|
||||
if (rank >= data.userrank && !(rank === 4 && data.userrank === 4)) {
|
||||
cb("You can't promote or demote someone with equal or higher rank than you.");
|
||||
throw new Error(
|
||||
"You can't promote or demote someone" +
|
||||
" with equal or higher rank than you."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
db.channels.setRank(chan.name, data.name, data.rank, cb);
|
||||
return dbSetChannelRank(chan.name, data.name, data.rank);
|
||||
}).then(() => {
|
||||
process.nextTick(cb);
|
||||
}).catch(error => {
|
||||
process.nextTick(cb, error.message || error);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -71,6 +71,8 @@ class Database {
|
|||
}
|
||||
|
||||
module.exports.Database = Database;
|
||||
module.exports.users = require("./database/accounts");
|
||||
module.exports.channels = require("./database/channels");
|
||||
|
||||
module.exports.init = function (newDB) {
|
||||
if (newDB) {
|
||||
|
@ -85,9 +87,6 @@ module.exports.init = function (newDB) {
|
|||
}).then(() => {
|
||||
process.nextTick(legacySetup);
|
||||
});
|
||||
|
||||
module.exports.users = require("./database/accounts");
|
||||
module.exports.channels = require("./database/channels");
|
||||
};
|
||||
|
||||
module.exports.getDB = function getDB() {
|
||||
|
|
|
@ -328,10 +328,10 @@ module.exports = {
|
|||
var replace = "(" + names.map(function () { return "?"; }).join(",") + ")";
|
||||
|
||||
/* Last substitution is the channel to select ranks for */
|
||||
names.push(chan);
|
||||
const sub = names.concat([chan]);
|
||||
|
||||
db.query("SELECT * FROM `channel_ranks` WHERE name IN " +
|
||||
replace + " AND channel=?", names,
|
||||
replace + " AND channel=?", sub,
|
||||
function (err, rows) {
|
||||
if (err) {
|
||||
callback(err, []);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
var db = require("../database");
|
||||
var Q = require("q");
|
||||
import Promise from 'bluebird';
|
||||
|
||||
const LOGGER = require('@calzoneman/jsli')('database/update');
|
||||
|
@ -41,15 +40,9 @@ module.exports.checkVersion = function () {
|
|||
};
|
||||
|
||||
function update(version, cb) {
|
||||
if (version < 4) {
|
||||
if (version < 7) {
|
||||
LOGGER.error('Cannot auto-upgrade: db_version 4 is too old!');
|
||||
process.exit(1);
|
||||
} else if (version < 5) {
|
||||
fixUtf8mb4(cb);
|
||||
} else if (version < 6) {
|
||||
fixCustomEmbeds(cb);
|
||||
} else if (version < 7) {
|
||||
fixCustomEmbedsInUserPlaylists(cb);
|
||||
} else if (version < 8) {
|
||||
addUsernameDedupeColumn(cb);
|
||||
} else if (version < 9) {
|
||||
|
@ -61,110 +54,6 @@ function update(version, cb) {
|
|||
}
|
||||
}
|
||||
|
||||
function fixUtf8mb4(cb) {
|
||||
var queries = [
|
||||
"ALTER TABLE `users` MODIFY `profile` TEXT CHARACTER SET utf8mb4 NOT NULL",
|
||||
"ALTER TABLE `global_bans` MODIFY `reason` VARCHAR(255) CHARACTER SET utf8mb4 NOT NULL",
|
||||
"ALTER TABLE `channel_libraries` MODIFY `title` VARCHAR(255) CHARACTER SET utf8mb4 NOT NULL",
|
||||
"ALTER TABLE `channel_bans` MODIFY `reason` VARCHAR(255) CHARACTER SET utf8mb4 NOT NULL"
|
||||
];
|
||||
|
||||
Q.allSettled(queries.map(function (query) {
|
||||
return Q.nfcall(db.query, query);
|
||||
})).then(function () {
|
||||
LOGGER.info("Fixed utf8mb4");
|
||||
cb();
|
||||
}).catch(function (e) {
|
||||
LOGGER.error("Failed to fix utf8mb4: " + e);
|
||||
});
|
||||
};
|
||||
|
||||
function fixCustomEmbeds(cb) {
|
||||
var CustomEmbedFilter = require("../customembed").filter;
|
||||
|
||||
Q.nfcall(db.query, "SELECT * FROM `channel_libraries` WHERE type='cu'")
|
||||
.then(function (rows) {
|
||||
var all = [];
|
||||
rows.forEach(function (row) {
|
||||
if (row.id.indexOf("cu:") === 0) return;
|
||||
|
||||
all.push(Q.nfcall(db.query, "DELETE FROM `channel_libraries` WHERE `id`=? AND `channel`=?",
|
||||
[row.id, row.channel]));
|
||||
|
||||
try {
|
||||
var media = CustomEmbedFilter(row.id);
|
||||
|
||||
all.push(Q.nfcall(db.channels.addToLibrary, row.channel, media));
|
||||
} catch(e) {
|
||||
console.error("WARNING: Unable to convert " + row.id);
|
||||
}
|
||||
});
|
||||
|
||||
Q.allSettled(all).then(function () {
|
||||
LOGGER.info("Converted custom embeds.");
|
||||
cb();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function fixCustomEmbedsInUserPlaylists(cb) {
|
||||
var CustomEmbedFilter = require("../customembed").filter;
|
||||
Q.nfcall(db.query, "SELECT * FROM `user_playlists` WHERE `contents` LIKE '%\"type\":\"cu\"%'")
|
||||
.then(function (rows) {
|
||||
var all = [];
|
||||
rows.forEach(function (row) {
|
||||
var data;
|
||||
try {
|
||||
data = JSON.parse(row.contents);
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
|
||||
var updated = [];
|
||||
var item;
|
||||
while ((item = data.shift()) !== undefined) {
|
||||
if (item.type !== "cu") {
|
||||
updated.push(item);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (/^cu:/.test(item.id)) {
|
||||
updated.push(item);
|
||||
continue;
|
||||
}
|
||||
|
||||
var media;
|
||||
try {
|
||||
media = CustomEmbedFilter(item.id);
|
||||
} catch (e) {
|
||||
LOGGER.info("WARNING: Unable to convert " + item.id);
|
||||
continue;
|
||||
}
|
||||
|
||||
updated.push({
|
||||
id: media.id,
|
||||
title: item.title,
|
||||
seconds: media.seconds,
|
||||
type: media.type,
|
||||
meta: {
|
||||
embed: media.meta.embed
|
||||
}
|
||||
});
|
||||
|
||||
all.push(Q.nfcall(db.query, "UPDATE `user_playlists` SET `contents`=?, `count`=? WHERE `user`=? AND `name`=?",
|
||||
[JSON.stringify(updated), updated.length, row.user, row.name]));
|
||||
}
|
||||
});
|
||||
|
||||
Q.allSettled(all).then(function () {
|
||||
LOGGER.info('Fixed custom embeds in user_playlists');
|
||||
cb();
|
||||
});
|
||||
}).catch(function (err) {
|
||||
LOGGER.error(err.stack);
|
||||
});
|
||||
}
|
||||
|
||||
function addUsernameDedupeColumn(cb) {
|
||||
LOGGER.info("Adding name_dedupe column on the users table");
|
||||
db.query("ALTER TABLE users ADD COLUMN name_dedupe VARCHAR(20) UNIQUE DEFAULT NULL", (error) => {
|
||||
|
|
Loading…
Reference in New Issue