Skip to content

Commit

Permalink
Transform nicknames to avoid issues with @username markdown syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
rlidwka committed Sep 27, 2019
1 parent ed957e2 commit 2174b58
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 6 deletions.
44 changes: 38 additions & 6 deletions cli/_lib/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,22 @@

'use strict';

const Promise = require('bluebird');
const mongoose = require('mongoose');
const html_unescape = require('nodeca.vbconvert/lib/html_unescape_entities');
const progress = require('./utils').progress;
const Promise = require('bluebird');
const mongoose = require('mongoose');
const html_unescape = require('nodeca.vbconvert/lib/html_unescape_entities');
const nick_transform = require('nodeca.vbconvert/lib/nick_transform');
const progress = require('./utils').progress;

const UNCONFIRMED = 3;
const MEMBERS = 11;
const VIOLATORS = 12;


module.exports = async function (N) {
let bot = await N.models.users.User.findOne()
.where('hid').equals(N.config.bots.default_bot_hid)
.lean(true);

let usergroups = await N.models.vbconvert.UserGroupMapping.find().lean(true);

let mongoid = {};
Expand All @@ -24,6 +29,24 @@ module.exports = async function (N) {

let conn = await N.vbconvert.getConnection();

let rows = (await conn.query('SELECT userid, username FROM user ORDER BY userid ASC'))[0];
let username_mapping = {};
let nicks_seen = new Set(rows.map(row => nick_transform.normalize(row.username)));

for (let { userid, username } of rows) {
let nick = html_unescape(username);

if (!nick_transform.valid(nick)) {
username_mapping[userid] = nick_transform(nick, nicks_seen, nick_transform.rules);
}
}

N.logger.info('Username mapping created ' +
`(changing ${Object.keys(username_mapping).length} out of ${rows.length} nicknames)`);

// remove old records of name change in case import is restarted
await N.models.users.UserNickChange.deleteMany({});

let gi_rows = (await conn.query('SELECT value FROM setting WHERE varname = "globalignore" LIMIT 1'))[0];

let hellbanned_ids = [];
Expand All @@ -32,7 +55,7 @@ module.exports = async function (N) {
hellbanned_ids = gi_rows[0].value.split(' ').map(Number);
}

let rows = (await conn.query(`
rows = (await conn.query(`
SELECT userid,usergroupid,membergroupids,username,email,password,salt,
passworddate,ipaddress,joindate,lastactivity,icq,skype,
CAST(birthday_search as char) as birthday,
Expand All @@ -58,7 +81,7 @@ module.exports = async function (N) {
}

user.hid = row.userid;
user.nick = html_unescape(row.username);
user.nick = username_mapping[row.userid] || html_unescape(row.username);
user.email = row.email;
user.joined_ts = new Date(row.joindate * 1000);
user.joined_ip = row.ipaddress;
Expand Down Expand Up @@ -124,6 +147,15 @@ module.exports = async function (N) {

await user.save();

if (username_mapping[row.userid]) {
await new N.models.users.UserNickChange({
from: bot._id,
user: user._id,
old_nick: html_unescape(row.username),
new_nick: username_mapping[row.userid]
}).save();
}

let authProvider = new N.models.users.AuthProvider();

authProvider.user = user._id;
Expand Down
91 changes: 91 additions & 0 deletions lib/nick_transform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
'use strict';

const regexp = /(?=.{2,})^=?[\p{L}\d]+(?:[-_=][\p{L}\d]+)*[#=]*$/u;

let rules = [];

rules.push([ n => n.replace(/\$+/, m => 'S'.repeat(m.length)), 10 ]);
rules.push([ n => n.replace(/^Ⓔⓤⓖⓔⓔ$/, 'Eugee'), 10 ]);
rules.push([ n => n.replace(/\][I|]\[|\}[I|]\{|\)[I|]\(/ug, 'Ж'), 10 ]);
rules.push([ n => n.replace(/\]\[|\}\{/ug, 'X'), 10 ]);
rules.push([ n => n.replace(/\(\)/ug, 'O'), 10 ]);
rules.push([ n => n.replace(/\|\{/ug, 'K'), 11 ]);
rules.push([ n => n.replace(/@/g, () => (n.indexOf('.') === -1 ? 'A' : '@')), 10 ]);
rules.push([ n => n.replace(/@[a-z0-9]+\.[a-z]*$/i, ''), 10 ]);
rules.push([ n => n.replace(/^&&&$/, 'AAA'), 10 ]);
rules.push([ n => n.replace(/^\^\^\^$/, 'aaa'), 10 ]);

rules.push([ n => n.replace(/^[^-_=\p{L}\d]+/ug, ''), 100 ]);
rules.push([ n => n.replace(/[^-_=\p{L}\d]+$/ug, ''), 1000 ]);

rules.push([ n => n.replace(/[^\$@\-_=\p{L}\d]/ug, '_'), 10000 ]);
rules.push([ n => n.replace(/[^\$@\-_=\p{L}\d]/ug, '-'), 11000 ]);
rules.push([ n => n.replace(/(\p{L}\d)[^\$@\-_=\p{L}\d](\p{L}\d)/ug, '$1=$2'), 12000 ]);

rules.push([ n => n.replace(/^[-_]+|[-_]+$/ug, ''), 100 ]);
rules.push([ n => n.replace(/[-_=]{2,}/ug, '_'), 1000 ]);
rules.push([ n => n.replace(/[-_=]{2,}/ug, '-'), 1100 ]);
rules.push([ n => n.replace(/[-_=]{2,}/ug, '='), 20000 ]);

rules.push([ n => n.replace(/$/, '='), 100000 ]);
rules.push([ n => n.replace(/$/, '#'), 110000 ]);
rules.push([ n => n.replace(/^(.*)$/, '=$1#'), 150000 ]);
rules.push([ n => n.replace(/^(.*)$/, '=$1='), 160000 ]);

rules = rules.sort((a, b) => a[1] - b[1]);

function valid(nick) { return nick.match(regexp); }
function normalize(nick) { return nick.toUpperCase().toLowerCase(); }

function transform_nick(nick, nicks_seen, rules/*, debug = null*/) {
let visited = new Set();

let weights = new Map();
weights.set(nick, 0);

/*let paths;
if (debug) {
paths = new Map();
paths.set(nick, []);
}*/

for (;;) {
let min_entry = [ '', Infinity ];

for (let entry of weights.entries()) {
if (entry[1] >= min_entry[1]) continue;
if (visited.has(entry[0])) continue;
min_entry = entry;
}

let [ current_nick, current_weight ] = min_entry;
let nick_norm = normalize(current_nick);

if (valid(current_nick) && !nicks_seen.has(nick_norm)) {
nicks_seen.add(nick_norm);
//if (debug) return [ current_nick, current_weight, paths.get(current_nick) ];
return current_nick;
}

for (let i = 0; i < rules.length; i++) {
let [ fn, weight ] = rules[i];
let new_nick = fn(current_nick);
let new_weight = current_weight + weight;
let existing_weight = weights.get(new_nick);

if (typeof existing_weight === 'undefined' || new_weight < existing_weight) {
weights.set(new_nick, new_weight);
//if (debug) paths.set(new_nick, paths.get(current_nick).concat([ i ]));
}
}

visited.add(current_nick);
}
}

module.exports = transform_nick;

module.exports.valid = valid;
module.exports.normalize = normalize;
module.exports.rules = rules;

0 comments on commit 2174b58

Please sign in to comment.