feat: sanitize input for checklists
This commit is contained in:
@@ -4,6 +4,7 @@ import { z } from "zod";
|
|||||||
import * as cardRepo from "@kan/db/repository/card.repo";
|
import * as cardRepo from "@kan/db/repository/card.repo";
|
||||||
import * as cardActivityRepo from "@kan/db/repository/cardActivity.repo";
|
import * as cardActivityRepo from "@kan/db/repository/cardActivity.repo";
|
||||||
import * as checklistRepo from "@kan/db/repository/checklist.repo";
|
import * as checklistRepo from "@kan/db/repository/checklist.repo";
|
||||||
|
import { stripHtml } from "@kan/shared/utils";
|
||||||
|
|
||||||
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
||||||
import { assertPermission } from "../utils/permissions";
|
import { assertPermission } from "../utils/permissions";
|
||||||
@@ -223,7 +224,7 @@ export const checklistRouter = createTRPCRouter({
|
|||||||
.input(
|
.input(
|
||||||
z.object({
|
z.object({
|
||||||
checklistPublicId: z.string().length(12),
|
checklistPublicId: z.string().length(12),
|
||||||
title: z.string().min(1).max(500),
|
title: z.string().min(1).max(500).transform(stripHtml),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.output(checklistItemSchema)
|
.output(checklistItemSchema)
|
||||||
@@ -288,7 +289,7 @@ export const checklistRouter = createTRPCRouter({
|
|||||||
.input(
|
.input(
|
||||||
z.object({
|
z.object({
|
||||||
checklistItemPublicId: z.string().length(12),
|
checklistItemPublicId: z.string().length(12),
|
||||||
title: z.string().min(1).max(500).optional(),
|
title: z.string().min(1).max(500).transform(stripHtml).optional(),
|
||||||
completed: z.boolean().optional(),
|
completed: z.boolean().optional(),
|
||||||
index: z.number().int().min(0).optional(),
|
index: z.number().int().min(0).optional(),
|
||||||
}),
|
}),
|
||||||
@@ -322,30 +323,29 @@ export const checklistRouter = createTRPCRouter({
|
|||||||
|
|
||||||
const previousTitle = item.title;
|
const previousTitle = item.title;
|
||||||
|
|
||||||
let updatedItem;
|
let updatedItem;
|
||||||
|
|
||||||
if (input.title !== undefined || input.completed !== undefined) {
|
if (input.title !== undefined || input.completed !== undefined) {
|
||||||
updatedItem = await checklistRepo.updateItemById(ctx.db, {
|
updatedItem = await checklistRepo.updateItemById(ctx.db, {
|
||||||
id: item.id,
|
id: item.id,
|
||||||
title: input.title,
|
title: input.title,
|
||||||
completed: input.completed,
|
completed: input.completed,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input.index !== undefined) {
|
if (input.index !== undefined) {
|
||||||
updatedItem = await checklistRepo.reorderItem(ctx.db, {
|
updatedItem = await checklistRepo.reorderItem(ctx.db, {
|
||||||
itemId: item.id,
|
itemId: item.id,
|
||||||
newIndex: input.index,
|
newIndex: input.index,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!updatedItem) {
|
|
||||||
throw new TRPCError({
|
|
||||||
message: `Failed to update checklist item`,
|
|
||||||
code: "INTERNAL_SERVER_ERROR",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (!updatedItem) {
|
||||||
|
throw new TRPCError({
|
||||||
|
message: `Failed to update checklist item`,
|
||||||
|
code: "INTERNAL_SERVER_ERROR",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Log completion toggle
|
// Log completion toggle
|
||||||
if (input.completed !== undefined) {
|
if (input.completed !== undefined) {
|
||||||
@@ -371,7 +371,6 @@ export const checklistRouter = createTRPCRouter({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return updatedItem;
|
return updatedItem;
|
||||||
|
|
||||||
}),
|
}),
|
||||||
deleteItem: protectedProcedure
|
deleteItem: protectedProcedure
|
||||||
.meta({
|
.meta({
|
||||||
|
|||||||
@@ -5,3 +5,4 @@ export * from "./email";
|
|||||||
export * from "./dueDateFilters";
|
export * from "./dueDateFilters";
|
||||||
export * from "./s3";
|
export * from "./s3";
|
||||||
export * from "./mentions";
|
export * from "./mentions";
|
||||||
|
export * from "./sanitize";
|
||||||
|
|||||||
6
packages/shared/src/utils/sanitize.ts
Normal file
6
packages/shared/src/utils/sanitize.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* Strips all HTML tags from a string, returning plain text.
|
||||||
|
* Use this on any user-supplied text field before storing or displaying.
|
||||||
|
*/
|
||||||
|
export const stripHtml = (value: string): string =>
|
||||||
|
value.replace(/<[^>]*>/g, "").trim();
|
||||||
Reference in New Issue
Block a user