forked from administration/panel
feat: work on access control lists
parent
77bf9dfeed
commit
6d7681e2a1
|
@ -8,8 +8,8 @@ import { NavigationToolbar } from "@/components/common/NavigationToolbar";
|
|||
import { ReportActions } from "@/components/pages/inspector/ReportActions";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import {
|
||||
fetchRelatedReports,
|
||||
fetchReportById,
|
||||
fetchReports,
|
||||
fetchSnapshotsByReport,
|
||||
fetchUserById,
|
||||
} from "@/lib/db";
|
||||
|
@ -28,13 +28,9 @@ export default async function Reports({ params }: { params: { id: string } }) {
|
|||
snapshots
|
||||
.map((snapshot) => snapshot._id)
|
||||
.map((contentId) =>
|
||||
fetchReports({
|
||||
_id: {
|
||||
$ne: report._id,
|
||||
},
|
||||
status: "Created",
|
||||
"content.id": contentId,
|
||||
})
|
||||
fetchRelatedReports(contentId).then((reports) =>
|
||||
reports.filter((entry) => entry._id !== report._id)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { ReportCard } from "@/components/cards/ReportCard";
|
||||
import { CardLink } from "@/components/common/CardLink";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { fetchReports } from "@/lib/db";
|
||||
import { fetchOpenReports } from "@/lib/db";
|
||||
|
||||
export default async function Reports() {
|
||||
const reports = (await fetchReports())
|
||||
const reports = (await fetchOpenReports())
|
||||
.reverse()
|
||||
.sort((b, _) => (b.content.report_reason.includes("Illegal") ? -1 : 0));
|
||||
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
import { getServerSession } from "next-auth";
|
||||
|
||||
type Permission =
|
||||
| "authifier"
|
||||
| `accounts${"" | `/fetch${"" | "/by-id"}`}`
|
||||
| `bots${"" | `/fetch${"" | "/by-id" | "/by-user"}`}`
|
||||
| `channels${"" | `/fetch${"" | "/by-id" | "/dm"}` | `/create${"" | "/dm"}`}`
|
||||
| `messages${"" | `/fetch${"" | "/by-id"}`}`
|
||||
| `reports${
|
||||
| ""
|
||||
| `/fetch${
|
||||
| ""
|
||||
| "/by-id"
|
||||
| "/open"
|
||||
| `/related${"" | "/by-content" | "/by-user"}`
|
||||
| `/snapshots${"" | "/by-report" | "/by-user"}`}`}`
|
||||
| `sessions${"" | `/fetch${"" | "/by-account-id"}`}`
|
||||
| `servers${"" | `/fetch${"" | "/by-id"}`}`
|
||||
| `users${"" | `/fetch${"" | "/by-id" | "/memberships"}`}`;
|
||||
|
||||
const ACL: Record<string, Set<Permission>> = {
|
||||
"insert@revolt.chat": new Set([
|
||||
"users/fetch/by-id",
|
||||
"reports/fetch/open",
|
||||
"reports/fetch/by-id",
|
||||
"reports/fetch/related",
|
||||
"reports/fetch/snapshots/by-report",
|
||||
] as Permission[]),
|
||||
};
|
||||
|
||||
function hasPermission(email: string, permission: Permission) {
|
||||
const segments = permission.split("/");
|
||||
while (segments.length) {
|
||||
if (ACL[email].has(segments.join("/") as Permission)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
segments.pop();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export async function hasPermissionFromSession(permission: Permission) {
|
||||
const session = await getServerSession();
|
||||
if (!session?.user?.email) throw "Not authenticated.";
|
||||
return hasPermission(session.user.email, permission);
|
||||
}
|
||||
|
||||
export async function checkPermission(permission: Permission) {
|
||||
if (!(await hasPermissionFromSession(permission)))
|
||||
throw `Missing permission ${permission}`;
|
||||
}
|
|
@ -10,7 +10,6 @@ import mongo, {
|
|||
fetchMessages,
|
||||
fetchUserById,
|
||||
findDM,
|
||||
updateLastMessageId,
|
||||
} from "./db";
|
||||
import { publishMessage, sendChatMessage } from "./redis";
|
||||
import { ulid } from "ulid";
|
||||
|
@ -34,7 +33,6 @@ export async function sendAlert(userId: string, content: string) {
|
|||
|
||||
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,
|
||||
|
|
89
lib/db.ts
89
lib/db.ts
|
@ -14,6 +14,7 @@ import type {
|
|||
} from "revolt-api";
|
||||
import { ulid } from "ulid";
|
||||
import { publishMessage } from "./redis";
|
||||
import { checkPermission } from "./accessPermissions";
|
||||
|
||||
let client: MongoClient;
|
||||
|
||||
|
@ -28,7 +29,7 @@ function mongo() {
|
|||
export default mongo;
|
||||
|
||||
export async function fetchBotById(id: string) {
|
||||
if (Math.random() > -1) throw "TODO: ACL";
|
||||
await checkPermission("bots/fetch/by-id");
|
||||
|
||||
return await mongo()
|
||||
.db("revolt")
|
||||
|
@ -78,7 +79,7 @@ export type Account = {
|
|||
};
|
||||
|
||||
export async function fetchAccountById(id: string) {
|
||||
if (Math.random() > -1) throw "TODO: ACL";
|
||||
await checkPermission("accounts/fetch/by-id");
|
||||
|
||||
return await mongo()
|
||||
.db("revolt")
|
||||
|
@ -95,7 +96,7 @@ export async function fetchAccountById(id: string) {
|
|||
}
|
||||
|
||||
export async function fetchSessionsByAccount(accountId: string) {
|
||||
if (Math.random() > -1) throw "TODO: ACL";
|
||||
await checkPermission("sessions/fetch/by-account-id");
|
||||
|
||||
return await mongo()
|
||||
.db("revolt")
|
||||
|
@ -115,7 +116,7 @@ export async function fetchSessionsByAccount(accountId: string) {
|
|||
}
|
||||
|
||||
export async function fetchUserById(id: string) {
|
||||
if (Math.random() > -1) throw "TODO: ACL";
|
||||
await checkPermission("users/fetch/by-id");
|
||||
|
||||
return await mongo()
|
||||
.db("revolt")
|
||||
|
@ -124,7 +125,7 @@ export async function fetchUserById(id: string) {
|
|||
}
|
||||
|
||||
export async function fetchUsersById(ids: string[]) {
|
||||
if (Math.random() > -1) throw "TODO: ACL";
|
||||
await checkPermission("users/fetch/by-id");
|
||||
|
||||
return await mongo()
|
||||
.db("revolt")
|
||||
|
@ -134,7 +135,7 @@ export async function fetchUsersById(ids: string[]) {
|
|||
}
|
||||
|
||||
export async function fetchChannelById(id: string) {
|
||||
if (Math.random() > -1) throw "TODO: ACL";
|
||||
await checkPermission("channels/fetch/by-id");
|
||||
|
||||
return await mongo()
|
||||
.db("revolt")
|
||||
|
@ -143,7 +144,7 @@ export async function fetchChannelById(id: string) {
|
|||
}
|
||||
|
||||
export async function fetchChannels(query: Filter<Channel>) {
|
||||
if (Math.random() > -1) throw "TODO: ACL";
|
||||
await checkPermission("channels/fetch");
|
||||
|
||||
return await mongo()
|
||||
.db("revolt")
|
||||
|
@ -152,20 +153,8 @@ export async function fetchChannels(query: Filter<Channel>) {
|
|||
.toArray();
|
||||
}
|
||||
|
||||
export async function updateLastMessageId(
|
||||
channelId: string,
|
||||
messageId: string
|
||||
) {
|
||||
if (Math.random() > -1) throw "TODO: ACL";
|
||||
|
||||
return await mongo()
|
||||
.db("revolt")
|
||||
.collection<Channel>("channels")
|
||||
.updateOne({ _id: channelId }, { $set: { last_message_id: messageId } });
|
||||
}
|
||||
|
||||
export async function findDM(user_a: string, user_b: string) {
|
||||
if (Math.random() > -1) throw "TODO: ACL";
|
||||
await checkPermission("channels/fetch/dm");
|
||||
|
||||
return await mongo()
|
||||
.db("revolt")
|
||||
|
@ -183,7 +172,7 @@ export async function createDM(
|
|||
userB: string,
|
||||
lastMessageId?: string
|
||||
) {
|
||||
if (Math.random() > -1) throw "TODO: ACL";
|
||||
await checkPermission("channels/create/dm");
|
||||
|
||||
const newChannel: Channel & { channel_type: "DirectMessage" } = {
|
||||
_id: ulid(),
|
||||
|
@ -211,7 +200,7 @@ export async function createDM(
|
|||
}
|
||||
|
||||
export async function fetchServerById(id: string) {
|
||||
if (Math.random() > -1) throw "TODO: ACL";
|
||||
await checkPermission("servers/fetch/by-id");
|
||||
|
||||
return await mongo()
|
||||
.db("revolt")
|
||||
|
@ -220,7 +209,7 @@ export async function fetchServerById(id: string) {
|
|||
}
|
||||
|
||||
export async function fetchServers(query: Filter<Server>) {
|
||||
if (Math.random() > -1) throw "TODO: ACL";
|
||||
await checkPermission("servers/fetch");
|
||||
|
||||
return await mongo()
|
||||
.db("revolt")
|
||||
|
@ -230,7 +219,7 @@ export async function fetchServers(query: Filter<Server>) {
|
|||
}
|
||||
|
||||
export async function fetchMessageById(id: string) {
|
||||
if (Math.random() > -1) throw "TODO: ACL";
|
||||
await checkPermission("messages/fetch/by-id");
|
||||
|
||||
return await mongo()
|
||||
.db("revolt")
|
||||
|
@ -239,7 +228,7 @@ export async function fetchMessageById(id: string) {
|
|||
}
|
||||
|
||||
export async function fetchMessages(query: Filter<Message>, limit = 50) {
|
||||
if (Math.random() > -1) throw "TODO: ACL";
|
||||
await checkPermission("messages/fetch");
|
||||
|
||||
return await mongo()
|
||||
.db("revolt")
|
||||
|
@ -248,10 +237,44 @@ export async function fetchMessages(query: Filter<Message>, limit = 50) {
|
|||
.toArray();
|
||||
}
|
||||
|
||||
export async function fetchOpenReports() {
|
||||
await checkPermission("reports/fetch/open");
|
||||
|
||||
return await mongo()
|
||||
.db("revolt")
|
||||
.collection<Report>("safety_reports")
|
||||
.find(
|
||||
{ status: "Created" },
|
||||
{
|
||||
sort: {
|
||||
_id: -1,
|
||||
},
|
||||
}
|
||||
)
|
||||
.toArray();
|
||||
}
|
||||
|
||||
export async function fetchRelatedReports(contentId: string) {
|
||||
await checkPermission("reports/fetch/related/by-content");
|
||||
|
||||
return await mongo()
|
||||
.db("revolt")
|
||||
.collection<Report>("safety_reports")
|
||||
.find(
|
||||
{ status: "Created", "content.id": contentId },
|
||||
{
|
||||
sort: {
|
||||
_id: -1,
|
||||
},
|
||||
}
|
||||
)
|
||||
.toArray();
|
||||
}
|
||||
|
||||
export async function fetchReports(
|
||||
query: Filter<Report> = { status: "Created" }
|
||||
) {
|
||||
if (Math.random() > -1) throw "TODO: ACL";
|
||||
await checkPermission("reports/fetch");
|
||||
|
||||
return await mongo()
|
||||
.db("revolt")
|
||||
|
@ -265,7 +288,7 @@ export async function fetchReports(
|
|||
}
|
||||
|
||||
export async function fetchReportById(id: string) {
|
||||
if (Math.random() > -1) throw "TODO: ACL";
|
||||
await checkPermission("reports/fetch/by-id");
|
||||
|
||||
return await mongo()
|
||||
.db("revolt")
|
||||
|
@ -274,7 +297,7 @@ export async function fetchReportById(id: string) {
|
|||
}
|
||||
|
||||
export async function fetchMembershipsByUser(userId: string) {
|
||||
if (Math.random() > -1) throw "TODO: ACL";
|
||||
await checkPermission("users/fetch/memberships");
|
||||
|
||||
return await mongo()
|
||||
.db("revolt")
|
||||
|
@ -286,7 +309,7 @@ export async function fetchMembershipsByUser(userId: string) {
|
|||
export async function fetchSnapshots(
|
||||
query: Filter<{ _id: string; report_id: string; content: SnapshotContent }>
|
||||
) {
|
||||
if (Math.random() > -1) throw "TODO: ACL";
|
||||
await checkPermission("reports/fetch/snapshots");
|
||||
|
||||
return await mongo()
|
||||
.db("revolt")
|
||||
|
@ -298,7 +321,7 @@ export async function fetchSnapshots(
|
|||
}
|
||||
|
||||
export async function fetchSnapshotsByReport(reportId: string) {
|
||||
if (Math.random() > -1) throw "TODO: ACL";
|
||||
await checkPermission("reports/fetch/snapshots/by-report");
|
||||
|
||||
return await mongo()
|
||||
.db("revolt")
|
||||
|
@ -309,7 +332,7 @@ export async function fetchSnapshotsByReport(reportId: string) {
|
|||
}
|
||||
|
||||
export async function fetchStrikesByUser(userId: string) {
|
||||
if (Math.random() > -1) throw "TODO: ACL";
|
||||
await checkPermission("reports/fetch/snapshots/by-user");
|
||||
|
||||
return await mongo()
|
||||
.db("revolt")
|
||||
|
@ -326,7 +349,7 @@ export async function fetchStrikesByUser(userId: string) {
|
|||
}
|
||||
|
||||
export async function fetchBotsByUser(userId: string) {
|
||||
if (Math.random() > -1) throw "TODO: ACL";
|
||||
await checkPermission("bots/fetch/by-user");
|
||||
|
||||
return await mongo()
|
||||
.db("revolt")
|
||||
|
@ -341,7 +364,7 @@ export type EmailClassification = {
|
|||
};
|
||||
|
||||
export async function fetchAuthifierEmailClassification(provider: string) {
|
||||
if (Math.random() > -1) throw "TODO: ACL";
|
||||
await checkPermission("authifier");
|
||||
|
||||
return await mongo()
|
||||
.db("authifier")
|
||||
|
|
10
lib/redis.ts
10
lib/redis.ts
|
@ -1,7 +1,7 @@
|
|||
"use server";
|
||||
|
||||
import { createClient } from "redis";
|
||||
import { Message } from "revolt-api";
|
||||
import { Channel, Message } from "revolt-api";
|
||||
import type { ProtocolV1 } from "revolt.js/lib/events/v1";
|
||||
import mongo from "./db";
|
||||
|
||||
|
@ -38,6 +38,14 @@ export async function sendChatMessage(message: Message, ephermal = false) {
|
|||
.db("revolt")
|
||||
.collection<Message>("messages")
|
||||
.insertOne(message);
|
||||
|
||||
await mongo()
|
||||
.db("revolt")
|
||||
.collection<Channel>("channels")
|
||||
.updateOne(
|
||||
{ _id: message.channel },
|
||||
{ $set: { last_message_id: message._id } }
|
||||
);
|
||||
}
|
||||
|
||||
await publishMessage(message.channel, {
|
||||
|
|
Loading…
Reference in New Issue