Skip to content

Commit

Permalink
Update permission scheme
Browse files Browse the repository at this point in the history
  • Loading branch information
oliver-ni committed Jul 8, 2024
1 parent 7102b66 commit 4c0bc00
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 52 deletions.
10 changes: 1 addition & 9 deletions helpers/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { getUnixTime, sub } from "date-fns";
import { Long, MongoClient, UpdateFilter } from "mongodb";
import NodeCache from "node-cache";

import { Member, Position, RawMember, Submission, SubmissionStatus } from "./types";
import { Member, RawMember, Submission, SubmissionStatus } from "./types";

let client: MongoClient | undefined;

Expand All @@ -30,13 +30,6 @@ const wrapCache = <T extends (id: string) => Promise<any>>(key: string, func: T)
};
};

const ROLES: [Position, string[]][] = [
[Position.ADMIN, ["908088852567187467"]],
[Position.COMMUNITY_MANAGER, ["718006431231508481"]],
[Position.MODERATOR, ["724879492622843944", "813433839471820810"]],
[Position.HELPER, ["732712709514199110", "794438698241884200"]],
];

export const fetchMember = wrapCache("member", async (id: string): Promise<Member | undefined> => {
const db = await dbPromise;
const collection = db.collection("member");
Expand All @@ -51,7 +44,6 @@ export const fetchMember = wrapCache("member", async (id: string): Promise<Membe
...result,
_id: result._id.toString(),
roles,
position: ROLES.find(([, ids]) => roles?.some((x) => ids.includes(x)))?.[0] ?? Position.MEMBER,
};
});

Expand Down
17 changes: 17 additions & 0 deletions helpers/permissions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Member } from "./types";

const admin = "718006431231508481";
const serverManager = "1219500880534179892";
const botManager = "1219501453240959006";

const permittedRoles: Record<string, string[]> = {
"moderator-application": [admin, serverManager],
"ban-appeal": [admin, serverManager],
"suspension-appeal": [admin, botManager],
};

export const permittedToViewForm = (member: Member, formId: string) => {
const roles = member.roles ?? [];
const permittedRolesForForm = permittedRoles[formId] ?? [];
return roles.some((role) => permittedRolesForForm.includes(role));
};
35 changes: 9 additions & 26 deletions helpers/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ export enum AuthMode {
enum SessionStatus {
REDIRECT_LOGIN,
REDIRECT_DASHBOARD,
FORBIDDEN,
CONTINUE,
}

Expand All @@ -62,39 +61,25 @@ const addMemberInfo = async (session: IronSession<SessionVars>) => {
return { user, member };
};

const handleRequest = async (
user: User | undefined,
member: Member | undefined,
mode: AuthMode,
position: Position | undefined,
) => {
const handleRequest = async (user: User | undefined, mode: AuthMode) => {
if (mode === AuthMode.GUEST && user) return SessionStatus.REDIRECT_DASHBOARD;
if (mode === AuthMode.AUTHENTICATED && !user) return SessionStatus.REDIRECT_LOGIN;

if (position) {
if (!member) return SessionStatus.FORBIDDEN;
if (member.position < position) return SessionStatus.FORBIDDEN;
}

return SessionStatus.CONTINUE;
};

export const withSession = (
handler: (req: NextIronRequest, res: NextApiResponse) => void,
mode: AuthMode,
position?: Position,
mode: AuthMode
) => {
const wrapped = async (req: NextIronRequest, res: NextApiResponse) => {
req.session = await getIronSession<SessionVars>(req, res, IRON_CONFIG);
const { user, member } = await addMemberInfo(req.session);
const status = await handleRequest(user, member, mode, position);
const { user } = await addMemberInfo(req.session);
const status = await handleRequest(user, mode);

if (status === SessionStatus.REDIRECT_DASHBOARD) {
return res.redirect("/dashboard");
} else if (status === SessionStatus.REDIRECT_LOGIN) {
return res.redirect("/");
} else if (status === SessionStatus.FORBIDDEN) {
return res.status(403).end();
}

return handler(req, res);
Expand All @@ -105,25 +90,23 @@ export const withSession = (

export const withServerSideSession = <
T extends { [key: string]: any } = { [key: string]: any },
Q extends ParsedUrlQuery = ParsedUrlQuery,
Q extends ParsedUrlQuery = ParsedUrlQuery
>(
handler: (ctx: NextIronGetServerSidePropsContext<Q>) => Promise<GetServerSidePropsResult<T>>,
mode: AuthMode,
position?: Position,
position?: Position
) => {
const wrapped = async (
ctx: NextIronGetServerSidePropsContext<Q>,
ctx: NextIronGetServerSidePropsContext<Q>
): Promise<GetServerSidePropsResult<T>> => {
ctx.req.session = await getIronSession<SessionVars>(ctx.req, ctx.res, IRON_CONFIG);
const { user, member } = await addMemberInfo(ctx.req.session);
const status = await handleRequest(user, member, mode, position);
const { user } = await addMemberInfo(ctx.req.session);
const status = await handleRequest(user, mode);

if (status === SessionStatus.REDIRECT_DASHBOARD) {
return { redirect: { permanent: false, destination: "/dashboard" } };
} else if (status === SessionStatus.REDIRECT_LOGIN) {
return { redirect: { permanent: false, destination: "/" } };
} else if (status === SessionStatus.FORBIDDEN) {
return { redirect: { permanent: false, destination: "/dashboard" } };
}

return handler(ctx);
Expand Down
1 change: 0 additions & 1 deletion helpers/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ export type Member = {
muted?: boolean;
trading_muted?: boolean;
roles?: string[];
position: Position;
};

export enum Position {
Expand Down
16 changes: 11 additions & 5 deletions pages/a/[formId]/submissions/[submissionId].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import ErrorAlert from "~components/formium/ErrorAlert";
import SubmissionsLayout from "~components/layouts/SubmissionsLayout";
import { fetchSubmission, fetchSubmissions } from "~helpers/db";
import { formium } from "~helpers/formium";
import { permittedToViewForm } from "~helpers/permissions";
import { AuthMode, withServerSideSession } from "~helpers/session";
import {
Position,
Expand Down Expand Up @@ -153,7 +154,7 @@ type SubmissionContentProps = {
const SubmissionContent = ({ form, submission }: SubmissionContentProps) => {
const fieldNames = Object.values(form.schema?.fields ?? {}).reduce(
(acc, val) => acc.set(val.slug, val.title),
new Map<string, string | undefined>(),
new Map<string, string | undefined>()
);

const ownedFields = [...fieldNames.keys()].filter((x) => submission.data.hasOwnProperty(x));
Expand Down Expand Up @@ -326,12 +327,17 @@ type SubmissionPageQuery = {

export const getServerSideProps = withServerSideSession<SubmissionPageProps, SubmissionPageQuery>(
async ({ req, params, query }) => {
const user = req.session.user;
if (!params) throw new Error("No params found.");
if (!user) throw new Error("User not found");

const { formId, submissionId } = params;

const user = req.session.user;
const member = req.session.member;
if (!user || !member) throw new Error("User not found");

if (!permittedToViewForm(member, formId)) {
return { redirect: { permanent: false, destination: "/dashboard" } };
}

let form;
try {
form = await formium.getFormBySlug(formId);
Expand Down Expand Up @@ -363,5 +369,5 @@ export const getServerSideProps = withServerSideSession<SubmissionPageProps, Sub
};
},
AuthMode.AUTHENTICATED,
Position.COMMUNITY_MANAGER,
Position.COMMUNITY_MANAGER
);
24 changes: 17 additions & 7 deletions pages/a/[formId]/submissions/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Form } from "@formium/types";
import SubmissionsLayout from "~components/layouts/SubmissionsLayout";
import { fetchSubmissions } from "~helpers/db";
import { formium } from "~helpers/formium";
import { permittedToViewForm } from "~helpers/permissions";
import { AuthMode, withServerSideSession } from "~helpers/session";
import { Position, SerializableSubmission, User, makeSerializable } from "~helpers/types";

Expand All @@ -28,17 +29,26 @@ const SubmissionsPage = ({ user, form, submissions }: SubmissionsPageProps) => {

export default SubmissionsPage;

export const getServerSideProps = withServerSideSession<SubmissionsPageProps>(
type SubmissionsPageQuery = {
formId: string;
};

export const getServerSideProps = withServerSideSession<SubmissionsPageProps, SubmissionsPageQuery>(
async ({ req, params, query }) => {
const id = params?.formId?.toString();
if (!params) throw new Error("No params found.");
const { formId } = params;

const user = req.session.user;
const member = req.session.member;
if (!user || !member) throw new Error("User not found");

if (!id) throw new Error("Form ID not found");
if (!user) throw new Error("User not found");
if (!permittedToViewForm(member, formId)) {
return { redirect: { permanent: false, destination: "/dashboard" } };
}

let form;
try {
form = await formium.getFormBySlug(id);
form = await formium.getFormBySlug(formId);
} catch (e) {
const err = e as any;
if (err.status === 404) return { notFound: true };
Expand All @@ -55,13 +65,13 @@ export const getServerSideProps = withServerSideSession<SubmissionsPageProps>(

return {
props: {
id,
id: formId,
form,
user,
submissions: submissions.map(makeSerializable),
},
};
},
AuthMode.AUTHENTICATED,
Position.COMMUNITY_MANAGER,
Position.COMMUNITY_MANAGER
);
12 changes: 8 additions & 4 deletions pages/api/forms/[formId]/submissions/[submissionId].ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { NextApiResponse } from "next";
import { AuthMode, NextIronRequest, withSession } from "helpers/session";
import { fetchSubmission, updateSubmission } from "~helpers/db";
import { formium } from "~helpers/formium";
import { Position, Submission, SubmissionStatus } from "~helpers/types";
import { permittedToViewForm } from "~helpers/permissions";
import { Submission, SubmissionStatus } from "~helpers/types";

sendgrid.setApiKey(process.env.SENDGRID_KEY as string);

Expand All @@ -18,7 +19,7 @@ const sendEmail = async (
submission: Submission,
formId: string,
status: number,
comment: string,
comment: string
) => {
if (!submission.email) return;
if (!(status in EMAIL_UPDATES)) return;
Expand Down Expand Up @@ -52,7 +53,10 @@ const handler = async (req: NextIronRequest, res: NextApiResponse) => {
if (typeof req.body.status !== "number") return res.status(400).end();

const user = req.session.user;
if (!user) return res.status(401);
const member = req.session.member;
if (!user || !member) return res.status(401);

if (!permittedToViewForm(member, formId)) return res.status(403).end();

const submission = await fetchSubmission(submissionId);
if (!submission) return res.status(404);
Expand All @@ -68,4 +72,4 @@ const handler = async (req: NextIronRequest, res: NextApiResponse) => {
res.status(204).end();
};

export default withSession(handler, AuthMode.AUTHENTICATED, Position.COMMUNITY_MANAGER);
export default withSession(handler, AuthMode.AUTHENTICATED);

0 comments on commit 4c0bc00

Please sign in to comment.