forked from administration/panel
parent
77075dad23
commit
bc48204410
|
@ -23,8 +23,10 @@ import { Input } from "../../ui/input";
|
||||||
import {
|
import {
|
||||||
banUser,
|
banUser,
|
||||||
closeReportsByUser,
|
closeReportsByUser,
|
||||||
|
resetBotToken,
|
||||||
sendAlert,
|
sendAlert,
|
||||||
suspendUser,
|
suspendUser,
|
||||||
|
transferBot,
|
||||||
unsuspendUser,
|
unsuspendUser,
|
||||||
updateBotDiscoverability,
|
updateBotDiscoverability,
|
||||||
updateUserBadges,
|
updateUserBadges,
|
||||||
|
@ -37,6 +39,7 @@ import { Card, CardHeader } from "../../ui/card";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { decodeTime } from "ulid";
|
import { decodeTime } from "ulid";
|
||||||
import { Checkbox } from "@/components/ui/checkbox";
|
import { Checkbox } from "@/components/ui/checkbox";
|
||||||
|
import UserSelector from "@/components/ui/user-selector";
|
||||||
|
|
||||||
const badges = [1, 2, 4, 8, 16, 32, 128, 0, 256, 512, 1024];
|
const badges = [1, 2, 4, 8, 16, 32, 128, 0, 256, 512, 1024];
|
||||||
|
|
||||||
|
@ -53,6 +56,8 @@ export function UserActions({ user, bot }: { user: User; bot?: Bot }) {
|
||||||
displayName: false,
|
displayName: false,
|
||||||
status: false,
|
status: false,
|
||||||
});
|
});
|
||||||
|
const [transferTarget, setTransferTarget] = useState<User | null>(null);
|
||||||
|
const [transferResetToken, setTransferResetToken] = useState(true);
|
||||||
|
|
||||||
const userInaccessible = userDraft.flags === 4 || userDraft.flags === 2;
|
const userInaccessible = userDraft.flags === 4 || userDraft.flags === 2;
|
||||||
|
|
||||||
|
@ -416,6 +421,86 @@ export function UserActions({ user, bot }: { user: User; bot?: Bot }) {
|
||||||
</AlertDialogContent>
|
</AlertDialogContent>
|
||||||
</AlertDialog>
|
</AlertDialog>
|
||||||
|
|
||||||
|
<AlertDialog>
|
||||||
|
<AlertDialogTrigger asChild>
|
||||||
|
<Button variant="ghost" disabled={!user.bot?.owner}>Reset bot token</Button>
|
||||||
|
</AlertDialogTrigger>
|
||||||
|
<AlertDialogContent>
|
||||||
|
<AlertDialogHeader>
|
||||||
|
<AlertDialogTitle>Reset token</AlertDialogTitle>
|
||||||
|
<AlertDialogDescription className="flex flex-col gap-2">
|
||||||
|
<span>
|
||||||
|
Re-roll this bot's authentication token. This will not disconnect active connections.
|
||||||
|
</span>
|
||||||
|
</AlertDialogDescription>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
<AlertDialogFooter>
|
||||||
|
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||||
|
<AlertDialogAction
|
||||||
|
onClick={() => resetBotToken(user._id)
|
||||||
|
.then(() => toast({
|
||||||
|
title: "Reset bot token",
|
||||||
|
}))
|
||||||
|
.catch((e) => toast({
|
||||||
|
title: "Failed to reset token",
|
||||||
|
description: String(e),
|
||||||
|
variant: "destructive",
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Reset
|
||||||
|
</AlertDialogAction>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
|
|
||||||
|
<AlertDialog>
|
||||||
|
<AlertDialogTrigger asChild>
|
||||||
|
<Button variant="ghost" disabled={!user.bot?.owner}>Transfer bot</Button>
|
||||||
|
</AlertDialogTrigger>
|
||||||
|
<AlertDialogContent>
|
||||||
|
<AlertDialogHeader>
|
||||||
|
<AlertDialogTitle>Transfer bot</AlertDialogTitle>
|
||||||
|
<AlertDialogDescription className="flex flex-col gap-2">
|
||||||
|
<span>
|
||||||
|
Transfer this bot to a new owner.
|
||||||
|
</span>
|
||||||
|
<UserSelector
|
||||||
|
onChange={setTransferTarget}
|
||||||
|
/>
|
||||||
|
<Checkbox
|
||||||
|
checked={transferResetToken}
|
||||||
|
onChange={(e) => setTransferResetToken(!!e)}
|
||||||
|
>
|
||||||
|
Also reset token
|
||||||
|
</Checkbox>
|
||||||
|
</AlertDialogDescription>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
<AlertDialogFooter>
|
||||||
|
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||||
|
<AlertDialogAction
|
||||||
|
disabled={!transferTarget}
|
||||||
|
onClick={() => transferBot(user._id, transferTarget!._id, transferResetToken)
|
||||||
|
.then(() => toast({
|
||||||
|
title: "Reset bot token",
|
||||||
|
}))
|
||||||
|
.catch((e) => toast({
|
||||||
|
title: "Failed to reset token",
|
||||||
|
description: String(e),
|
||||||
|
variant: "destructive",
|
||||||
|
}))
|
||||||
|
.finally(() => {
|
||||||
|
setTransferResetToken(true);
|
||||||
|
setTransferTarget(null);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Transfer
|
||||||
|
</AlertDialogAction>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
|
|
||||||
<AlertDialog>
|
<AlertDialog>
|
||||||
<AlertDialogTrigger asChild>
|
<AlertDialogTrigger asChild>
|
||||||
<Button variant="ghost">Close Open Reports</Button>
|
<Button variant="ghost">Close Open Reports</Button>
|
||||||
|
|
|
@ -24,7 +24,7 @@ type Permission =
|
||||||
| `bots${
|
| `bots${
|
||||||
| ""
|
| ""
|
||||||
| `/fetch${"" | "/by-id" | "/by-user"}`
|
| `/fetch${"" | "/by-id" | "/by-user"}`
|
||||||
| `/update${"" | "/discoverability"}`}`
|
| `/update${"" | "/discoverability" | "/owner" | "/reset-token"}`}`
|
||||||
| `channels${
|
| `channels${
|
||||||
| ""
|
| ""
|
||||||
| `/fetch${"" | "/by-id" | "/by-server" | "/dm" | "/invites"}`
|
| `/fetch${"" | "/by-id" | "/by-server" | "/dm" | "/invites"}`
|
||||||
|
@ -139,7 +139,10 @@ const PermissionSets = {
|
||||||
"users/update/badges",
|
"users/update/badges",
|
||||||
|
|
||||||
"servers/update/owner",
|
"servers/update/owner",
|
||||||
"servers/update/add-member",
|
|
||||||
|
"bots/fetch/by-user",
|
||||||
|
"bots/update/reset-token",
|
||||||
|
"bots/update/owner",
|
||||||
|
|
||||||
"accounts/fetch/by-id",
|
"accounts/fetch/by-id",
|
||||||
"accounts/fetch/by-email",
|
"accounts/fetch/by-email",
|
||||||
|
@ -164,6 +167,9 @@ const PermissionSets = {
|
||||||
"users/fetch/notices",
|
"users/fetch/notices",
|
||||||
|
|
||||||
"bots/fetch/by-user",
|
"bots/fetch/by-user",
|
||||||
|
"bots/update/reset-token",
|
||||||
|
"bots/update/owner",
|
||||||
|
|
||||||
// "messages/fetch/by-user",
|
// "messages/fetch/by-user",
|
||||||
// "users/fetch/memberships",
|
// "users/fetch/memberships",
|
||||||
"servers/fetch",
|
"servers/fetch",
|
||||||
|
@ -175,6 +181,8 @@ const PermissionSets = {
|
||||||
"channels/create/dm",
|
"channels/create/dm",
|
||||||
|
|
||||||
"servers/update/quarantine",
|
"servers/update/quarantine",
|
||||||
|
"servers/update/owner",
|
||||||
|
"servers/update/add-member",
|
||||||
"backup/fetch",
|
"backup/fetch",
|
||||||
|
|
||||||
"reports/fetch/related/by-user",
|
"reports/fetch/related/by-user",
|
||||||
|
|
|
@ -28,6 +28,7 @@ import {
|
||||||
} from "revolt-api";
|
} from "revolt-api";
|
||||||
import { checkPermission } from "./accessPermissions";
|
import { checkPermission } from "./accessPermissions";
|
||||||
import { Long } from "mongodb";
|
import { Long } from "mongodb";
|
||||||
|
import { nanoid } from "nanoid";
|
||||||
|
|
||||||
export async function sendAlert(userId: string, content: string) {
|
export async function sendAlert(userId: string, content: string) {
|
||||||
await checkPermission("users/create/alert", userId, { content });
|
await checkPermission("users/create/alert", userId, { content });
|
||||||
|
@ -819,6 +820,84 @@ export async function updateBotDiscoverability(botId: string, state: boolean) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function resetBotToken(botId: string) {
|
||||||
|
await checkPermission("bots/update/reset-token", { botId });
|
||||||
|
|
||||||
|
// Should generate tokens the exact same as the backend generates them:
|
||||||
|
// https://github.com/revoltchat/backend/blob/41f20c2239ed6307ad821b321d13240dc6ff3327/crates/core/database/src/models/bots/model.rs#L106
|
||||||
|
|
||||||
|
await mongo()
|
||||||
|
.db("revolt")
|
||||||
|
.collection<Bot>("bots")
|
||||||
|
.updateOne(
|
||||||
|
{
|
||||||
|
_id: botId,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
token: nanoid(64),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function transferBot(botId: string, ownerId: string, resetToken: boolean) {
|
||||||
|
await checkPermission("bots/update/owner", { botId, ownerId, resetToken });
|
||||||
|
|
||||||
|
if (resetToken) {
|
||||||
|
await checkPermission("bots/update/reset-token", { botId });
|
||||||
|
}
|
||||||
|
|
||||||
|
await mongo()
|
||||||
|
.db("revolt")
|
||||||
|
.collection<Bot>("bots")
|
||||||
|
.updateOne(
|
||||||
|
{
|
||||||
|
_id: botId,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
owner: ownerId,
|
||||||
|
...(
|
||||||
|
resetToken
|
||||||
|
? {
|
||||||
|
token: nanoid(64),
|
||||||
|
}
|
||||||
|
: {}
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
await mongo()
|
||||||
|
.db("revolt")
|
||||||
|
.collection<User>("users")
|
||||||
|
.updateOne(
|
||||||
|
{
|
||||||
|
_id: botId,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
"bot.owner": ownerId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// This doesn't appear to work, maybe Revite can't handle it. I'll leave it in regardless.
|
||||||
|
await publishMessage(
|
||||||
|
botId,
|
||||||
|
{
|
||||||
|
type: "UserUpdate",
|
||||||
|
id: botId,
|
||||||
|
data: {
|
||||||
|
bot: {
|
||||||
|
owner: ownerId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export async function restoreAccount(accountId: string) {
|
export async function restoreAccount(accountId: string) {
|
||||||
if (RESTRICT_ACCESS_LIST.includes(accountId)) throw "restricted access";
|
if (RESTRICT_ACCESS_LIST.includes(accountId)) throw "restricted access";
|
||||||
await checkPermission("accounts/restore", accountId);
|
await checkPermission("accounts/restore", accountId);
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
"lodash.debounce": "^4.0.8",
|
"lodash.debounce": "^4.0.8",
|
||||||
"lucide-react": "^0.263.0",
|
"lucide-react": "^0.263.0",
|
||||||
"mongodb": "^5.7.0",
|
"mongodb": "^5.7.0",
|
||||||
|
"nanoid": "^5.0.1",
|
||||||
"next": "13.4.12",
|
"next": "13.4.12",
|
||||||
"next-auth": "^4.22.3",
|
"next-auth": "^4.22.3",
|
||||||
"ntfy": "^1.3.1",
|
"ntfy": "^1.3.1",
|
||||||
|
|
|
@ -80,6 +80,9 @@ dependencies:
|
||||||
mongodb:
|
mongodb:
|
||||||
specifier: ^5.7.0
|
specifier: ^5.7.0
|
||||||
version: 5.7.0
|
version: 5.7.0
|
||||||
|
nanoid:
|
||||||
|
specifier: ^5.0.1
|
||||||
|
version: 5.0.1
|
||||||
next:
|
next:
|
||||||
specifier: 13.4.12
|
specifier: 13.4.12
|
||||||
version: 13.4.12(react-dom@18.2.0)(react@18.2.0)(sass@1.64.1)
|
version: 13.4.12(react-dom@18.2.0)(react@18.2.0)(sass@1.64.1)
|
||||||
|
@ -3754,6 +3757,12 @@ packages:
|
||||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
/nanoid@5.0.1:
|
||||||
|
resolution: {integrity: sha512-vWeVtV5Cw68aML/QaZvqN/3QQXc6fBfIieAlu05m7FZW2Dgb+3f0xc0TTxuJW+7u30t7iSDTV/j3kVI0oJqIfQ==}
|
||||||
|
engines: {node: ^18 || >=20}
|
||||||
|
hasBin: true
|
||||||
|
dev: false
|
||||||
|
|
||||||
/natural-compare@1.4.0:
|
/natural-compare@1.4.0:
|
||||||
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
Loading…
Reference in New Issue