1
0
Fork 0

feat: work on access control lists

fix-1
Paul Makles 2023-07-30 16:51:57 +01:00
parent 77bf9dfeed
commit 6d7681e2a1
No known key found for this signature in database
GPG Key ID: 5059F398521BB0F6
6 changed files with 124 additions and 46 deletions

View File

@ -8,8 +8,8 @@ import { NavigationToolbar } from "@/components/common/NavigationToolbar";
import { ReportActions } from "@/components/pages/inspector/ReportActions"; import { ReportActions } from "@/components/pages/inspector/ReportActions";
import { Separator } from "@/components/ui/separator"; import { Separator } from "@/components/ui/separator";
import { import {
fetchRelatedReports,
fetchReportById, fetchReportById,
fetchReports,
fetchSnapshotsByReport, fetchSnapshotsByReport,
fetchUserById, fetchUserById,
} from "@/lib/db"; } from "@/lib/db";
@ -28,13 +28,9 @@ export default async function Reports({ params }: { params: { id: string } }) {
snapshots snapshots
.map((snapshot) => snapshot._id) .map((snapshot) => snapshot._id)
.map((contentId) => .map((contentId) =>
fetchReports({ fetchRelatedReports(contentId).then((reports) =>
_id: { reports.filter((entry) => entry._id !== report._id)
$ne: report._id, )
},
status: "Created",
"content.id": contentId,
})
) )
); );

View File

@ -1,10 +1,10 @@
import { ReportCard } from "@/components/cards/ReportCard"; import { ReportCard } from "@/components/cards/ReportCard";
import { CardLink } from "@/components/common/CardLink"; import { CardLink } from "@/components/common/CardLink";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { fetchReports } from "@/lib/db"; import { fetchOpenReports } from "@/lib/db";
export default async function Reports() { export default async function Reports() {
const reports = (await fetchReports()) const reports = (await fetchOpenReports())
.reverse() .reverse()
.sort((b, _) => (b.content.report_reason.includes("Illegal") ? -1 : 0)); .sort((b, _) => (b.content.report_reason.includes("Illegal") ? -1 : 0));

53
lib/accessPermissions.ts Normal file
View File

@ -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}`;
}

View File

@ -10,7 +10,6 @@ import mongo, {
fetchMessages, fetchMessages,
fetchUserById, fetchUserById,
findDM, findDM,
updateLastMessageId,
} from "./db"; } from "./db";
import { publishMessage, sendChatMessage } from "./redis"; import { publishMessage, sendChatMessage } from "./redis";
import { ulid } from "ulid"; import { ulid } from "ulid";
@ -34,7 +33,6 @@ export async function sendAlert(userId: string, content: string) {
let dm = await findDM(PLATFORM_MOD_ID, userId); let dm = await findDM(PLATFORM_MOD_ID, userId);
if (!dm) dm = await createDM(PLATFORM_MOD_ID, userId, messageId); if (!dm) dm = await createDM(PLATFORM_MOD_ID, userId, messageId);
else await updateLastMessageId(dm._id, messageId);
await sendChatMessage({ await sendChatMessage({
_id: messageId, _id: messageId,

View File

@ -14,6 +14,7 @@ import type {
} from "revolt-api"; } from "revolt-api";
import { ulid } from "ulid"; import { ulid } from "ulid";
import { publishMessage } from "./redis"; import { publishMessage } from "./redis";
import { checkPermission } from "./accessPermissions";
let client: MongoClient; let client: MongoClient;
@ -28,7 +29,7 @@ function mongo() {
export default mongo; export default mongo;
export async function fetchBotById(id: string) { export async function fetchBotById(id: string) {
if (Math.random() > -1) throw "TODO: ACL"; await checkPermission("bots/fetch/by-id");
return await mongo() return await mongo()
.db("revolt") .db("revolt")
@ -78,7 +79,7 @@ export type Account = {
}; };
export async function fetchAccountById(id: string) { export async function fetchAccountById(id: string) {
if (Math.random() > -1) throw "TODO: ACL"; await checkPermission("accounts/fetch/by-id");
return await mongo() return await mongo()
.db("revolt") .db("revolt")
@ -95,7 +96,7 @@ export async function fetchAccountById(id: string) {
} }
export async function fetchSessionsByAccount(accountId: string) { export async function fetchSessionsByAccount(accountId: string) {
if (Math.random() > -1) throw "TODO: ACL"; await checkPermission("sessions/fetch/by-account-id");
return await mongo() return await mongo()
.db("revolt") .db("revolt")
@ -115,7 +116,7 @@ export async function fetchSessionsByAccount(accountId: string) {
} }
export async function fetchUserById(id: string) { export async function fetchUserById(id: string) {
if (Math.random() > -1) throw "TODO: ACL"; await checkPermission("users/fetch/by-id");
return await mongo() return await mongo()
.db("revolt") .db("revolt")
@ -124,7 +125,7 @@ export async function fetchUserById(id: string) {
} }
export async function fetchUsersById(ids: string[]) { export async function fetchUsersById(ids: string[]) {
if (Math.random() > -1) throw "TODO: ACL"; await checkPermission("users/fetch/by-id");
return await mongo() return await mongo()
.db("revolt") .db("revolt")
@ -134,7 +135,7 @@ export async function fetchUsersById(ids: string[]) {
} }
export async function fetchChannelById(id: string) { export async function fetchChannelById(id: string) {
if (Math.random() > -1) throw "TODO: ACL"; await checkPermission("channels/fetch/by-id");
return await mongo() return await mongo()
.db("revolt") .db("revolt")
@ -143,7 +144,7 @@ export async function fetchChannelById(id: string) {
} }
export async function fetchChannels(query: Filter<Channel>) { export async function fetchChannels(query: Filter<Channel>) {
if (Math.random() > -1) throw "TODO: ACL"; await checkPermission("channels/fetch");
return await mongo() return await mongo()
.db("revolt") .db("revolt")
@ -152,20 +153,8 @@ export async function fetchChannels(query: Filter<Channel>) {
.toArray(); .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) { 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() return await mongo()
.db("revolt") .db("revolt")
@ -183,7 +172,7 @@ export async function createDM(
userB: string, userB: string,
lastMessageId?: string lastMessageId?: string
) { ) {
if (Math.random() > -1) throw "TODO: ACL"; await checkPermission("channels/create/dm");
const newChannel: Channel & { channel_type: "DirectMessage" } = { const newChannel: Channel & { channel_type: "DirectMessage" } = {
_id: ulid(), _id: ulid(),
@ -211,7 +200,7 @@ export async function createDM(
} }
export async function fetchServerById(id: string) { export async function fetchServerById(id: string) {
if (Math.random() > -1) throw "TODO: ACL"; await checkPermission("servers/fetch/by-id");
return await mongo() return await mongo()
.db("revolt") .db("revolt")
@ -220,7 +209,7 @@ export async function fetchServerById(id: string) {
} }
export async function fetchServers(query: Filter<Server>) { export async function fetchServers(query: Filter<Server>) {
if (Math.random() > -1) throw "TODO: ACL"; await checkPermission("servers/fetch");
return await mongo() return await mongo()
.db("revolt") .db("revolt")
@ -230,7 +219,7 @@ export async function fetchServers(query: Filter<Server>) {
} }
export async function fetchMessageById(id: string) { export async function fetchMessageById(id: string) {
if (Math.random() > -1) throw "TODO: ACL"; await checkPermission("messages/fetch/by-id");
return await mongo() return await mongo()
.db("revolt") .db("revolt")
@ -239,7 +228,7 @@ export async function fetchMessageById(id: string) {
} }
export async function fetchMessages(query: Filter<Message>, limit = 50) { export async function fetchMessages(query: Filter<Message>, limit = 50) {
if (Math.random() > -1) throw "TODO: ACL"; await checkPermission("messages/fetch");
return await mongo() return await mongo()
.db("revolt") .db("revolt")
@ -248,10 +237,44 @@ export async function fetchMessages(query: Filter<Message>, limit = 50) {
.toArray(); .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( export async function fetchReports(
query: Filter<Report> = { status: "Created" } query: Filter<Report> = { status: "Created" }
) { ) {
if (Math.random() > -1) throw "TODO: ACL"; await checkPermission("reports/fetch");
return await mongo() return await mongo()
.db("revolt") .db("revolt")
@ -265,7 +288,7 @@ export async function fetchReports(
} }
export async function fetchReportById(id: string) { export async function fetchReportById(id: string) {
if (Math.random() > -1) throw "TODO: ACL"; await checkPermission("reports/fetch/by-id");
return await mongo() return await mongo()
.db("revolt") .db("revolt")
@ -274,7 +297,7 @@ export async function fetchReportById(id: string) {
} }
export async function fetchMembershipsByUser(userId: string) { export async function fetchMembershipsByUser(userId: string) {
if (Math.random() > -1) throw "TODO: ACL"; await checkPermission("users/fetch/memberships");
return await mongo() return await mongo()
.db("revolt") .db("revolt")
@ -286,7 +309,7 @@ export async function fetchMembershipsByUser(userId: string) {
export async function fetchSnapshots( export async function fetchSnapshots(
query: Filter<{ _id: string; report_id: string; content: SnapshotContent }> query: Filter<{ _id: string; report_id: string; content: SnapshotContent }>
) { ) {
if (Math.random() > -1) throw "TODO: ACL"; await checkPermission("reports/fetch/snapshots");
return await mongo() return await mongo()
.db("revolt") .db("revolt")
@ -298,7 +321,7 @@ export async function fetchSnapshots(
} }
export async function fetchSnapshotsByReport(reportId: string) { export async function fetchSnapshotsByReport(reportId: string) {
if (Math.random() > -1) throw "TODO: ACL"; await checkPermission("reports/fetch/snapshots/by-report");
return await mongo() return await mongo()
.db("revolt") .db("revolt")
@ -309,7 +332,7 @@ export async function fetchSnapshotsByReport(reportId: string) {
} }
export async function fetchStrikesByUser(userId: string) { export async function fetchStrikesByUser(userId: string) {
if (Math.random() > -1) throw "TODO: ACL"; await checkPermission("reports/fetch/snapshots/by-user");
return await mongo() return await mongo()
.db("revolt") .db("revolt")
@ -326,7 +349,7 @@ export async function fetchStrikesByUser(userId: string) {
} }
export async function fetchBotsByUser(userId: string) { export async function fetchBotsByUser(userId: string) {
if (Math.random() > -1) throw "TODO: ACL"; await checkPermission("bots/fetch/by-user");
return await mongo() return await mongo()
.db("revolt") .db("revolt")
@ -341,7 +364,7 @@ export type EmailClassification = {
}; };
export async function fetchAuthifierEmailClassification(provider: string) { export async function fetchAuthifierEmailClassification(provider: string) {
if (Math.random() > -1) throw "TODO: ACL"; await checkPermission("authifier");
return await mongo() return await mongo()
.db("authifier") .db("authifier")

View File

@ -1,7 +1,7 @@
"use server"; "use server";
import { createClient } from "redis"; 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 type { ProtocolV1 } from "revolt.js/lib/events/v1";
import mongo from "./db"; import mongo from "./db";
@ -38,6 +38,14 @@ export async function sendChatMessage(message: Message, ephermal = false) {
.db("revolt") .db("revolt")
.collection<Message>("messages") .collection<Message>("messages")
.insertOne(message); .insertOne(message);
await mongo()
.db("revolt")
.collection<Channel>("channels")
.updateOne(
{ _id: message.channel },
{ $set: { last_message_id: message._id } }
);
} }
await publishMessage(message.channel, { await publishMessage(message.channel, {