From a7e26531e529c042822f94ac8ab07a8c0b2cdff3 Mon Sep 17 00:00:00 2001 From: stijnpotters Date: Mon, 15 Jun 2026 12:07:42 +0200 Subject: [PATCH 1/6] Add /build to .gitignore to exclude build artifacts --- src/main/frontend/.gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/frontend/.gitignore b/src/main/frontend/.gitignore index c65a0878..fc091fc6 100644 --- a/src/main/frontend/.gitignore +++ b/src/main/frontend/.gitignore @@ -9,3 +9,5 @@ /.env /.env.production /.env.development + +/build From eb723b40c086b2c5a24752861f246d4115bf465a Mon Sep 17 00:00:00 2001 From: stijnpotters Date: Mon, 15 Jun 2026 12:52:28 +0200 Subject: [PATCH 2/6] Update development environment configuration and enhance security settings --- src/main/frontend/environment/development.ts | 2 +- src/main/frontend/vite.config.ts | 3 ++ .../flow/common/config/CsrfCookieFilter.java | 32 +++++++++++++++++++ .../config/SecurityChainConfigurer.java | 6 ++++ 4 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/frankframework/flow/common/config/CsrfCookieFilter.java diff --git a/src/main/frontend/environment/development.ts b/src/main/frontend/environment/development.ts index 50d445be..9796d233 100644 --- a/src/main/frontend/environment/development.ts +++ b/src/main/frontend/environment/development.ts @@ -2,7 +2,7 @@ import base, { type EnvironmentVariables } from './base' const development: EnvironmentVariables = { ...base, - apiBaseUrl: 'http://localhost:8080', + apiBaseUrl: '', } export default development diff --git a/src/main/frontend/vite.config.ts b/src/main/frontend/vite.config.ts index 80d9c0f3..6260d8f4 100644 --- a/src/main/frontend/vite.config.ts +++ b/src/main/frontend/vite.config.ts @@ -28,5 +28,8 @@ export default defineConfig({ }, server: { port: 3000, + proxy: { + '/api': 'http://localhost:8080', + }, }, }) diff --git a/src/main/java/org/frankframework/flow/common/config/CsrfCookieFilter.java b/src/main/java/org/frankframework/flow/common/config/CsrfCookieFilter.java new file mode 100644 index 00000000..78758233 --- /dev/null +++ b/src/main/java/org/frankframework/flow/common/config/CsrfCookieFilter.java @@ -0,0 +1,32 @@ +package org.frankframework.flow.common.config; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import org.jspecify.annotations.NonNull; +import org.springframework.security.web.csrf.CsrfToken; +import org.springframework.web.filter.OncePerRequestFilter; + +/** + * Forces the deferred {@link CsrfToken} to load on every request so the XSRF-TOKEN cookie is + * written. Otherwise the cookie is only minted when something reads the token, leaving a SPA with no + * token to echo back as X-XSRF-TOKEN. + */ +public class CsrfCookieFilter extends OncePerRequestFilter { + + @Override + protected void doFilterInternal( + @NonNull HttpServletRequest request, + @NonNull HttpServletResponse response, + @NonNull FilterChain filterChain + ) throws ServletException, IOException { + CsrfToken csrfToken = (CsrfToken) request.getAttribute(CsrfToken.class.getName()); + if (csrfToken != null) { + csrfToken.getToken(); + } + + filterChain.doFilter(request, response); + } +} diff --git a/src/main/java/org/frankframework/flow/common/config/SecurityChainConfigurer.java b/src/main/java/org/frankframework/flow/common/config/SecurityChainConfigurer.java index d1084c00..87659b4c 100644 --- a/src/main/java/org/frankframework/flow/common/config/SecurityChainConfigurer.java +++ b/src/main/java/org/frankframework/flow/common/config/SecurityChainConfigurer.java @@ -23,6 +23,7 @@ import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.csrf.CookieCsrfTokenRepository; +import org.springframework.security.web.csrf.CsrfFilter; import org.springframework.security.web.util.matcher.AnyRequestMatcher; @Configuration @@ -61,6 +62,11 @@ public SecurityFilterChain configureChain(IAuthenticator authenticator, HttpSecu http.formLogin(FormLoginConfigurer::disable); http.logout(LogoutConfigurer::disable); http.sessionManagement(management -> management.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)); + + if (csrfEnabled) { + http.addFilterAfter(new CsrfCookieFilter(), CsrfFilter.class); + } + return authenticator.configureHttpSecurity(http); } From 280d3b8fc426acb3231458bb2bb1c967855b281e Mon Sep 17 00:00:00 2001 From: stijnpotters Date: Mon, 15 Jun 2026 13:24:06 +0200 Subject: [PATCH 3/6] Refactor API URL handling and improve CSRF configuration --- src/main/frontend/.gitignore | 2 -- src/main/frontend/app/utils/api.ts | 4 +-- src/main/frontend/environment/base.ts | 9 ------ src/main/frontend/environment/development.ts | 8 ----- src/main/frontend/environment/environment.ts | 9 ------ src/main/frontend/environment/production.ts | 7 ----- .../config/SecurityChainConfigurer.java | 29 ++++++++++--------- 7 files changed, 17 insertions(+), 51 deletions(-) delete mode 100644 src/main/frontend/environment/base.ts delete mode 100644 src/main/frontend/environment/development.ts delete mode 100644 src/main/frontend/environment/environment.ts delete mode 100644 src/main/frontend/environment/production.ts diff --git a/src/main/frontend/.gitignore b/src/main/frontend/.gitignore index fc091fc6..c65a0878 100644 --- a/src/main/frontend/.gitignore +++ b/src/main/frontend/.gitignore @@ -9,5 +9,3 @@ /.env /.env.production /.env.development - -/build diff --git a/src/main/frontend/app/utils/api.ts b/src/main/frontend/app/utils/api.ts index 3279a424..888e5994 100644 --- a/src/main/frontend/app/utils/api.ts +++ b/src/main/frontend/app/utils/api.ts @@ -1,7 +1,5 @@ -import variables from '../../environment/environment' - export function apiUrl(path: string): string { - return `${variables.apiBaseUrl}/api${path}` + return `/api${path}` } const getAnonymousSessionId = () => { diff --git a/src/main/frontend/environment/base.ts b/src/main/frontend/environment/base.ts deleted file mode 100644 index 299efc10..00000000 --- a/src/main/frontend/environment/base.ts +++ /dev/null @@ -1,9 +0,0 @@ -export interface EnvironmentVariables { - apiBaseUrl: string -} - -const base: EnvironmentVariables = { - apiBaseUrl: '', -} - -export default base diff --git a/src/main/frontend/environment/development.ts b/src/main/frontend/environment/development.ts deleted file mode 100644 index 9796d233..00000000 --- a/src/main/frontend/environment/development.ts +++ /dev/null @@ -1,8 +0,0 @@ -import base, { type EnvironmentVariables } from './base' - -const development: EnvironmentVariables = { - ...base, - apiBaseUrl: '', -} - -export default development diff --git a/src/main/frontend/environment/environment.ts b/src/main/frontend/environment/environment.ts deleted file mode 100644 index e42c2d24..00000000 --- a/src/main/frontend/environment/environment.ts +++ /dev/null @@ -1,9 +0,0 @@ -import development from './development' -import production from './production' -import type { EnvironmentVariables } from './base' - -const environment = process.env.NODE_ENV - -const variables: EnvironmentVariables = environment === 'development' ? development : production - -export default variables diff --git a/src/main/frontend/environment/production.ts b/src/main/frontend/environment/production.ts deleted file mode 100644 index 71565e0a..00000000 --- a/src/main/frontend/environment/production.ts +++ /dev/null @@ -1,7 +0,0 @@ -import base, { type EnvironmentVariables } from './base' - -const production: EnvironmentVariables = { - ...base, -} - -export default production diff --git a/src/main/java/org/frankframework/flow/common/config/SecurityChainConfigurer.java b/src/main/java/org/frankframework/flow/common/config/SecurityChainConfigurer.java index 87659b4c..96d1f8db 100644 --- a/src/main/java/org/frankframework/flow/common/config/SecurityChainConfigurer.java +++ b/src/main/java/org/frankframework/flow/common/config/SecurityChainConfigurer.java @@ -17,6 +17,7 @@ import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer; import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer; import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer; @@ -50,23 +51,11 @@ public void setEnvironment(Environment environment) { public SecurityFilterChain configureChain(IAuthenticator authenticator, HttpSecurity http) throws Exception { configureAuthenticator(authenticator); http.headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin)); - http.csrf(csrf -> { - if (csrfEnabled) { - csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()); - csrf.csrfTokenRequestHandler(new SpaCsrfTokenRequestHandler()); - return; - } - csrf.disable(); - }); + configureCsrf(http); http.securityMatcher(AnyRequestMatcher.INSTANCE); http.formLogin(FormLoginConfigurer::disable); http.logout(LogoutConfigurer::disable); http.sessionManagement(management -> management.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)); - - if (csrfEnabled) { - http.addFilterAfter(new CsrfCookieFilter(), CsrfFilter.class); - } - return authenticator.configureHttpSecurity(http); } @@ -81,4 +70,18 @@ private void configureAuthenticator(IAuthenticator authenticator) { servletConfig.setUrlMapping("/*"); authenticator.registerServlet(servletConfig); } + + private void configureCsrf(HttpSecurity http) { + if (!csrfEnabled) { + http.csrf(AbstractHttpConfigurer::disable); + return; + } + + http.csrf(csrf -> { + csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()); + csrf.csrfTokenRequestHandler(new SpaCsrfTokenRequestHandler()); + }); + + http.addFilterAfter(new CsrfCookieFilter(), CsrfFilter.class); + } } From 299237f21d3fa8f80cd37c105d7ed3842414f0bd Mon Sep 17 00:00:00 2001 From: stijnpotters Date: Tue, 2 Jun 2026 15:58:41 +0200 Subject: [PATCH 4/6] Enhance node components with improved shadow effects for better visual depth --- .../app/routes/studio/canvas/nodetypes/child-node.tsx | 4 ++-- .../frontend/app/routes/studio/canvas/nodetypes/exit-node.tsx | 2 +- .../app/routes/studio/canvas/nodetypes/frank-node.tsx | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/frontend/app/routes/studio/canvas/nodetypes/child-node.tsx b/src/main/frontend/app/routes/studio/canvas/nodetypes/child-node.tsx index c9a6905e..718a2927 100644 --- a/src/main/frontend/app/routes/studio/canvas/nodetypes/child-node.tsx +++ b/src/main/frontend/app/routes/studio/canvas/nodetypes/child-node.tsx @@ -159,7 +159,7 @@ export function ChildNodeComponent({
{/* Body */} -
+
{child.attributes && Object.entries(child.attributes).map(([key, value]) => (
diff --git a/src/main/frontend/app/routes/studio/canvas/nodetypes/exit-node.tsx b/src/main/frontend/app/routes/studio/canvas/nodetypes/exit-node.tsx index 330c76a7..36737b49 100644 --- a/src/main/frontend/app/routes/studio/canvas/nodetypes/exit-node.tsx +++ b/src/main/frontend/app/routes/studio/canvas/nodetypes/exit-node.tsx @@ -30,7 +30,7 @@ export default function ExitNodeComponent(properties: NodeProps) {
) {
) { ))} {(properties.data.children.length > 0 || dragOver || canDropDraggedElement) && (
-
+
{properties.data.children.map((child) => (
Date: Wed, 3 Jun 2026 11:11:40 +0200 Subject: [PATCH 5/6] Refactor shadow effects in node components for improved visual consistency --- .../app/routes/studio/canvas/nodetypes/child-node.tsx | 4 ++-- .../frontend/app/routes/studio/canvas/nodetypes/exit-node.tsx | 2 +- .../app/routes/studio/canvas/nodetypes/frank-node.tsx | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/frontend/app/routes/studio/canvas/nodetypes/child-node.tsx b/src/main/frontend/app/routes/studio/canvas/nodetypes/child-node.tsx index 718a2927..377a2cd5 100644 --- a/src/main/frontend/app/routes/studio/canvas/nodetypes/child-node.tsx +++ b/src/main/frontend/app/routes/studio/canvas/nodetypes/child-node.tsx @@ -159,7 +159,7 @@ export function ChildNodeComponent({
{/* Body */} -
+
{child.attributes && Object.entries(child.attributes).map(([key, value]) => (
diff --git a/src/main/frontend/app/routes/studio/canvas/nodetypes/exit-node.tsx b/src/main/frontend/app/routes/studio/canvas/nodetypes/exit-node.tsx index 36737b49..bb665a83 100644 --- a/src/main/frontend/app/routes/studio/canvas/nodetypes/exit-node.tsx +++ b/src/main/frontend/app/routes/studio/canvas/nodetypes/exit-node.tsx @@ -30,7 +30,7 @@ export default function ExitNodeComponent(properties: NodeProps) {
) {
) { ))} {(properties.data.children.length > 0 || dragOver || canDropDraggedElement) && (
-
+
{properties.data.children.map((child) => (
Date: Mon, 15 Jun 2026 14:30:05 +0200 Subject: [PATCH 6/6] Refactor shadow effects in various node components for improved visual consistency --- .../app/routes/configurations/configuration-file-tile.tsx | 6 +++--- .../app/routes/studio/canvas/nodetypes/child-node.tsx | 2 +- .../app/routes/studio/canvas/nodetypes/exit-node.tsx | 2 +- .../app/routes/studio/canvas/nodetypes/frank-node.tsx | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/frontend/app/routes/configurations/configuration-file-tile.tsx b/src/main/frontend/app/routes/configurations/configuration-file-tile.tsx index 3ff69d33..83551dc6 100644 --- a/src/main/frontend/app/routes/configurations/configuration-file-tile.tsx +++ b/src/main/frontend/app/routes/configurations/configuration-file-tile.tsx @@ -40,7 +40,7 @@ export default function ConfigurationFileTile({ } return ( -
+

{relativePath} @@ -55,7 +55,7 @@ export default function ConfigurationFileTile({

{adapterNames.length === 1 ? 'Adapter' : 'Adapters'}

-
+
    {adapterNames.map((name, index) => ( ) { return ( -
  • +
  • {name} diff --git a/src/main/frontend/app/routes/studio/canvas/nodetypes/child-node.tsx b/src/main/frontend/app/routes/studio/canvas/nodetypes/child-node.tsx index 377a2cd5..3345316c 100644 --- a/src/main/frontend/app/routes/studio/canvas/nodetypes/child-node.tsx +++ b/src/main/frontend/app/routes/studio/canvas/nodetypes/child-node.tsx @@ -159,7 +159,7 @@ export function ChildNodeComponent({
    ) {
    ) {
    ) { ))} {(properties.data.children.length > 0 || dragOver || canDropDraggedElement) && (
    -
    +
    {properties.data.children.map((child) => (