mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-10 07:55:46 +01:00
feat: remote user deletion logic, #12611
This commit is contained in:
@@ -510,7 +510,7 @@ define('admin/manage/users', [
|
|||||||
if (confirm) {
|
if (confirm) {
|
||||||
Promise.all(
|
Promise.all(
|
||||||
uids.map(
|
uids.map(
|
||||||
uid => api.del(`/users/${uid}${path}`, {}).then(() => {
|
uid => api.del(`/users/${encodeURIComponent(uid)}${path}`, {}).then(() => {
|
||||||
if (path !== '/content') {
|
if (path !== '/content') {
|
||||||
removeRow(uid);
|
removeRow(uid);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ Actors.assert = async (ids, options = {}) => {
|
|||||||
|
|
||||||
// winston.verbose(`[activitypub/actors] Asserting ${ids.length} actor(s)`);
|
// 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 urlMap = new Map();
|
||||||
const followersUrlMap = new Map();
|
const followersUrlMap = new Map();
|
||||||
const pubKeysMap = new Map();
|
const pubKeysMap = new Map();
|
||||||
@@ -207,3 +209,29 @@ Actors.getLocalFollowersCount = async (id) => {
|
|||||||
|
|
||||||
return await db.sortedSetCard(`followersRemote:${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 }) {
|
async function processDeletion({ uid, method, password, caller }) {
|
||||||
const isTargetAdmin = await user.isAdministrator(uid);
|
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);
|
const hasAdminPrivilege = await privileges.admin.can('admin:users', caller.uid);
|
||||||
|
|
||||||
if (isSelf && meta.config.allowAccountDelete !== 1) {
|
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;
|
const uid = req.params.uid || res.locals.uid;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(utils.isNumber(uid) && await user.exists(uid)) ||
|
((utils.isNumber(uid) || activitypub.helpers.isUri(uid)) && await user.exists(uid)) ||
|
||||||
(uid.indexOf('@') !== -1 && await activitypub.helpers.query(uid))
|
(uid.indexOf('@') !== -1 && await user.existsBySlug(uid))
|
||||||
) {
|
) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ const topics = require('../topics');
|
|||||||
const groups = require('../groups');
|
const groups = require('../groups');
|
||||||
const messaging = require('../messaging');
|
const messaging = require('../messaging');
|
||||||
const plugins = require('../plugins');
|
const plugins = require('../plugins');
|
||||||
|
const activitypub = require('../activitypub');
|
||||||
const batch = require('../batch');
|
const batch = require('../batch');
|
||||||
|
const utils = require('../utils');
|
||||||
|
|
||||||
module.exports = function (User) {
|
module.exports = function (User) {
|
||||||
const deletesInProgress = {};
|
const deletesInProgress = {};
|
||||||
@@ -24,7 +26,7 @@ module.exports = function (User) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
User.deleteContent = async function (callerUid, uid) {
|
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]]');
|
throw new Error('[[error:invalid-uid]]');
|
||||||
}
|
}
|
||||||
if (deletesInProgress[uid]) {
|
if (deletesInProgress[uid]) {
|
||||||
@@ -61,7 +63,7 @@ module.exports = function (User) {
|
|||||||
let deleteIds = [];
|
let deleteIds = [];
|
||||||
await batch.processSortedSet('post:queue', async (ids) => {
|
await batch.processSortedSet('post:queue', async (ids) => {
|
||||||
const data = await db.getObjects(ids.map(id => `post:queue:${id}`));
|
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);
|
deleteIds = deleteIds.concat(userQueuedIds);
|
||||||
}, { batch: 500 });
|
}, { batch: 500 });
|
||||||
await async.eachSeries(deleteIds, posts.removeFromQueue);
|
await async.eachSeries(deleteIds, posts.removeFromQueue);
|
||||||
@@ -90,7 +92,7 @@ module.exports = function (User) {
|
|||||||
deletesInProgress[uid] = 'user.deleteAccount';
|
deletesInProgress[uid] = 'user.deleteAccount';
|
||||||
|
|
||||||
await removeFromSortedSets(uid);
|
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) {
|
if (!userData || !userData.username) {
|
||||||
delete deletesInProgress[uid];
|
delete deletesInProgress[uid];
|
||||||
@@ -153,6 +155,7 @@ module.exports = function (User) {
|
|||||||
flags.resolveFlag('user', uid, uid),
|
flags.resolveFlag('user', uid, uid),
|
||||||
User.reset.cleanByUid(uid),
|
User.reset.cleanByUid(uid),
|
||||||
User.email.expireValidation(uid),
|
User.email.expireValidation(uid),
|
||||||
|
activitypub.actors.remove(uid),
|
||||||
]);
|
]);
|
||||||
await db.deleteAll([
|
await db.deleteAll([
|
||||||
`followers:${uid}`, `following:${uid}`, `user:${uid}`,
|
`followers:${uid}`, `following:${uid}`, `user:${uid}`,
|
||||||
|
|||||||
Reference in New Issue
Block a user