2017-02-18 01:56:23 -07:00
|
|
|
'use strict';
|
2014-04-15 02:25:42 -04:00
|
|
|
|
2019-09-07 18:22:03 -04:00
|
|
|
const async = require('async');
|
|
|
|
|
const winston = require('winston');
|
2016-09-27 13:31:50 +03:00
|
|
|
|
2019-09-07 18:22:03 -04:00
|
|
|
const db = require('../../database');
|
|
|
|
|
const groups = require('../../groups');
|
|
|
|
|
const user = require('../../user');
|
|
|
|
|
const events = require('../../events');
|
|
|
|
|
const meta = require('../../meta');
|
|
|
|
|
const plugins = require('../../plugins');
|
2019-12-04 11:14:01 -05:00
|
|
|
const translator = require('../../translator');
|
2014-04-15 02:25:42 -04:00
|
|
|
|
2019-09-07 18:22:03 -04:00
|
|
|
const User = module.exports;
|
2014-04-15 02:25:42 -04:00
|
|
|
|
2019-09-07 18:22:03 -04:00
|
|
|
User.makeAdmins = async function (socket, uids) {
|
2017-02-18 01:52:56 -07:00
|
|
|
if (!Array.isArray(uids)) {
|
2019-09-07 18:22:03 -04:00
|
|
|
throw new Error('[[error:invalid-data]]');
|
|
|
|
|
}
|
|
|
|
|
const userData = await user.getUsersFields(uids, ['banned']);
|
|
|
|
|
userData.forEach((userData) => {
|
|
|
|
|
if (userData && userData.banned) {
|
|
|
|
|
throw new Error('[[error:cant-make-banned-users-admin]]');
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
for (const uid of uids) {
|
|
|
|
|
/* eslint-disable no-await-in-loop */
|
|
|
|
|
await groups.join('administrators', uid);
|
|
|
|
|
await events.log({
|
|
|
|
|
type: 'user-makeAdmin',
|
|
|
|
|
uid: socket.uid,
|
|
|
|
|
targetUid: uid,
|
|
|
|
|
ip: socket.ip,
|
|
|
|
|
});
|
2014-06-13 22:48:24 -04:00
|
|
|
}
|
2014-04-15 02:25:42 -04:00
|
|
|
};
|
|
|
|
|
|
2019-09-07 18:22:03 -04:00
|
|
|
User.removeAdmins = async function (socket, uids) {
|
2017-02-18 01:52:56 -07:00
|
|
|
if (!Array.isArray(uids)) {
|
2019-09-07 18:22:03 -04:00
|
|
|
throw new Error('[[error:invalid-data]]');
|
|
|
|
|
}
|
|
|
|
|
for (const uid of uids) {
|
|
|
|
|
/* eslint-disable no-await-in-loop */
|
|
|
|
|
const count = await groups.getMemberCount('administrators');
|
|
|
|
|
if (count === 1) {
|
|
|
|
|
throw new Error('[[error:cant-remove-last-admin]]');
|
|
|
|
|
}
|
|
|
|
|
await groups.leave('administrators', uid);
|
|
|
|
|
await events.log({
|
|
|
|
|
type: 'user-removeAdmin',
|
|
|
|
|
uid: socket.uid,
|
|
|
|
|
targetUid: uid,
|
|
|
|
|
ip: socket.ip,
|
|
|
|
|
});
|
2014-05-05 16:48:09 -04:00
|
|
|
}
|
2014-06-13 22:48:24 -04:00
|
|
|
};
|
2014-05-05 16:48:09 -04:00
|
|
|
|
2019-09-07 18:22:03 -04:00
|
|
|
User.createUser = async function (socket, userData) {
|
2014-04-15 02:25:42 -04:00
|
|
|
if (!userData) {
|
2019-09-07 18:22:03 -04:00
|
|
|
throw new Error('[[error:invalid-data]]');
|
2014-04-15 02:25:42 -04:00
|
|
|
}
|
2019-09-07 18:22:03 -04:00
|
|
|
return await user.create(userData);
|
2014-04-15 02:25:42 -04:00
|
|
|
};
|
|
|
|
|
|
2019-09-07 18:22:03 -04:00
|
|
|
User.resetLockouts = async function (socket, uids) {
|
2014-08-14 08:34:38 -04:00
|
|
|
if (!Array.isArray(uids)) {
|
2019-09-07 18:22:03 -04:00
|
|
|
throw new Error('[[error:invalid-data]]');
|
2014-08-14 08:34:38 -04:00
|
|
|
}
|
2019-09-07 18:22:03 -04:00
|
|
|
await Promise.all(uids.map(uid => user.auth.resetLockout(uid)));
|
2014-08-14 08:34:38 -04:00
|
|
|
};
|
|
|
|
|
|
2019-09-07 18:22:03 -04:00
|
|
|
User.validateEmail = async function (socket, uids) {
|
2014-10-06 13:11:12 -04:00
|
|
|
if (!Array.isArray(uids)) {
|
2019-09-07 18:22:03 -04:00
|
|
|
throw new Error('[[error:invalid-data]]');
|
2014-10-06 13:11:12 -04:00
|
|
|
}
|
|
|
|
|
|
2018-11-05 08:20:43 -05:00
|
|
|
uids = uids.filter(uid => parseInt(uid, 10));
|
2019-09-07 18:22:03 -04:00
|
|
|
await db.setObjectField(uids.map(uid => 'user:' + uid), 'email:confirmed', 1);
|
|
|
|
|
await db.sortedSetRemove('users:notvalidated', uids);
|
2014-11-03 15:31:41 -05:00
|
|
|
};
|
|
|
|
|
|
2019-09-07 18:22:03 -04:00
|
|
|
User.sendValidationEmail = async function (socket, uids) {
|
2015-02-11 14:44:56 -05:00
|
|
|
if (!Array.isArray(uids)) {
|
2019-09-07 18:22:03 -04:00
|
|
|
throw new Error('[[error:invalid-data]]');
|
2015-02-11 14:44:56 -05:00
|
|
|
}
|
2015-04-13 17:29:43 -04:00
|
|
|
|
2018-10-21 16:47:51 -04:00
|
|
|
if (!meta.config.requireEmailConfirmation) {
|
2019-09-07 18:22:03 -04:00
|
|
|
throw new Error('[[error:email-confirmations-are-disabled]]');
|
2015-02-11 14:44:56 -05:00
|
|
|
}
|
|
|
|
|
|
2019-09-07 18:22:03 -04:00
|
|
|
await async.eachLimit(uids, 50, async function (uid) {
|
|
|
|
|
await user.email.sendValidationEmail(uid);
|
|
|
|
|
});
|
2015-02-11 14:44:56 -05:00
|
|
|
};
|
|
|
|
|
|
2019-09-07 18:22:03 -04:00
|
|
|
User.sendPasswordResetEmail = async function (socket, uids) {
|
2014-11-03 15:31:41 -05:00
|
|
|
if (!Array.isArray(uids)) {
|
2019-09-07 18:22:03 -04:00
|
|
|
throw new Error('[[error:invalid-data]]');
|
2014-11-03 15:31:41 -05:00
|
|
|
}
|
|
|
|
|
|
2018-11-05 08:20:43 -05:00
|
|
|
uids = uids.filter(uid => parseInt(uid, 10));
|
2014-11-03 15:31:41 -05:00
|
|
|
|
2019-09-07 18:22:03 -04:00
|
|
|
await Promise.all(uids.map(async function (uid) {
|
|
|
|
|
const userData = await user.getUserFields(uid, ['email', 'username']);
|
|
|
|
|
if (!userData.email) {
|
|
|
|
|
throw new Error('[[error:user-doesnt-have-email, ' + userData.username + ']]');
|
|
|
|
|
}
|
|
|
|
|
await user.reset.send(userData.email);
|
|
|
|
|
}));
|
2014-10-06 13:11:12 -04:00
|
|
|
};
|
|
|
|
|
|
2019-09-07 18:22:03 -04:00
|
|
|
User.forcePasswordReset = async function (socket, uids) {
|
2019-03-20 16:34:22 -04:00
|
|
|
if (!Array.isArray(uids)) {
|
2019-09-07 18:22:03 -04:00
|
|
|
throw new Error('[[error:invalid-data]]');
|
2019-03-20 16:34:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uids = uids.filter(uid => parseInt(uid, 10));
|
|
|
|
|
|
2019-09-07 18:22:03 -04:00
|
|
|
await db.setObjectField(uids.map(uid => 'user:' + uid), 'passwordExpiry', Date.now());
|
|
|
|
|
await user.auth.revokeAllSessions(uids);
|
2019-03-20 16:34:22 -04:00
|
|
|
};
|
|
|
|
|
|
2019-09-07 18:22:03 -04:00
|
|
|
User.deleteUsers = async function (socket, uids) {
|
|
|
|
|
deleteUsers(socket, uids, async function (uid) {
|
|
|
|
|
await user.deleteAccount(uid);
|
|
|
|
|
});
|
2016-08-12 01:55:38 +03:00
|
|
|
};
|
|
|
|
|
|
2019-09-07 18:22:03 -04:00
|
|
|
User.deleteUsersAndContent = async function (socket, uids) {
|
|
|
|
|
deleteUsers(socket, uids, async function (uid) {
|
|
|
|
|
await user.delete(socket.uid, uid);
|
|
|
|
|
});
|
2016-08-12 01:55:38 +03:00
|
|
|
};
|
|
|
|
|
|
2019-09-07 18:22:03 -04:00
|
|
|
async function deleteUsers(socket, uids, method) {
|
2016-08-12 01:55:38 +03:00
|
|
|
if (!Array.isArray(uids)) {
|
2019-09-07 18:22:03 -04:00
|
|
|
throw new Error('[[error:invalid-data]]');
|
2014-05-05 16:48:09 -04:00
|
|
|
}
|
2019-09-07 18:22:03 -04:00
|
|
|
const isMembers = await groups.isMembers(uids, 'administrators');
|
|
|
|
|
if (isMembers.includes(true)) {
|
|
|
|
|
throw new Error('[[error:cant-delete-other-admins]]');
|
|
|
|
|
}
|
|
|
|
|
async function doDelete(uid) {
|
|
|
|
|
const userData = await method(uid);
|
|
|
|
|
await events.log({
|
|
|
|
|
type: 'user-delete',
|
|
|
|
|
uid: socket.uid,
|
|
|
|
|
targetUid: uid,
|
|
|
|
|
ip: socket.ip,
|
|
|
|
|
username: userData.username,
|
|
|
|
|
email: userData.email,
|
|
|
|
|
});
|
|
|
|
|
plugins.fireHook('action:user.delete', {
|
|
|
|
|
callerUid: socket.uid,
|
|
|
|
|
uid: uid,
|
|
|
|
|
ip: socket.ip,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
await Promise.all(uids.map(uid => doDelete(uid)));
|
|
|
|
|
} catch (err) {
|
|
|
|
|
winston.error(err);
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-09-16 12:19:58 -04:00
|
|
|
|
2019-09-07 18:22:03 -04:00
|
|
|
User.search = async function (socket, data) {
|
|
|
|
|
const searchData = await user.search({
|
|
|
|
|
query: data.query,
|
|
|
|
|
searchBy: data.searchBy,
|
|
|
|
|
uid: socket.uid,
|
2018-10-03 19:12:46 -04:00
|
|
|
});
|
2014-04-15 02:25:42 -04:00
|
|
|
|
2019-09-07 18:22:03 -04:00
|
|
|
if (!searchData.users.length) {
|
|
|
|
|
return searchData;
|
|
|
|
|
}
|
2014-12-21 16:29:32 -05:00
|
|
|
|
2019-09-07 18:22:03 -04:00
|
|
|
const uids = searchData.users.map(user => user && user.uid);
|
|
|
|
|
const userInfo = await user.getUsersFields(uids, ['email', 'flags', 'lastonline', 'joindate']);
|
2016-11-15 14:01:06 +03:00
|
|
|
|
2019-09-07 18:22:03 -04:00
|
|
|
searchData.users.forEach(function (user, index) {
|
|
|
|
|
if (user && userInfo[index]) {
|
|
|
|
|
user.email = userInfo[index].email;
|
|
|
|
|
user.flags = userInfo[index].flags || 0;
|
|
|
|
|
user.lastonlineISO = userInfo[index].lastonlineISO;
|
|
|
|
|
user.joindateISO = userInfo[index].joindateISO;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return searchData;
|
2014-04-15 02:25:42 -04:00
|
|
|
};
|
|
|
|
|
|
2019-09-07 18:22:03 -04:00
|
|
|
User.restartJobs = async function () {
|
2019-07-16 11:42:24 -04:00
|
|
|
user.startJobs();
|
2016-08-26 10:04:38 -04:00
|
|
|
};
|
2019-12-04 11:14:01 -05:00
|
|
|
|
|
|
|
|
User.loadGroups = async function (socket, uids) {
|
|
|
|
|
const [userData, groupData] = await Promise.all([
|
|
|
|
|
user.getUsersData(uids),
|
|
|
|
|
groups.getUserGroupsFromSet('groups:createtime', uids),
|
|
|
|
|
]);
|
|
|
|
|
userData.forEach((data, index) => {
|
|
|
|
|
data.groups = groupData[index].filter(group => !groups.isPrivilegeGroup(group.name));
|
|
|
|
|
data.groups.forEach((group) => {
|
|
|
|
|
group.nameEscaped = translator.escape(group.displayName);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
return { users: userData };
|
|
|
|
|
};
|