From 596974625255b9483b55e8437060c0b93e3baaf1 Mon Sep 17 00:00:00 2001 From: Paul Makles Date: Sun, 30 Jul 2023 17:23:05 +0100 Subject: [PATCH] feat: implement ACL for actions --- lib/accessPermissions.ts | 48 +++++++++++++++++++++++++++++++++------- lib/actions.ts | 47 ++++++++++++++++----------------------- 2 files changed, 59 insertions(+), 36 deletions(-) diff --git a/lib/accessPermissions.ts b/lib/accessPermissions.ts index e954839..c783e07 100644 --- a/lib/accessPermissions.ts +++ b/lib/accessPermissions.ts @@ -2,8 +2,16 @@ import { getServerSession } from "next-auth"; type Permission = | "authifier" - | `accounts${"" | `/fetch${"" | "/by-id"}`}` - | `bots${"" | `/fetch${"" | "/by-id" | "/by-user"}`}` + | `accounts${ + | "" + | `/fetch${"" | "/by-id"}` + | "/disable" + | "/restore" + | `/deletion${"" | "/queue" | "/cancel"}`}` + | `bots${ + | "" + | `/fetch${"" | "/by-id" | "/by-user"}` + | `/update${"" | "/discoverability"}`}` | `channels${"" | `/fetch${"" | "/by-id" | "/dm"}` | `/create${"" | "/dm"}`}` | `messages${"" | `/fetch${"" | "/by-id"}`}` | `reports${ @@ -13,19 +21,43 @@ type Permission = | "/by-id" | "/open" | `/related${"" | "/by-content" | "/by-user"}` - | `/snapshots${"" | "/by-report" | "/by-user"}`}`}` + | `/snapshots${"" | "/by-report" | "/by-user"}`}` + | `/update${ + | "" + | "/notes" + | "/resolve" + | "/reject" + | "/reopen" + | `/bulk-close${"" | "/by-user"}`}`}` | `sessions${"" | `/fetch${"" | "/by-account-id"}`}` - | `servers${"" | `/fetch${"" | "/by-id"}`}` - | `users${"" | `/fetch${"" | "/by-id" | "/memberships"}`}`; + | `servers${ + | "" + | `/fetch${"" | "/by-id"}` + | `/update${"" | "/flags" | "/discoverability"}`}` + | `users${ + | "" + | `/fetch${"" | "/by-id" | "/memberships"}` + | `/create${"" | "/alert" | "/strike"}` + | `/update${"" | "/badges"}` + | `/action${"" | "/unsuspend" | "/suspend" | "/wipe" | "/ban"}`}`; -const ACL: Record> = { - "insert@revolt.chat": new Set([ +const PermissionSets = { + "view-open-reports": [ + // Required for viewing open reports "users/fetch/by-id", "reports/fetch/open", "reports/fetch/by-id", "reports/fetch/related", "reports/fetch/snapshots/by-report", - ] as Permission[]), + ] as Permission[], +}; + +const Roles = { + moderator: [...PermissionSets["view-open-reports"]], +}; + +const ACL: Record> = { + "insert@revolt.chat": new Set([...Roles["moderator"]] as Permission[]), }; function hasPermission(email: string, permission: Permission) { diff --git a/lib/actions.ts b/lib/actions.ts index b475a4c..dcb0071 100644 --- a/lib/actions.ts +++ b/lib/actions.ts @@ -25,9 +25,10 @@ import { SessionInfo, User, } from "revolt-api"; +import { checkPermission } from "./accessPermissions"; export async function sendAlert(userId: string, content: string) { - if (Math.random() > -1) throw "TODO: ACL"; + await checkPermission("users/create/alert"); const messageId = ulid(); @@ -47,7 +48,7 @@ export async function createStrike( givenReason: string, additionalContext: string ) { - if (Math.random() > -1) throw "TODO: ACL"; + await checkPermission("users/create/strike"); const strike: AccountStrike & { moderator_id: string } = { _id: ulid(), @@ -74,7 +75,7 @@ Further violations will result in suspension or a permanent ban depending on sev } export async function updateReportNotes(reportId: string, notes: string) { - if (Math.random() > -1) throw "TODO: ACL"; + await checkPermission("reports/update/notes"); return await mongo() .db("revolt") @@ -90,7 +91,7 @@ export async function updateReportNotes(reportId: string, notes: string) { } export async function resolveReport(reportId: string) { - if (Math.random() > -1) throw "TODO: ACL"; + await checkPermission("reports/update/resolve"); const $set = { status: "Resolved", @@ -108,7 +109,7 @@ export async function resolveReport(reportId: string) { } export async function rejectReport(reportId: string, reason: string) { - if (Math.random() > -1) throw "TODO: ACL"; + await checkPermission("reports/update/reject"); const $set = { status: "Rejected", @@ -127,7 +128,7 @@ export async function rejectReport(reportId: string, reason: string) { } export async function reopenReport(reportId: string) { - if (Math.random() > -1) throw "TODO: ACL"; + await checkPermission("reports/update/reopen"); const $set = { status: "Created", @@ -172,7 +173,7 @@ export async function closeReportsByUser(userId: string) { } export async function disableAccount(userId: string) { - if (Math.random() > -1) throw "TODO: ACL"; + await checkPermission("accounts/disable"); await mongo() .db("revolt") @@ -185,8 +186,7 @@ export async function disableAccount(userId: string) { } export async function suspendUser(userId: string) { - if (Math.random() > -1) throw "TODO: ACL"; - + await checkPermission("users/action/suspend"); await disableAccount(userId); await mongo() @@ -217,8 +217,7 @@ export async function suspendUser(userId: string) { } export async function updateUserBadges(userId: string, badges: number) { - if (Math.random() > -1) throw "TODO: ACL"; - + await checkPermission("users/update/badges"); await mongo().db("revolt").collection("users").updateOne( { _id: userId, @@ -244,7 +243,7 @@ export async function updateUserBadges(userId: string, badges: number) { } export async function wipeUser(userId: string, flags = 4) { - if (Math.random() > -1) throw "TODO: ACL"; + await checkPermission("users/action/wipe"); // retrieve messages, dm channels, relationships, server memberships const backup = { @@ -341,14 +340,12 @@ export async function wipeUser(userId: string, flags = 4) { } export async function banUser(userId: string) { - if (Math.random() > -1) throw "TODO: ACL"; - + await checkPermission("users/action/ban"); return await wipeUser(userId, 4); } export async function unsuspendUser(userId: string) { - if (Math.random() > -1) throw "TODO: ACL"; - + await checkPermission("users/action/unsuspend"); await restoreAccount(userId); await mongo() @@ -367,8 +364,7 @@ export async function unsuspendUser(userId: string) { } export async function updateServerFlags(serverId: string, flags: number) { - if (Math.random() > -1) throw "TODO: ACL"; - + await checkPermission("servers/update/flags"); await mongo().db("revolt").collection("servers").updateOne( { _id: serverId, @@ -394,8 +390,7 @@ export async function updateServerDiscoverability( serverId: string, state: boolean ) { - if (Math.random() > -1) throw "TODO: ACL"; - + await checkPermission("servers/update/discoverability"); await mongo() .db("revolt") .collection("servers") @@ -413,8 +408,7 @@ export async function updateServerDiscoverability( } export async function updateBotDiscoverability(botId: string, state: boolean) { - if (Math.random() > -1) throw "TODO: ACL"; - + await checkPermission("bots/update/discoverability"); await mongo() .db("revolt") .collection("bots") @@ -432,8 +426,7 @@ export async function updateBotDiscoverability(botId: string, state: boolean) { } export async function restoreAccount(accountId: string) { - if (Math.random() > -1) throw "TODO: ACL"; - + await checkPermission("accounts/restore"); await mongo() .db("revolt") .collection("accounts") @@ -450,8 +443,7 @@ export async function restoreAccount(accountId: string) { } export async function queueAccountDeletion(accountId: string) { - if (Math.random() > -1) throw "TODO: ACL"; - + await checkPermission("accounts/deletion/queue"); const twoWeeksFuture = new Date(); twoWeeksFuture.setDate(twoWeeksFuture.getDate() + 14); @@ -477,8 +469,7 @@ export async function queueAccountDeletion(accountId: string) { } export async function cancelAccountDeletion(accountId: string) { - if (Math.random() > -1) throw "TODO: ACL"; - + await checkPermission("accounts/deletion/cancel"); await mongo() .db("revolt") .collection("accounts")