fix: cross site scripting with html content

This commit is contained in:
Rotimi Best
2025-12-03 09:33:53 +01:00
parent f2b719cd1b
commit 7b18c325da
15 changed files with 458 additions and 151 deletions
@@ -0,0 +1,26 @@
import type { RequestHandler } from './$types';
export const POST: RequestHandler = async ({ request }) => {
try {
const report = await request.json();
// Log the CSP violation for monitoring
console.warn('CSP Violation Report:', {
timestamp: new Date().toISOString(),
documentURI: report['document-uri'],
violatedDirective: report['violated-directive'],
blockedURI: report['blocked-uri'],
effectiveDirective: report['effective-directive'],
originalPolicy: report['original-policy'],
sourceFile: report['source-file'],
lineNumber: report['line-number'],
columnNumber: report['column-number'],
userAgent: request.headers.get('user-agent')
});
return new Response('OK', { status: 200 });
} catch (error) {
console.error('Error processing CSP report:', error);
return new Response('Bad Request', { status: 400 });
}
};
@@ -26,6 +26,7 @@
import { fetchCourses } from '$lib/utils/services/courses';
import { t } from '$lib/utils/functions/translations';
import { courses } from '$lib/components/Courses/store';
import { sanitizeHtml } from '$lib/utils/functions/sanitize';
import type { Course } from '$lib/utils/types';
export let data;
@@ -383,20 +384,21 @@
}}
onDelete={() => handleDelete(false)}
/>
<section class="max-w-3xl mx-auto md:mx-10 lg:mb-20">
<section class="mx-auto max-w-3xl md:mx-10 lg:mb-20">
sfgsggs
{#if !question}
<div class="py-10 px-5 mb-3">
<div class="mb-3 px-5 py-10">
<SkeletonText style="width: 25%;" />
<SkeletonText style="width: 100%; margin-bottom: 2rem" />
<SkeletonPlaceholder style="width: 100%; height: 20rem;" />
</div>
{:else}
<div class="py-10 px-5">
<a class="text-gray-500 dark:text-white text-md flex items-center" href={`/lms/community`}>
<div class="px-5 py-10">
<a class="text-md flex items-center text-gray-500 dark:text-white" href={`/lms/community`}>
<ArrowLeftIcon size={24} class="carbon-icon dark:text-white" />
{$t('community.ask.go_back')}
</a>
<div class="my-5 flex justify-between items-center">
<div class="my-5 flex items-center justify-between">
{#if isEditMode}
<TextField
bind:value={editContent.title}
@@ -404,7 +406,7 @@
errorMessage={errors.title}
/>
<Dropdown
class="w-[25%] h-full"
class="h-full w-[25%]"
size="xl"
label="Select Course"
items={fetchedCourses.map((course) => ({ id: course.id, text: course.title }))}
@@ -418,6 +420,7 @@
disabled={voted.question}
/>
<h2 class="text-3xl">{question.title}</h2>
sfgsg
</div>
{/if}
@@ -439,17 +442,18 @@
{/if}
{/if}
</div>
<div class="my-1 px-1 rounded-lg border border-1 border-gray">
<header class="flex items-center justify-between leading-none p-2">
<div class="flex items-center no-underline hover:underline text-black">
<div class="border-1 border-gray my-1 rounded-lg border px-1">
<header class="flex items-center justify-between p-2 leading-none">
<div class="flex items-center text-black no-underline hover:underline">
sfgsg
<Avatar
src={question.author.avatar}
name={question.author.name}
width="w-7"
height="h-7"
/>
<p class="dark:text-white ml-2 text-sm">{question.author.name}</p>
<p class="dark:text-white ml-2 text-sm text-gray-500">
<p class="ml-2 text-sm dark:text-white">{question.author.name}</p>
<p class="ml-2 text-sm text-gray-500 dark:text-white">
{question.createdAt}
</p>
</div>
@@ -475,7 +479,7 @@
</div>
{:else}
<section class="prose prose-sm sm:prose p-2">
{@html question.body}
{@html sanitizeHtml(question.body)}
</section>
{/if}
</div>
@@ -485,18 +489,18 @@
</div>
{#each question.comments as comment}
<div class="my-5 px-1 flex items-start">
<div class="my-5 flex items-start px-1">
<Vote
value={comment.votes}
upVote={() => upvoteQuestion('comment', comment.id)}
disabled={voted.comment[comment.id]}
/>
<div class="w-full rounded-lg border border-1 border-gray">
<header class="flex items-center justify-between leading-none p-2">
<div class="border-1 border-gray w-full rounded-lg border">
<header class="flex items-center justify-between p-2 leading-none">
<div class="flex items-center text-black">
<Avatar src={comment.avatar} name={comment.name} width="w-7" height="h-7" />
<p class="dark:text-white ml-2 text-sm">{comment.name}</p>
<p class="dark:text-white ml-2 text-sm text-gray-500">
<p class="ml-2 text-sm dark:text-white">{comment.name}</p>
<p class="ml-2 text-sm text-gray-500 dark:text-white">
{comment.createdAt}
</p>
</div>
@@ -518,7 +522,7 @@
{/if}
</header>
<article class="prose prose-sm sm:prose p-2">
{@html comment.comment}
{@html sanitizeHtml(comment.comment)}
</article>
</div>
</div>
@@ -535,7 +539,7 @@
/>
{/if}
<div class="flex justify-end mr-2">
<div class="mr-2 flex justify-end">
<PrimaryButton label="Comment" onClick={submitComment} />
</div>
</div>
@@ -19,6 +19,7 @@
commentInCommunityValidation
} from '$lib/utils/functions/validator';
import { fetchCourses } from '$lib/utils/services/courses';
import { sanitizeHtml } from '$lib/utils/functions/sanitize';
import { currentOrg, currentOrgPath, isOrgAdmin } from '$lib/utils/store/org';
import { profile } from '$lib/utils/store/user';
import type { Course } from '$lib/utils/types';
@@ -477,7 +478,7 @@
</div>
{:else}
<section class="prose prose-sm sm:prose p-2">
{@html question.body}
{@html sanitizeHtml(question.body)}
</section>
{/if}
</div>
@@ -520,7 +521,7 @@
{/if}
</header>
<article class="prose prose-sm sm:prose p-2">
{@html comment.comment}
{@html sanitizeHtml(comment.comment)}
</article>
</div>
</div>