"use server"; import { writeFile } from "fs/promises"; import { PLATFORM_MOD_ID } from "./constants"; import mongo, { createDM, fetchChannels, fetchMembershipsByUser, fetchMessages, fetchUserById, findDM, updateLastMessageId, } from "./db"; import { publishMessage, sendChatMessage } from "./redis"; import { ulid } from "ulid"; import { AccountInfo, File, Member, Message, SessionInfo, User, } from "revolt-api"; export async function sendAlert(userId: string, content: string) { const messageId = ulid(); let dm = await findDM(PLATFORM_MOD_ID, userId); if (!dm) dm = await createDM(PLATFORM_MOD_ID, userId, messageId); else await updateLastMessageId(dm._id, messageId); await sendChatMessage({ _id: messageId, author: PLATFORM_MOD_ID, channel: dm._id, content, }); } export async function disableAccount(userId: string) { await mongo() .db("revolt") .collection("accounts") .updateOne({ _id: userId }, { $set: { disabled: true } }); await mongo().db("revolt").collection("sessions").deleteMany({ user_id: userId, }); } export async function suspendUser(userId: string) { await disableAccount(userId); await mongo() .db("revolt") .collection("users") .updateOne( { _id: userId, }, { $set: { flags: 1, }, } ); const memberships = await fetchMembershipsByUser(userId); for (const topic of memberships.map((x) => x._id.server)) { await publishMessage(topic, { type: "UserUpdate", id: userId, data: { flags: 1, }, }); } } export async function wipeUser(userId: string, flags = 4) { // retrieve messages, dm channels, relationships, server memberships const backup = { _event: "wipe", user: await fetchUserById(userId), messages: await fetchMessages({ author: userId }, undefined), dms: await fetchChannels({ channel_type: "DirectMessage", recipients: userId, }), memberships: await fetchMembershipsByUser(userId), }; await writeFile( `./exports/${new Date().toISOString()} - ${userId}.json`, JSON.stringify(backup) ); // mark all attachments as deleted + reported const attachmentIds = backup.messages .filter((message) => message.attachments) .map((message) => message.attachments) .flat() .filter((attachment) => attachment) .map((attachment) => attachment!._id); if (backup.user?.avatar) { attachmentIds.push(backup.user.avatar._id); } if (backup.user?.profile?.background) { attachmentIds.push(backup.user.profile.background._id); } if (attachmentIds.length) { await mongo() .db("revolt") .collection("attachments") .updateMany( { _id: { $in: attachmentIds } }, { $set: { reported: true, deleted: true, }, } ); } // delete messages await mongo().db("revolt").collection("messages").deleteMany({ author: userId, }); // delete server memberships await mongo().db("revolt").collection("server_members").deleteMany({ "_id.user": userId, }); // disable account await disableAccount(userId); // clear user profile await mongo() .db("revolt") .collection("users") .updateOne( { _id: userId, }, { $set: { flags, }, $unset: { avatar: 1, profile: 1, status: 1, }, } ); // broadcast wipe event for (const topic of [ ...backup.dms.map((x) => x._id), ...backup.memberships.map((x) => x._id.server), ]) { await publishMessage(topic, { type: "UserPlatformWipe", user_id: userId, flags, }); } } export async function banUser(userId: string) { return await wipeUser(userId, 4); }