Harden form auth and submission handling
This commit is contained in:
+20
-24
@@ -7,17 +7,8 @@ import { questions } from "@/db/schema";
|
||||
import type { QuestionType } from "@/db/schema";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/app/api/auth/[...nextauth]/route";
|
||||
|
||||
async function assertAdmin() {
|
||||
const session = await getServerSession(authOptions);
|
||||
const adminIds = (process.env.ADMIN_DISCORD_IDS ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
||||
const discordId = (session?.user as { discordId?: string } | undefined)?.discordId;
|
||||
if (!discordId || !adminIds.includes(discordId)) {
|
||||
throw new Error("Unauthorized");
|
||||
}
|
||||
}
|
||||
import { requireAdmin } from "@/lib/auth";
|
||||
import { sanitizeHtml } from "@/lib/sanitize-html";
|
||||
|
||||
export async function createQuestion(
|
||||
formId: string,
|
||||
@@ -29,18 +20,18 @@ export async function createQuestion(
|
||||
options?: string[];
|
||||
}
|
||||
) {
|
||||
await assertAdmin();
|
||||
await requireAdmin();
|
||||
await db.insert(questions).values({
|
||||
formId,
|
||||
type: data.type,
|
||||
label: data.label,
|
||||
label: sanitizeHtml(data.label),
|
||||
required: data.required,
|
||||
displayOrder: data.displayOrder,
|
||||
options: data.options ?? [],
|
||||
allowOther: false,
|
||||
});
|
||||
revalidatePath("/form");
|
||||
revalidatePath("/form/admin");
|
||||
revalidatePath("/admin/form");
|
||||
}
|
||||
|
||||
export async function updateQuestion(
|
||||
@@ -56,7 +47,7 @@ export async function updateQuestion(
|
||||
allowOther: boolean;
|
||||
}>
|
||||
) {
|
||||
await assertAdmin();
|
||||
await requireAdmin();
|
||||
if (data.imageUrl !== undefined) {
|
||||
const q = await db.query.questions.findFirst({
|
||||
where: (q, { eq }) => eq(q.id, id),
|
||||
@@ -65,9 +56,14 @@ export async function updateQuestion(
|
||||
await deleteImageFile(q.imageUrl);
|
||||
}
|
||||
}
|
||||
await db.update(questions).set(data).where(eq(questions.id, id));
|
||||
const nextData = {
|
||||
...data,
|
||||
label: data.label === undefined ? undefined : sanitizeHtml(data.label),
|
||||
};
|
||||
|
||||
await db.update(questions).set(nextData).where(eq(questions.id, id));
|
||||
revalidatePath("/form");
|
||||
revalidatePath("/form/admin");
|
||||
revalidatePath("/admin/form");
|
||||
}
|
||||
|
||||
export async function bulkUpdateQuestions(
|
||||
@@ -82,7 +78,7 @@ export async function bulkUpdateQuestions(
|
||||
allowOther: boolean;
|
||||
}[]
|
||||
) {
|
||||
await assertAdmin();
|
||||
await requireAdmin();
|
||||
|
||||
// Use Promise.all to update all questions concurrently
|
||||
await Promise.all(
|
||||
@@ -90,7 +86,7 @@ export async function bulkUpdateQuestions(
|
||||
db
|
||||
.update(questions)
|
||||
.set({
|
||||
label: u.label,
|
||||
label: sanitizeHtml(u.label),
|
||||
type: u.type,
|
||||
required: u.required,
|
||||
displayOrder: u.displayOrder,
|
||||
@@ -102,7 +98,7 @@ export async function bulkUpdateQuestions(
|
||||
);
|
||||
|
||||
revalidatePath("/form");
|
||||
revalidatePath("/form/admin");
|
||||
revalidatePath("/admin/form");
|
||||
}
|
||||
|
||||
async function deleteImageFile(imageUrl: string | null) {
|
||||
@@ -119,7 +115,7 @@ async function deleteImageFile(imageUrl: string | null) {
|
||||
}
|
||||
|
||||
export async function deleteQuestion(id: string, formId: string) {
|
||||
await assertAdmin();
|
||||
await requireAdmin();
|
||||
const q = await db.query.questions.findFirst({
|
||||
where: (q, { eq }) => eq(q.id, id),
|
||||
});
|
||||
@@ -128,14 +124,14 @@ export async function deleteQuestion(id: string, formId: string) {
|
||||
}
|
||||
await db.delete(questions).where(eq(questions.id, id));
|
||||
revalidatePath("/form");
|
||||
revalidatePath("/form/admin");
|
||||
revalidatePath(`/admin/form/${formId}`);
|
||||
}
|
||||
|
||||
export async function reorderQuestions(
|
||||
formId: string,
|
||||
orderedIds: string[]
|
||||
) {
|
||||
await assertAdmin();
|
||||
await requireAdmin();
|
||||
await Promise.all(
|
||||
orderedIds.map((id, index) =>
|
||||
db
|
||||
@@ -145,5 +141,5 @@ export async function reorderQuestions(
|
||||
)
|
||||
);
|
||||
revalidatePath("/form");
|
||||
revalidatePath("/form/admin");
|
||||
revalidatePath(`/admin/form/${formId}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user