Updated nick handling

This commit is contained in:
Andris Reinman 2017-09-18 17:10:35 +03:00
parent c0351a91cf
commit 6db8e096bc
5 changed files with 159 additions and 13 deletions

View file

@ -10,7 +10,10 @@ secure=false
[motd]
source="message" # "message" or "file"
#file="/path/to/motd"
message="Set MOTD message with the server config option \u0002irc.motd\u0002"
message="""
Set MOTD message with the server config option \u0002irc.motd\u0002.
Once you have set or changed the message then reload the server by
running \u0002systemctl reload wildduck\u0002 or send a SIGHUP message to it"""
[tls]
# If certificate path is not defined, use global or built-in self-signed certs

View file

@ -335,3 +335,14 @@ indexes:
expireAfterSeconds: 15552000
key:
updated: 1
# Indexes for IRC
- collection: nicks
index:
name: irc_nicks
unique: true
key:
ns: 1
unickview: 1
user: 1

View file

@ -51,7 +51,7 @@ class GridstoreStorage {
transferEncoding: attachment.transferEncoding
};
if (!isNaN(metadata.m)) {
if (isNaN(metadata.m) || typeof metadata.m !== 'number') {
errors.notify(new Error('Invalid magic "' + metadata.m + '" for ' + id));
}
@ -198,7 +198,7 @@ class GridstoreStorage {
}
delete(id, magic, callback) {
if (!isNaN(magic)) {
if (isNaN(magic) || typeof magic !== 'number') {
errors.notify(new Error('Invalid magic "' + magic + '" for ' + id));
}
this.gridfs.collection(this.bucketName + '.files').findOneAndUpdate({
@ -239,7 +239,7 @@ class GridstoreStorage {
}
update(ids, count, magic, callback) {
if (!isNaN(magic)) {
if (isNaN(magic) || typeof magic !== 'number') {
errors.notify(new Error('Invalid magic "' + magic + '" for ' + ids));
}
// update attachments

View file

@ -5,6 +5,7 @@ const crypto = require('crypto');
const EventEmitter = require('events');
const os = require('os');
const codes = require('./codes');
const db = require('../db');
const PING_TIMEOUT = 120 * 1000;
const SOCKET_TIMEOUT = 5 * 60 * 1000;
@ -412,16 +413,128 @@ class IRCConnection extends EventEmitter {
return next();
}
//this.session.clientHostname = 'example.com';
this.session.user = result.username;
next(null, {
id: result.user,
username: result.username
db.users.collection('users').findOne({ _id: result.user }, {
fields: {
_id: true,
username: true,
address: true,
name: true,
ns: true
}
}, (err, userData) => {
if (err) {
return next(err);
}
let ns = userData.ns;
if (userData.address) {
let parts = userData.address.split('@');
this.session.user = parts.shift();
this.session.clientHostname = parts.join('@');
if (!ns) {
ns = this.session.clientHostname;
}
}
this.session.ns = ns || 'root';
next(null, {
id: userData._id,
username: userData.username
});
});
}
);
}
getNick(nick, next) {
let ns = this.session.ns;
let unickview = nick.toLowerCase().replace(/\./g, '');
let user = this.session.auth.id;
let verifyUser = done => {
if (unickview === this.session.auth.username.replace(/\./g, '')) {
return done();
}
db.users.collection('users').findOne({ unameview: unickview }, {
fields: {
_id: true,
username: true
}
}, (err, userData) => {
if (err) {
return next(err);
}
if (userData && userData._id.toString() !== this.session.auth.id.toString()) {
return next(new Error('Can not acquire reserved nick'));
}
return done();
});
};
verifyUser(() => {
db.database.collection('nicks').insertOne({
ns,
unickview,
nick,
user
}, (err, r) => {
if (err) {
if (err.code === 11000) {
return db.database.collection('nicks').findOne({
ns,
unickview
}, (err, nickData) => {
if (err) {
return next(err);
}
if (!nickData) {
return next(new Error('Race condition in acquireing nick'));
}
if (nickData.user.toString() === user.toString()) {
return next(null, nickData._id);
}
return next(new Error('Requested nick is already in use'));
});
}
return next(err);
}
let insertId = r && r.insertedId;
if (!insertId) {
return next(new Error('Failed to set up nick'));
}
// try to remove old nicks
db.database.collection('nicks').deleteOne({
ns,
unickview: { $ne: unickview },
user
}, () => next(null, insertId));
});
});
}
verifyNickChange(currentSource, next) {
this.getNick(this.session.nick, err => {
if (err) {
currentSource = currentSource || this.getFormattedName();
this.send({ verb: 'ERR_UNAVAILRESOURCE', params: err.message });
this.session.nick = this.session.user;
}
if (currentSource) {
this.send({ source: currentSource, verb: 'NICK', target: false, params: this.session.nick });
}
this.server.nick(this);
return next();
});
}
checkAuth() {
if (!this.session.auth) {
this.send({ verb: 'ERR_NOTREGISTERED', params: 'PRIVMSG', message: 'Authentication required to chat in this server' });
@ -475,18 +588,28 @@ class IRCConnection extends EventEmitter {
}
command_NICK(params, next) {
let currentSource = this.getFormattedName();
if (params.length > 1) {
this.send({ verb: 'ERR_ERRONEUSNICKNAME', params, message: 'Erroneous Nickname' });
return next();
} else if (!params.length) {
this.send({ verb: 'ERR_NEEDMOREPARAMS', params, message: 'Not enough parameters' });
return next();
} else if (this.server.disabledNicks.includes(params[0].trim().toLowerCase())) {
this.send({ verb: 'ERR_ERRONEUSNICKNAME', params, message: 'Erroneous Nickname' });
return next();
} else {
this.session.nick = params[0];
}
this.checkSessionStart();
this.server.nick(this);
return next();
if (this.session.auth) {
this.verifyNickChange(currentSource, next);
} else {
next();
}
}
command_PASS(params, next) {
@ -526,6 +649,7 @@ class IRCConnection extends EventEmitter {
if (auth) {
this.session.auth = auth;
this.checkSessionStart();
return this.verifyNickChange(false, next);
}
return next();
});
@ -731,6 +855,7 @@ class IRCConnection extends EventEmitter {
target: this.session.nick,
message: 'You are now identified for ' + this.session.user
});
return this.verifyNickChange(false, next);
} else {
this.send({
source: ':NickServ!NickServ@services.',
@ -806,6 +931,7 @@ class IRCConnection extends EventEmitter {
message: 'You are now logged in as ' + this.session.user
});
this.send({ verb: 'RPL_SASLSUCCESS', target: this.session.nick || '*', message: 'SASL authentication successful' });
return this.verifyNickChange(false, next);
} else {
this.send({ verb: 'ERR_SASLFAIL', target: this.session.nick || '*', message: 'SASL authentication failed' });
}
@ -816,6 +942,12 @@ class IRCConnection extends EventEmitter {
return next();
}
command_NN(params, next) {
this.session.nick = params[0];
this.server.nick(this);
next();
}
}
module.exports = IRCConnection;

View file

@ -25,14 +25,14 @@
"dependencies": {
"addressparser": "1.0.1",
"bcryptjs": "2.4.3",
"bugsnag": "1.12.1",
"bugsnag": "1.12.2",
"generate-password": "1.3.0",
"he": "1.1.1",
"html-to-text": "3.3.0",
"humanname": "0.2.2",
"humanparser": "1.5.0",
"iconv-lite": "0.4.19",
"joi": "10.6.0",
"joi": "11.0.1",
"js-yaml": "3.10.0",
"libbase64": "0.2.0",
"libmime": "3.1.0",
@ -49,14 +49,14 @@
"qrcode": "0.9.0",
"redfour": "1.0.2",
"redis": "2.8.0",
"restify": "5.2.0",
"restify": "6.0.0",
"seq-index": "1.1.0",
"smtp-server": "3.1.0",
"speakeasy": "2.0.0",
"tlds": "1.196.0",
"utf7": "1.0.2",
"uuid": "3.1.0",
"wild-config": "1.3.2"
"wild-config": "1.3.5"
},
"repository": {
"type": "git",