From ba48122db6694804678f77b2e18ec0b0ce4d94ec Mon Sep 17 00:00:00 2001 From: monsieurswag Date: Thu, 3 Oct 2024 22:10:02 +0200 Subject: [PATCH 1/6] Prevent modal creation when mandatory objects are missing in nested tables --- .../components/DetailView/DetailView.svelte | 18 ++++++++++++++++-- frontend/src/lib/utils/crud.ts | 2 +- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/frontend/src/lib/components/DetailView/DetailView.svelte b/frontend/src/lib/components/DetailView/DetailView.svelte index 4abb82876..49bb037e7 100644 --- a/frontend/src/lib/components/DetailView/DetailView.svelte +++ b/frontend/src/lib/components/DetailView/DetailView.svelte @@ -3,6 +3,7 @@ import { page } from '$app/stores'; import ConfirmModal from '$lib/components/Modals/ConfirmModal.svelte'; import CreateModal from '$lib/components/Modals/CreateModal.svelte'; + import MissingConstraintsModal from '$lib/components/Modals/MissingConstraintsModal.svelte'; import ModelTable from '$lib/components/ModelTable/ModelTable.svelte'; import type { ModalComponent, @@ -17,6 +18,7 @@ import { URL_MODEL_MAP } from '$lib/utils/crud'; import { isURL } from '$lib/utils/helpers'; import { toCamelCase, capitalizeFirstLetter } from '$lib/utils/locales.js'; + import { checkConstraints } from '$lib/utils/crud'; import { languageTag } from '$paraglide/runtime.js'; import * as m from '$paraglide/messages.js'; import { ISO_8601_REGEX } from '$lib/utils/constants'; @@ -69,7 +71,7 @@ } function modalCreateForm(model: Record): void { - const modalComponent: ModalComponent = { + let modalComponent: ModalComponent = { ref: CreateModal, props: { form: model.createForm, @@ -77,12 +79,24 @@ debug: false } }; - const modal: ModalSettings = { + let modal: ModalSettings = { type: 'component', component: modalComponent, // Data title: safeTranslate('add' + capitalizeFirstLetter(model.info.localName)) }; + if (checkConstraints(model.createForm.constraints, model.foreignKeys).length > 0) { + modalComponent = { + ref: MissingConstraintsModal + }; + modal = { + type: 'component', + component: modalComponent, + title: m.warning(), + body: safeTranslate('add' + capitalizeFirstLetter(model.info.localName)).toLowerCase(), + value: checkConstraints(model.createForm.constraints, model.foreignKeys) + }; + } modalStore.trigger(modal); } diff --git a/frontend/src/lib/utils/crud.ts b/frontend/src/lib/utils/crud.ts index 69f532efe..5bf91c559 100644 --- a/frontend/src/lib/utils/crud.ts +++ b/frontend/src/lib/utils/crud.ts @@ -17,7 +17,7 @@ type GetOptionsParams = { selfSelect?: boolean; }; -export function checkConstraints(constraints: { [key: string]: any }, foreignKeys: any) { +export function checkConstraints(constraints: { [key: string]: any }, foreignKeys: any): string[] { const emptyConstraintsList = []; for (const [key, constraint] of Object.entries(constraints)) { if (constraint.required && foreignKeys[key]) From 06304dd77f5576fee5ab983139ffe07b73e7b0fd Mon Sep 17 00:00:00 2001 From: monsieurswag Date: Thu, 3 Oct 2024 22:26:40 +0200 Subject: [PATCH 2/6] Modify the evidence file stream behavior to stop reading when being terminated by the client Fix useless code --- .../evidences/[id=uuid]/attachment/+server.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/frontend/src/routes/(app)/(third-party)/evidences/[id=uuid]/attachment/+server.ts b/frontend/src/routes/(app)/(third-party)/evidences/[id=uuid]/attachment/+server.ts index ed87e123c..9ac07bd10 100644 --- a/frontend/src/routes/(app)/(third-party)/evidences/[id=uuid]/attachment/+server.ts +++ b/frontend/src/routes/(app)/(third-party)/evidences/[id=uuid]/attachment/+server.ts @@ -29,9 +29,13 @@ export const GET: RequestHandler = async ({ fetch, setHeaders, params }) => { } const reader = attachmentResponse.body.getReader(); + let readerTerminated = false; const stream = new ReadableStream({ start(controller) { function push() { + if (readerTerminated) { + return; + } reader.read().then(({ done, value }) => { if (done) { controller.close(); @@ -42,6 +46,9 @@ export const GET: RequestHandler = async ({ fetch, setHeaders, params }) => { }); } push(); + }, + cancel() { + readerTerminated = true; } }); From 2703077d1bf1df08fddfb641af028f8826afbd51 Mon Sep 17 00:00:00 2001 From: eric-intuitem <71850047+eric-intuitem@users.noreply.github.com> Date: Fri, 4 Oct 2024 20:43:57 +0200 Subject: [PATCH 3/6] improve redirect --- frontend/src/lib/utils/helpers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/lib/utils/helpers.ts b/frontend/src/lib/utils/helpers.ts index 367b679f1..e40ce9e98 100644 --- a/frontend/src/lib/utils/helpers.ts +++ b/frontend/src/lib/utils/helpers.ts @@ -60,7 +60,7 @@ export function formatScoreValue(value: number, max_score: number, fullDonut = f } export function getSecureRedirect(url: any): string { - const SECURE_REDIRECT_URL_REGEX = /^\/(?!.*\/\/)[^\s]*$/; + const SECURE_REDIRECT_URL_REGEX = /^\/[^/]/; return typeof url === 'string' && SECURE_REDIRECT_URL_REGEX.test(url) ? url : ''; } From 2916138f63ef7bb97bdbdcbd634e54717e0010a3 Mon Sep 17 00:00:00 2001 From: monsieurswag Date: Mon, 7 Oct 2024 11:21:43 +0200 Subject: [PATCH 4/6] Fix the AutoCompleteSelect value filling for evidences attached to a requirement assessment Formatter --- .../[id=uuid]/edit/+page.server.ts | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/frontend/src/routes/(app)/(internal)/requirement-assessments/[id=uuid]/edit/+page.server.ts b/frontend/src/routes/(app)/(internal)/requirement-assessments/[id=uuid]/edit/+page.server.ts index a6f9d3e3f..599538c38 100644 --- a/frontend/src/routes/(app)/(internal)/requirement-assessments/[id=uuid]/edit/+page.server.ts +++ b/frontend/src/routes/(app)/(internal)/requirement-assessments/[id=uuid]/edit/+page.server.ts @@ -10,7 +10,7 @@ import { tableSourceMapper, type TableSource } from '@skeletonlabs/skeleton'; import type { Actions } from '@sveltejs/kit'; import { fail, redirect } from '@sveltejs/kit'; import { setFlash } from 'sveltekit-flash-message/server'; -import { setError, superValidate } from 'sveltekit-superforms'; +import { superValidate } from 'sveltekit-superforms'; import { zod } from 'sveltekit-superforms/adapters'; import type { PageServerLoad } from './$types'; import { z } from 'zod'; @@ -43,6 +43,7 @@ export const load = (async ({ fetch, params }) => { } const schema = modelSchema(URLModel); + object.evidences = object.evidences.map((evidence) => evidence.id); const form = await superValidate(object, zod(schema), { errors: true }); const foreignKeys: Record = {}; @@ -116,24 +117,27 @@ export const load = (async ({ fetch, params }) => { const tables: Record = {}; - for (const key of ['applied-controls', 'evidences'] as urlModel[]) { - const keyEndpoint = `${BASE_API_URL}/${key}/?requirement_assessments=${params.id}`; - const response = await fetch(keyEndpoint); - if (response.ok) { - const data = await response.json().then((data) => data.results); + await Promise.all( + ['applied-controls', 'evidences'].map(async (key) => { + const keyEndpoint = `${BASE_API_URL}/${key}/?requirement_assessments=${params.id}`; + const response = await fetch(keyEndpoint); - const bodyData = tableSourceMapper(data, listViewFields[key].body); + if (response.ok) { + const data = await response.json().then((data) => data.results); - const table: TableSource = { - head: listViewFields[key].head, - body: bodyData, - meta: data - }; - tables[key] = table; - } else { - console.error(`Failed to fetch data for ${key}: ${response.statusText}`); - } - } + const bodyData = tableSourceMapper(data, listViewFields[key].body); + + const table: TableSource = { + head: listViewFields[key].head, + body: bodyData, + meta: data + }; + tables[key] = table; + } else { + console.error(`Failed to fetch data for ${key}: ${response.statusText}`); + } + }) + ); const measureForeignKeys: Record = {}; From 4544fe142945d060471c9d277f62aa41f467b9a7 Mon Sep 17 00:00:00 2001 From: monsieurswag Date: Mon, 7 Oct 2024 12:19:13 +0200 Subject: [PATCH 5/6] Stop storelibraries command on SIGINT Formatter --- backend/library/management/commands/storelibraries.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/library/management/commands/storelibraries.py b/backend/library/management/commands/storelibraries.py index 4ac126240..617c74877 100644 --- a/backend/library/management/commands/storelibraries.py +++ b/backend/library/management/commands/storelibraries.py @@ -1,12 +1,14 @@ from pathlib import Path -import structlog +import structlog, signal from ciso_assistant.settings import LIBRARIES_PATH from core.models import StoredLibrary from django.core.management.base import BaseCommand logger = structlog.getLogger(__name__) +signal.signal(signal.SIGINT, signal.SIG_DFL) + class Command(BaseCommand): help = "Store libraries in the database" From 7b80cff9c0581322d333d65542552b6e02a9c179 Mon Sep 17 00:00:00 2001 From: Nassim Tabchiche Date: Tue, 8 Oct 2024 14:11:04 +0200 Subject: [PATCH 6/6] Mitigate open redirect --- frontend/src/lib/utils/helpers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/lib/utils/helpers.ts b/frontend/src/lib/utils/helpers.ts index e40ce9e98..63a830557 100644 --- a/frontend/src/lib/utils/helpers.ts +++ b/frontend/src/lib/utils/helpers.ts @@ -60,7 +60,7 @@ export function formatScoreValue(value: number, max_score: number, fullDonut = f } export function getSecureRedirect(url: any): string { - const SECURE_REDIRECT_URL_REGEX = /^\/[^/]/; + const SECURE_REDIRECT_URL_REGEX = /^\/\w+/; return typeof url === 'string' && SECURE_REDIRECT_URL_REGEX.test(url) ? url : ''; }