From 71e488cc2b193917d281e2caaf03f3f9f8d67089 Mon Sep 17 00:00:00 2001 From: monsieurswag Date: Wed, 5 Jun 2024 17:53:57 +0200 Subject: [PATCH 1/4] Fix non filtered next redirection Formatter --- frontend/src/lib/components/Forms/ModelForm.svelte | 3 ++- frontend/src/lib/utils/helpers.ts | 5 +++++ .../(app)/[model=urlmodel]/[id=uuid]/edit/+layout.server.ts | 4 +++- .../(app)/[model=urlmodel]/[id=uuid]/edit/+page.server.ts | 4 +++- .../(app)/requirement-assessments/[id=uuid]/+page.server.ts | 3 ++- .../(app)/requirement-assessments/[id=uuid]/+page.svelte | 3 ++- .../routes/(app)/risk-scenarios/[id=uuid]/edit/+page.svelte | 5 +++-- .../src/routes/(app)/users/[id=uuid]/edit/+page.server.ts | 6 +++++- frontend/src/routes/(authentication)/login/+page.server.ts | 5 +++-- 9 files changed, 28 insertions(+), 10 deletions(-) diff --git a/frontend/src/lib/components/Forms/ModelForm.svelte b/frontend/src/lib/components/Forms/ModelForm.svelte index 7f79c8e14..e9b80346b 100644 --- a/frontend/src/lib/components/Forms/ModelForm.svelte +++ b/frontend/src/lib/components/Forms/ModelForm.svelte @@ -20,6 +20,7 @@ import { page } from '$app/stores'; import * as m from '$paraglide/messages.js'; import { zod } from 'sveltekit-superforms/adapters'; + import { getSecureRedirect } from '$lib/utils/helpers'; export let form: SuperValidated; export let model: ModelInfo; @@ -36,7 +37,7 @@ if (browser) { var currentUrl = window.location.href; var url = new URL(currentUrl); - var nextValue = url.searchParams.get('next'); + var nextValue = getSecureRedirect(url.searchParams.get('next')); if (nextValue) window.location.href = nextValue; } } diff --git a/frontend/src/lib/utils/helpers.ts b/frontend/src/lib/utils/helpers.ts index 6cedab306..f5e8b695e 100644 --- a/frontend/src/lib/utils/helpers.ts +++ b/frontend/src/lib/utils/helpers.ts @@ -43,3 +43,8 @@ export function formatScoreValue(value: number, max_score: number) { } return (value * 100) / max_score; } + +export function getSecureRedirect(url: any): string { + const SECURE_REDIRECT_URL_REGEX = /^\/(?!.*\/\/)[^\s]*$/; + return typeof url === 'string' && SECURE_REDIRECT_URL_REGEX.test(url) ? url : ''; +} diff --git a/frontend/src/routes/(app)/[model=urlmodel]/[id=uuid]/edit/+layout.server.ts b/frontend/src/routes/(app)/[model=urlmodel]/[id=uuid]/edit/+layout.server.ts index 063d5075f..8c145d9dd 100644 --- a/frontend/src/routes/(app)/[model=urlmodel]/[id=uuid]/edit/+layout.server.ts +++ b/frontend/src/routes/(app)/[model=urlmodel]/[id=uuid]/edit/+layout.server.ts @@ -1,5 +1,6 @@ import { superValidate } from 'sveltekit-superforms'; import type { LayoutServerLoad } from './$types'; +import { getSecureRedirect } from '$lib/utils/helpers'; import { redirect } from '@sveltejs/kit'; import { setFlash } from 'sveltekit-flash-message/server'; import { BASE_API_URL } from '$lib/utils/constants'; @@ -35,7 +36,8 @@ export const load: LayoutServerLoad = async (event) => { ); throw redirect( 302, - event.url.searchParams.get('next') || `/${model.urlModel}/${riskAcceptance.id}` + getSecureRedirect(event.url.searchParams.get('next')) || + `/${model.urlModel}/${riskAcceptance.id}` ); } } diff --git a/frontend/src/routes/(app)/[model=urlmodel]/[id=uuid]/edit/+page.server.ts b/frontend/src/routes/(app)/[model=urlmodel]/[id=uuid]/edit/+page.server.ts index acf9a9b47..32dfd5f5a 100644 --- a/frontend/src/routes/(app)/[model=urlmodel]/[id=uuid]/edit/+page.server.ts +++ b/frontend/src/routes/(app)/[model=urlmodel]/[id=uuid]/edit/+page.server.ts @@ -4,6 +4,7 @@ import { fail, type Actions } from '@sveltejs/kit'; import { setError, superValidate } from 'sveltekit-superforms'; import { setFlash } from 'sveltekit-flash-message/server'; import { urlParamModelVerboseName } from '$lib/utils/crud'; +import { getSecureRedirect } from '$lib/utils/helpers'; import { redirect } from '@sveltejs/kit'; import { localItems, toCamelCase } from '$lib/utils/locales'; @@ -101,7 +102,8 @@ export const actions: Actions = { ); redirect( 302, - event.url.searchParams.get('next') ?? `/${event.params.model}/${event.params.id}` + getSecureRedirect(event.url.searchParams.get('next')) ?? + `/${event.params.model}/${event.params.id}` ); } }; diff --git a/frontend/src/routes/(app)/requirement-assessments/[id=uuid]/+page.server.ts b/frontend/src/routes/(app)/requirement-assessments/[id=uuid]/+page.server.ts index e9ea2f7e2..922ecbc75 100644 --- a/frontend/src/routes/(app)/requirement-assessments/[id=uuid]/+page.server.ts +++ b/frontend/src/routes/(app)/requirement-assessments/[id=uuid]/+page.server.ts @@ -8,6 +8,7 @@ import * as m from '$paraglide/messages'; import { languageTag } from '$paraglide/runtime'; import { tableSourceMapper, type TableSource } from '@skeletonlabs/skeleton'; import type { Actions } from '@sveltejs/kit'; +import { getSecureRedirect } from '$lib/utils/helpers'; import { fail, redirect } from '@sveltejs/kit'; import { setFlash } from 'sveltekit-flash-message/server'; import { setError, superValidate } from 'sveltekit-superforms'; @@ -259,7 +260,7 @@ export const actions: Actions = { setFlash({ type: 'success', message: m.successfullySavedObject({ object: model }) }, event); redirect( 302, - event.url.searchParams.get('next') || + getSecureRedirect(event.url.searchParams.get('next')) || `/compliance-assessments/${object.compliance_assessment}/` ); }, diff --git a/frontend/src/routes/(app)/requirement-assessments/[id=uuid]/+page.svelte b/frontend/src/routes/(app)/requirement-assessments/[id=uuid]/+page.svelte index 22f2accb2..603fb1f66 100644 --- a/frontend/src/routes/(app)/requirement-assessments/[id=uuid]/+page.svelte +++ b/frontend/src/routes/(app)/requirement-assessments/[id=uuid]/+page.svelte @@ -20,6 +20,7 @@ import CreateModal from '$lib/components/Modals/CreateModal.svelte'; import ModelTable from '$lib/components/ModelTable/ModelTable.svelte'; import { getOptions } from '$lib/utils/crud'; + import { getSecureRedirect } from '$lib/utils/helpers'; import { breadcrumbObject } from '$lib/utils/stores'; import { getModalStore, @@ -43,7 +44,7 @@ function cancel(): void { var currentUrl = window.location.href; var url = new URL(currentUrl); - var nextValue = url.searchParams.get('next'); + var nextValue = getSecureRedirect(url.searchParams.get('next')); if (nextValue) window.location.href = nextValue; } diff --git a/frontend/src/routes/(app)/risk-scenarios/[id=uuid]/edit/+page.svelte b/frontend/src/routes/(app)/risk-scenarios/[id=uuid]/edit/+page.svelte index ffd35de14..1924a9f19 100644 --- a/frontend/src/routes/(app)/risk-scenarios/[id=uuid]/edit/+page.svelte +++ b/frontend/src/routes/(app)/risk-scenarios/[id=uuid]/edit/+page.svelte @@ -8,6 +8,7 @@ import ModelTable from '$lib/components/ModelTable/ModelTable.svelte'; import { getOptions } from '$lib/utils/crud'; import { modelSchema } from '$lib/utils/schemas'; + import { getSecureRedirect } from '$lib/utils/helpers'; import { getModalStore, getToastStore, @@ -52,7 +53,7 @@ if (browser) { var currentUrl = window.location.href; var url = new URL(currentUrl); - var nextValue = url.searchParams.get('next'); + var nextValue = getSecureRedirect(url.searchParams.get('next')); if (nextValue) window.location.href = nextValue; } } @@ -113,7 +114,7 @@ } )); } - const next = $page.url.searchParams.get('next'); + const next = getSecureRedirect($page.url.searchParams.get('next')); function riskColorMap() { let color_map = {}; diff --git a/frontend/src/routes/(app)/users/[id=uuid]/edit/+page.server.ts b/frontend/src/routes/(app)/users/[id=uuid]/edit/+page.server.ts index cb4f8b65d..96caa63fc 100644 --- a/frontend/src/routes/(app)/users/[id=uuid]/edit/+page.server.ts +++ b/frontend/src/routes/(app)/users/[id=uuid]/edit/+page.server.ts @@ -2,6 +2,7 @@ import { BASE_API_URL } from '$lib/utils/constants'; import { UserEditSchema } from '$lib/utils/schemas'; import { setError, superValidate } from 'sveltekit-superforms'; import type { PageServerLoad } from './$types'; +import { getSecureRedirect } from '$lib/utils/helpers'; import { redirect, fail, type Actions } from '@sveltejs/kit'; import { getModelInfo } from '$lib/utils/crud'; import { setFlash } from 'sveltekit-flash-message/server'; @@ -73,6 +74,9 @@ export const actions: Actions = { { type: 'success', message: m.successfullyUpdatedUser({ email: form.data.email }) }, event ); - redirect(302, event.url.searchParams.get('next') ?? `/users/${event.params.id}`); + redirect( + 302, + getSecureRedirect(event.url.searchParams.get('next')) ?? `/users/${event.params.id}` + ); } }; diff --git a/frontend/src/routes/(authentication)/login/+page.server.ts b/frontend/src/routes/(authentication)/login/+page.server.ts index 76623ddd5..1298ff17d 100644 --- a/frontend/src/routes/(authentication)/login/+page.server.ts +++ b/frontend/src/routes/(authentication)/login/+page.server.ts @@ -1,3 +1,5 @@ +import { getSecureRedirect } from '$lib/utils/helpers'; + import { fail, redirect, type Actions } from '@sveltejs/kit'; import { zod } from 'sveltekit-superforms/adapters'; import type { PageServerLoad } from './$types'; @@ -6,7 +8,6 @@ import { BASE_API_URL } from '$lib/utils/constants'; import { csrfToken } from '$lib/utils/csrf'; import { loginSchema } from '$lib/utils/schemas'; import { setError, superValidate } from 'sveltekit-superforms'; - export const load: PageServerLoad = async ({ request, locals }) => { // redirect user if already logged in if (locals.user) { @@ -63,6 +64,6 @@ export const actions: Actions = { secure: true }); - redirect(302, url.searchParams.get('next') || '/analytics'); + redirect(302, getSecureRedirect(url.searchParams.get('next')) || '/analytics'); } }; From 09df8d689931bf78e73f188a82bf21a29dbb3502 Mon Sep 17 00:00:00 2001 From: monsieurswag Date: Thu, 6 Jun 2024 17:31:11 +0200 Subject: [PATCH 2/4] Attempt to fix functional tests Remove useless comment --- frontend/messages/de.json | 2 +- frontend/messages/en.json | 2 +- frontend/messages/es.json | 2 +- frontend/messages/fr.json | 2 +- frontend/messages/it.json | 2 +- frontend/messages/nl.json | 2 +- frontend/messages/pt.json | 2 +- .../(app)/[model=urlmodel]/[id=uuid]/edit/+page.server.ts | 3 +-- .../(app)/requirement-assessments/[id=uuid]/+page.server.ts | 2 +- .../(app)/risk-scenarios/[id=uuid]/edit/+page.server.ts | 4 ++-- frontend/tests/utils/page-detail.ts | 4 +--- 11 files changed, 12 insertions(+), 15 deletions(-) diff --git a/frontend/messages/de.json b/frontend/messages/de.json index 4fac1d0f2..8827b5a55 100644 --- a/frontend/messages/de.json +++ b/frontend/messages/de.json @@ -460,7 +460,7 @@ "domainManager": "Domänen-Manager", "analyst": "Analyst", "successfullyCreatedObject": "Das {object} Objekt wurde erfolgreich erstellt", - "successfullyUpdatedObject": "Das {object} Objekt: {name} wurde erfolgreich aktualisiert", + "successfullyUpdatedObject": "Das {object} Objekt wurde erfolgreich aktualisiert", "successfullySavedObject": "Das {object} Objekt wurde erfolgreich gespeichert", "successfullyDeletedObject": "Das {object} Objekt wurde erfolgreich gelöscht", "successfullyDeletedLibrary": "Die Bibliothek wurde erfolgreich gelöscht", diff --git a/frontend/messages/en.json b/frontend/messages/en.json index 86a0394c4..14bfeda40 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -460,7 +460,7 @@ "domainManager": "Domain manager", "analyst": "Analyst", "successfullyCreatedObject": "The {object} object has been successfully created", - "successfullyUpdatedObject": "The {object} object: {name} has been successfully updated", + "successfullyUpdatedObject": "The {object} object has been successfully updated", "successfullySavedObject": "The {object} object has been successfully saved", "successfullyDeletedObject": "The {object} object has been successfully deleted", "successfullyDeletedLibrary": "The library has been successfully deleted", diff --git a/frontend/messages/es.json b/frontend/messages/es.json index 5857d54b0..4daa21381 100644 --- a/frontend/messages/es.json +++ b/frontend/messages/es.json @@ -460,7 +460,7 @@ "domainManager": "Gerente de dominio", "analyst": "Analista", "successfullyCreatedObject": "El objeto {object} se ha creado con éxito", - "successfullyUpdatedObject": "El objeto {object}: {name} se ha actualizado con éxito", + "successfullyUpdatedObject": "El objeto {object} se ha actualizado con éxito", "successfullySavedObject": "El objeto {object} se ha guardado con éxito", "successfullyDeletedObject": "El objeto {object} se ha eliminado con éxito", "successfullyDeletedLibrary": "La biblioteca se ha eliminado con éxito", diff --git a/frontend/messages/fr.json b/frontend/messages/fr.json index 3a5c3ed91..3b7053c16 100644 --- a/frontend/messages/fr.json +++ b/frontend/messages/fr.json @@ -460,7 +460,7 @@ "domainManager": "Gestionnaire de domaine", "analyst": "Analyste", "successfullyCreatedObject": "L'objet {object} a été créé avec succès", - "successfullyUpdatedObject": "L'objet {object}: {name} a été mis à jour avec succès", + "successfullyUpdatedObject": "L'objet {object} a été mis à jour avec succès", "successfullySavedObject": "L'objet {object} a été enregistré avec succès", "successfullyDeletedObject": "L'objet {object} a été supprimé avec succès", "successfullyDeletedLibrary": "La librairie a été supprimée avec succès", diff --git a/frontend/messages/it.json b/frontend/messages/it.json index 9cd9f51e7..a7e28a174 100644 --- a/frontend/messages/it.json +++ b/frontend/messages/it.json @@ -460,7 +460,7 @@ "domainManager": "Manager di dominio", "analyst": "Analista", "successfullyCreatedObject": "L'oggetto {object} è stato creato con successo", - "successfullyUpdatedObject": "L'oggetto {object}: {name} è stato aggiornato con successo", + "successfullyUpdatedObject": "L'oggetto {object} è stato aggiornato con successo", "successfullySavedObject": "L'oggetto {object} è stato salvato con successo", "successfullyDeletedObject": "L'oggetto {object} è stato eliminato con successo", "successfullyDeletedLibrary": "La biblioteca è stata eliminata con successo", diff --git a/frontend/messages/nl.json b/frontend/messages/nl.json index dd4b1553a..696a470ba 100644 --- a/frontend/messages/nl.json +++ b/frontend/messages/nl.json @@ -460,7 +460,7 @@ "domainManager": "Domeinbeheerder", "analyst": "Analist", "successfullyCreatedObject": "Het {object} object is succesvol aangemaakt", - "successfullyUpdatedObject": "Het {object} object: {name} is succesvol bijgewerkt", + "successfullyUpdatedObject": "Het {object} object is succesvol bijgewerkt", "successfullySavedObject": "Het {object} object is succesvol opgeslagen", "successfullyDeletedObject": "Het {object} object is succesvol verwijderd", "successfullyDeletedLibrary": "De bibliotheek is succesvol verwijderd", diff --git a/frontend/messages/pt.json b/frontend/messages/pt.json index e299d4f16..34dc93f79 100644 --- a/frontend/messages/pt.json +++ b/frontend/messages/pt.json @@ -460,7 +460,7 @@ "domainManager": "Gerente de domínio", "analyst": "Analista", "successfullyCreatedObject": "O objeto {object} foi criado com sucesso", - "successfullyUpdatedObject": "O objeto {object}: {name} foi atualizado com sucesso", + "successfullyUpdatedObject": "O objeto {object} foi atualizado com sucesso", "successfullySavedObject": "O objeto {object} foi salvo com sucesso", "successfullyDeletedObject": "O objeto {object} foi excluído com sucesso", "successfullyDeletedLibrary": "A biblioteca foi excluída com sucesso", diff --git a/frontend/src/routes/(app)/[model=urlmodel]/[id=uuid]/edit/+page.server.ts b/frontend/src/routes/(app)/[model=urlmodel]/[id=uuid]/edit/+page.server.ts index 32dfd5f5a..d90fa25d6 100644 --- a/frontend/src/routes/(app)/[model=urlmodel]/[id=uuid]/edit/+page.server.ts +++ b/frontend/src/routes/(app)/[model=urlmodel]/[id=uuid]/edit/+page.server.ts @@ -94,8 +94,7 @@ export const actions: Actions = { { type: 'success', message: m.successfullyUpdatedObject({ - object: localItems()[toCamelCase(modelVerboseName.toLowerCase())].toLowerCase(), - name: form.data.name + object: localItems()[toCamelCase(modelVerboseName.toLowerCase())].toLowerCase() }) }, event diff --git a/frontend/src/routes/(app)/requirement-assessments/[id=uuid]/+page.server.ts b/frontend/src/routes/(app)/requirement-assessments/[id=uuid]/+page.server.ts index 922ecbc75..5bd1f8e69 100644 --- a/frontend/src/routes/(app)/requirement-assessments/[id=uuid]/+page.server.ts +++ b/frontend/src/routes/(app)/requirement-assessments/[id=uuid]/+page.server.ts @@ -319,7 +319,7 @@ export const actions: Actions = { setFlash( { type: 'success', - message: m.successfullyUpdatedObject({ object: model, name: form.data.name }) + message: m.successfullyUpdatedObject({ object: model }) }, event ); diff --git a/frontend/src/routes/(app)/risk-scenarios/[id=uuid]/edit/+page.server.ts b/frontend/src/routes/(app)/risk-scenarios/[id=uuid]/edit/+page.server.ts index 4613d49bd..0624aad3b 100644 --- a/frontend/src/routes/(app)/risk-scenarios/[id=uuid]/edit/+page.server.ts +++ b/frontend/src/routes/(app)/risk-scenarios/[id=uuid]/edit/+page.server.ts @@ -223,7 +223,7 @@ export const actions: Actions = { setFlash( { type: 'success', - message: m.successfullyUpdatedObject({ object: modelVerboseName, name: form.data.name }) + message: m.successfullyUpdatedObject({ object: modelVerboseName }) }, event ); @@ -284,7 +284,7 @@ export const actions: Actions = { setFlash( { type: 'success', - message: m.successfullyUpdatedObject({ object: model, name: form.data.name }) + message: m.successfullyUpdatedObject({ object: model }) }, event ); diff --git a/frontend/tests/utils/page-detail.ts b/frontend/tests/utils/page-detail.ts index b022a5225..dec78557b 100644 --- a/frontend/tests/utils/page-detail.ts +++ b/frontend/tests/utils/page-detail.ts @@ -32,9 +32,7 @@ export class PageDetail extends BasePage { await this.form.saveButton.click(); await this.isToastVisible( - 'The .+: ' + - ({ ...buildParams, ...editedValues }.name || { ...buildParams, ...editedValues }.email) + - ' has been successfully updated' + 'The .+ object has been successfully updated' ); return editedValues; } From 89a50387bb844f74ebde62a3a1bd2d23e652db78 Mon Sep 17 00:00:00 2001 From: monsieurswag Date: Thu, 6 Jun 2024 17:44:41 +0200 Subject: [PATCH 3/4] Formatter --- frontend/tests/utils/page-detail.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frontend/tests/utils/page-detail.ts b/frontend/tests/utils/page-detail.ts index dec78557b..c3e06cdb5 100644 --- a/frontend/tests/utils/page-detail.ts +++ b/frontend/tests/utils/page-detail.ts @@ -31,9 +31,7 @@ export class PageDetail extends BasePage { await this.form.fill(editedValues); await this.form.saveButton.click(); - await this.isToastVisible( - 'The .+ object has been successfully updated' - ); + await this.isToastVisible('The .+ object has been successfully updated'); return editedValues; } From 165cb10716caacb597de581db19b2f9a695e9854 Mon Sep 17 00:00:00 2001 From: monsieurswag Date: Thu, 6 Jun 2024 18:19:57 +0200 Subject: [PATCH 4/4] Attempt to fix functional tests by making the toast detection more flexible --- frontend/tests/utils/page-detail.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/tests/utils/page-detail.ts b/frontend/tests/utils/page-detail.ts index c3e06cdb5..b82a5201f 100644 --- a/frontend/tests/utils/page-detail.ts +++ b/frontend/tests/utils/page-detail.ts @@ -31,7 +31,7 @@ export class PageDetail extends BasePage { await this.form.fill(editedValues); await this.form.saveButton.click(); - await this.isToastVisible('The .+ object has been successfully updated'); + await this.isToastVisible('The .+ has been successfully updated'); return editedValues; }