mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-09 23:45:45 +01:00
feat: remote user deletion logic, #12611
This commit is contained in:
@@ -510,7 +510,7 @@ define('admin/manage/users', [
|
||||
if (confirm) {
|
||||
Promise.all(
|
||||
uids.map(
|
||||
uid => api.del(`/users/${uid}${path}`, {}).then(() => {
|
||||
uid => api.del(`/users/${encodeURIComponent(uid)}${path}`, {}).then(() => {
|
||||
if (path !== '/content') {
|
||||
removeRow(uid);
|
||||
}
|
||||
|
||||
@@ -71,6 +71,8 @@ Actors.assert = async (ids, options = {}) => {
|
||||
|
||||
// winston.verbose(`[activitypub/actors] Asserting ${ids.length} actor(s)`);
|
||||
|
||||
// NOTE: MAKE SURE EVERY DB ADDITION HAS A CORRESPONDING REMOVAL IN ACTORS.REMOVE!
|
||||
|
||||
const urlMap = new Map();
|
||||
const followersUrlMap = new Map();
|
||||
const pubKeysMap = new Map();
|
||||
@@ -207,3 +209,29 @@ Actors.getLocalFollowersCount = async (id) => {
|
||||
|
||||
return await db.sortedSetCard(`followersRemote:${id}`);
|
||||
};
|
||||
|
||||
Actors.remove = async (id) => {
|
||||
const exists = await db.isSortedSetMember('usersRemote:lastCrawled', id);
|
||||
if (!exists) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let { username, fullname, url, followersUrl } = await user.getUserFields(id, ['username', 'fullname', 'url', 'followersUrl']);
|
||||
username = username.toLowerCase();
|
||||
|
||||
await Promise.all([
|
||||
db.sortedSetRemoveBulk([
|
||||
['ap.preferredUsername:sorted', `${username}:${id}`],
|
||||
['ap.name:sorted', `${fullname.toLowerCase()}:${id}`],
|
||||
]),
|
||||
db.deleteObjectField('handle:uid', username),
|
||||
db.deleteObjectField('followersUrl:uid', followersUrl),
|
||||
db.deleteObjectField('remoteUrl:uid', url),
|
||||
db.delete(`userRemote:${id}:keys`),
|
||||
]);
|
||||
|
||||
await Promise.all([
|
||||
db.delete(`userRemote:${id}`),
|
||||
db.sortedSetRemove('usersRemote:lastCrawled', id),
|
||||
]);
|
||||
};
|
||||
|
||||
@@ -515,7 +515,7 @@ async function isPrivilegedOrSelfAndPasswordMatch(caller, data) {
|
||||
|
||||
async function processDeletion({ uid, method, password, caller }) {
|
||||
const isTargetAdmin = await user.isAdministrator(uid);
|
||||
const isSelf = parseInt(uid, 10) === parseInt(caller.uid, 10);
|
||||
const isSelf = String(uid) === String(caller.uid);
|
||||
const hasAdminPrivilege = await privileges.admin.can('admin:users', caller.uid);
|
||||
|
||||
if (isSelf && meta.config.allowAccountDelete !== 1) {
|
||||
|
||||
@@ -29,8 +29,8 @@ Assert.user = helpers.try(async (req, res, next) => {
|
||||
const uid = req.params.uid || res.locals.uid;
|
||||
|
||||
if (
|
||||
(utils.isNumber(uid) && await user.exists(uid)) ||
|
||||
(uid.indexOf('@') !== -1 && await activitypub.helpers.query(uid))
|
||||
((utils.isNumber(uid) || activitypub.helpers.isUri(uid)) && await user.exists(uid)) ||
|
||||
(uid.indexOf('@') !== -1 && await user.existsBySlug(uid))
|
||||
) {
|
||||
return next();
|
||||
}
|
||||
|
||||
@@ -13,7 +13,9 @@ const topics = require('../topics');
|
||||
const groups = require('../groups');
|
||||
const messaging = require('../messaging');
|
||||
const plugins = require('../plugins');
|
||||
const activitypub = require('../activitypub');
|
||||
const batch = require('../batch');
|
||||
const utils = require('../utils');
|
||||
|
||||
module.exports = function (User) {
|
||||
const deletesInProgress = {};
|
||||
@@ -24,7 +26,7 @@ module.exports = function (User) {
|
||||
};
|
||||
|
||||
User.deleteContent = async function (callerUid, uid) {
|
||||
if (parseInt(uid, 10) <= 0) {
|
||||
if (utils.isNumber(uid) && parseInt(uid, 10) <= 0) {
|
||||
throw new Error('[[error:invalid-uid]]');
|
||||
}
|
||||
if (deletesInProgress[uid]) {
|
||||
@@ -61,7 +63,7 @@ module.exports = function (User) {
|
||||
let deleteIds = [];
|
||||
await batch.processSortedSet('post:queue', async (ids) => {
|
||||
const data = await db.getObjects(ids.map(id => `post:queue:${id}`));
|
||||
const userQueuedIds = data.filter(d => parseInt(d.uid, 10) === parseInt(uid, 10)).map(d => d.id);
|
||||
const userQueuedIds = data.filter(d => String(d.uid) === String(uid)).map(d => d.id);
|
||||
deleteIds = deleteIds.concat(userQueuedIds);
|
||||
}, { batch: 500 });
|
||||
await async.eachSeries(deleteIds, posts.removeFromQueue);
|
||||
@@ -90,7 +92,7 @@ module.exports = function (User) {
|
||||
deletesInProgress[uid] = 'user.deleteAccount';
|
||||
|
||||
await removeFromSortedSets(uid);
|
||||
const userData = await db.getObject(`user:${uid}`);
|
||||
const userData = await db.getObject(utils.isNumber(uid) ? `user:${uid}` : `userRemote:${uid}`);
|
||||
|
||||
if (!userData || !userData.username) {
|
||||
delete deletesInProgress[uid];
|
||||
@@ -153,6 +155,7 @@ module.exports = function (User) {
|
||||
flags.resolveFlag('user', uid, uid),
|
||||
User.reset.cleanByUid(uid),
|
||||
User.email.expireValidation(uid),
|
||||
activitypub.actors.remove(uid),
|
||||
]);
|
||||
await db.deleteAll([
|
||||
`followers:${uid}`, `following:${uid}`, `user:${uid}`,
|
||||
|
||||
Reference in New Issue
Block a user