Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.git/
.gitattributes
.gitignore
.github/

.idea/
.vscode/
*.iml
*.ipr
*.iws
*.sw?
*.orig

.DS_Store
Thumbs.db

**/target/

!.mvn/
!mvnw
!mvnw.cmd
76 changes: 76 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# syntax=docker/dockerfile:1.6
FROM eclipse-temurin:21 AS deps
WORKDIR /code
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8

# Copy only Maven wrapper + .mvn + every pom.xml from the build context,
# without enumerating modules (requires BuildKit).
RUN --mount=type=bind,source=.,target=/src,ro \
bash -ceu ' \
mkdir -p /code; \
cd /src; \
# copy Maven wrapper if present
cp mvnw /code/; \
mkdir -p /code/.mvn && cp -R .mvn/. /code/.mvn/; \
# copy all pom.xml preserving directory structure
while IFS= read -r -d "" p; do \
mkdir -p /code/"$(dirname "$p")"; \
cp "$p" /code/"$p"; \
done < <(find . -name pom.xml -type f -print0); \
Comment on lines +12 to +19
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

“If present” comment is false; cp will fail when files are absent.

Guard wrapper/.mvn copies to avoid breaking builds in forks/CI without mvnw.

-        # copy Maven wrapper if present
-        cp mvnw /code/; \
-        mkdir -p /code/.mvn && cp -R .mvn/. /code/.mvn/; \
+        # copy Maven wrapper if present
+        [ -f mvnw ] && cp mvnw /code/ || true; \
+        if [ -d .mvn ]; then mkdir -p /code/.mvn && cp -R .mvn/. /code/.mvn/; fi; \
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# copy Maven wrapper if present
cp mvnw /code/; \
mkdir -p /code/.mvn && cp -R .mvn/. /code/.mvn/; \
# copy all pom.xml preserving directory structure
while IFS= read -r -d "" p; do \
mkdir -p /code/"$(dirname "$p")"; \
cp "$p" /code/"$p"; \
done < <(find . -name pom.xml -type f -print0); \
# copy Maven wrapper if present
[ -f mvnw ] && cp mvnw /code/ || true; \
if [ -d .mvn ]; then mkdir -p /code/.mvn && cp -R .mvn/. /code/.mvn/; fi; \
# copy all pom.xml preserving directory structure
while IFS= read -r -d "" p; do \
mkdir -p /code/"$(dirname "$p")"; \
cp "$p" /code/"$p"; \
done < <(find . -name pom.xml -type f -print0); \
🤖 Prompt for AI Agents
In Dockerfile around lines 12 to 19, the comments claim "if present" but the cp
commands unconditionally copy mvnw and .mvn which will fail if they don't exist;
guard these copies by checking existence first: only cp mvnw if the file exists,
only create /code/.mvn and cp .mvn contents if the .mvn directory exists, and
keep the find+while loop for pom.xml as-is (or ensure it safely handles no
results); update the Dockerfile to perform -f/-d tests (or use shell
conditionals) before each cp to avoid build failures in forks/CI without
mvnw/.mvn.

'

RUN --mount=type=cache,target=/root/.m2 \
./mvnw -B -DskipTests \
-DoutputAbsoluteArtifactFilename=true \
-DincludePlugins=true \
org.apache.maven.plugins:maven-dependency-plugin:3.8.1:go-offline

FROM eclipse-temurin:21 AS builder
WORKDIR /code
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8

ARG DB_HOST
ARG DB_PORT
ARG DB_DATABASE
ARG DB_USER
ARG DB_PASSWORD

Comment on lines +32 to +37
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

DB credentials as build args leak into image history.

Build-time args are visible in layer history and logs; don’t pass secrets this way.

Use BuildKit secrets for the password and minimal-privilege codegen user:

-ARG DB_PASSWORD
+ARG DB_PASSWORD # kept for local dev, prefer secret in CI

And in the build step:

-RUN --mount=type=cache,target=/root/.m2 \
+RUN --mount=type=cache,target=/root/.m2 \
+    --mount=type=secret,id=dbpass \
     dockerize -wait tcp://${DB_HOST}:${DB_PORT} -timeout 60s \
   && ./mvnw clean package \
@@
-	  -Ddb.password="${DB_PASSWORD}" \
+	  -Ddb.password="$(cat /run/secrets/dbpass || echo ${DB_PASSWORD})" \

Document building with: docker build --secret id=dbpass,src=./db.pass …

COPY . /code

# Download and install dockerize.
# Needed so the web container will wait for MariaDB to start.
# Wait for the db to startup(via dockerize), then
# Build steve, requires a db to be available on port 3306
ARG PORT=8180
ARG DOCKERIZE_VERSION=v0.19.0
RUN curl -sfL "https://github.com/powerman/dockerize/releases/download/${DOCKERIZE_VERSION}/dockerize-$(uname -s)-$(uname -m)" \
| install /dev/stdin /usr/local/bin/dockerize

RUN --mount=type=cache,target=/root/.m2 \
dockerize -wait tcp://${DB_HOST}:${DB_PORT} -timeout 60s \
&& ./mvnw clean package \
-DskipTests \
-Dhttp.port=${PORT} \
-Dserver.host="0.0.0.0" \
-Ddb.ip="${DB_HOST}" \
-Ddb.port=${DB_PORT} \
-Ddb.schema="${DB_DATABASE}" \
-Ddb.user="${DB_USER}" \
-Ddb.password="${DB_PASSWORD}" \
-Dserver.gzip.enabled=false \
-Dappender="CONSOLE" \
-Djdk.tls.client.protocols="TLSv1,TLSv1.1,TLSv1.2"
Comment on lines +60 to +62
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Don’t enable TLS 1.0/1.1.

These are deprecated and should not be forced on the build JVM.

-	  -Djdk.tls.client.protocols="TLSv1,TLSv1.1,TLSv1.2"
+	  -Djdk.tls.client.protocols="TLSv1.2,TLSv1.3"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
-Dserver.gzip.enabled=false \
-Dappender="CONSOLE" \
-Djdk.tls.client.protocols="TLSv1,TLSv1.1,TLSv1.2"
-Dserver.gzip.enabled=false \
-Dappender="CONSOLE" \
-Djdk.tls.client.protocols="TLSv1.2,TLSv1.3"
🤖 Prompt for AI Agents
In Dockerfile around lines 60 to 62, the JVM system property
jdk.tls.client.protocols is forcing deprecated TLSv1 and TLSv1.1; remove those
protocols so only modern TLS versions are allowed (e.g., use TLSv1.2 and TLSv1.3
or omit the property to use the JVM defaults). Update the
-Djdk.tls.client.protocols value to exclude TLSv1 and TLSv1.1 and ensure it
specifies only supported secure protocols.


Comment on lines +49 to +63
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Build depends on a running DB; docker compose can’t guarantee DB is up before build.

With dockerize in the builder stage, docker compose up --build will likely fail because images are built before services start. This conflicts with SteVe’s jOOQ/Flyway codegen requirement for a live DB (per retrieved learnings).

Leverage the learning: SteVe needs DB during mvn generate-sources.

Options:

  • Simplest workflow: document a 2-step sequence:
    1. docker compose up -d db
    2. docker build --build-arg DB_* …
    3. docker compose up app
  • Or add a compose “codegen” service that depends_on db:healthy and runs mvn -Ddb.* generate-sources, stores generated-sources in a volume, then let Dockerfile build without DB.
  • Or supply a cached “generated-sources” artifact via a separate stage/volume.

If you keep dockerize in Dockerfile, remove build from compose for app to avoid misleading users.

🤖 Prompt for AI Agents
In Dockerfile around lines 49-63, the build currently waits for a running DB via
dockerize which fails because images are built before compose starts services;
remove the dockerize wait from the Dockerfile and instead (choose one) either:
1) document a two-step build workflow (bring up the db first, then build the
image with DB_* build-args, then start the app), or 2) add a separate "codegen"
service in docker-compose that depends_on db:healthy and runs mvn -Ddb.*
generate-sources writing generated-sources into a shared volume which the app
build stage consumes, or 3) create a prior CI/build stage that produces and
caches generated-sources/artifact which the Dockerfile copies in; implement one
of these fixes and ensure the Dockerfile no longer blocks on DB at build time
(or remove app from compose build to avoid misleading users).

FROM eclipse-temurin:21
WORKDIR /app
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8

ARG PORT=8180

COPY --from=builder /code/steve/target/steve.jar /app/
COPY --from=builder /code/steve/target/libs/ /app/libs/

EXPOSE ${PORT}
EXPOSE 8443

CMD ["sh", "-c", "exec java -XX:MaxRAMPercentage=85 -jar /app/steve.jar"]
39 changes: 22 additions & 17 deletions steve/docker-compose.yml → docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,42 +1,47 @@
version: "3.0"

volumes:
db-data:
external: false

services:

db:
# Pinning MariaDB to point release 10.4.30 works around the issues with the
# database migrations seen with 10.4.31 in issue #1212.
# database migrations seen with 10.4.31 in issue https://github.com/steve-community/steve/issues/1212.
#
# TODO: Get database migrations to work with the latest point releases of
# MariaDB 10.4.
image: mariadb:10.4.30
restart: unless-stopped
ports:
- 3306:3306
- "3306:3306"
environment:
MYSQL_RANDOM_ROOT_PASSWORD: "yes"
MYSQL_DATABASE: stevedb
MYSQL_USER: steve
MYSQL_PASSWORD: changeme
volumes:
- db-data:/var/lib/mysql
healthcheck:
test: [ "CMD", "mysqladmin", "ping", "-h", "localhost" ]
interval: 5s
timeout: 3s
retries: 20

app:
build:
context: .
args:
DB_HOST: host.docker.internal
DB_PORT: 3306
DB_DATABASE: stevedb
DB_USER: steve
DB_PASSWORD: changeme
image: steve:test
Comment on lines +29 to +37
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Build-time DB args embed secrets and don’t ensure DB is up before build.

Two issues:

  • Secrets in build args leak to image history/logs.
  • Compose builds images before starting services; builder won’t reach db even with host.docker.internal.

Consider:

  • Remove build args here; build after db is up (two-step workflow), passing secrets via build secrets.
  • Or add a dedicated “codegen” service (depends_on: db:healthy) to run mvn generate-sources, then build the image without DB coupling.

restart: unless-stopped
build: .
links:
- "db:mariadb"
depends_on:
db:
condition: service_healthy
volumes:
- .:/code
ports:
- "8180:8180"
- "8443:8443"
environment:
MYSQL_HOST: mariadb
MYSQL_PORT: 3306
MYSQL_DATABASE: stevedb
MYSQL_USER: steve
MYSQL_PASSWORD: changeme
depends_on:
- db

19 changes: 19 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
<module>steve-ocpp-2-x</module>
<module>steve-ocpp-soap</module>
<module>steve-ocpp-websocket</module>
<module>steve-ui</module>
<module>steve-ui-jsp</module>
<module>steve-ui-thymeleaf</module>
</modules>

<properties>
Expand Down Expand Up @@ -85,11 +87,21 @@
<artifactId>steve-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>de.rwth.idsg</groupId>
<artifactId>steve-ui</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>de.rwth.idsg</groupId>
<artifactId>steve-ui-jsp</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>de.rwth.idsg</groupId>
<artifactId>steve-ui-thymeleaf</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
Expand All @@ -104,6 +116,13 @@
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.ee10</groupId>
<artifactId>jetty-ee10-bom</artifactId>
<version>${jetty.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
Expand Down
8 changes: 8 additions & 0 deletions steve-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
Comment on lines +61 to +64
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Don’t pin a logging backend in core; make logback non-transitive

Core libraries should depend on slf4j-api only. Make logback optional so downstream runnable modules decide the backend.

Apply:

-    <dependency>
-      <groupId>ch.qos.logback</groupId>
-      <artifactId>logback-classic</artifactId>
-    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-classic</artifactId>
+      <optional>true</optional>
+    </dependency>

🏁 Script executed:

#!/bin/bash
# Check for multiple SLF4J bindings across modules
rg -n -C2 -g '**/pom.xml' 'logback-classic|slf4j-simple|log4j-to-slf4j|jul-to-slf4j'

Length of output: 1065


🏁 Script executed:

#!/bin/bash
# Check for explicit slf4j-api declaration in steve-core/pom.xml
rg -n -C2 '<artifactId>slf4j-api</artifactId>' steve-core/pom.xml

Length of output: 210


Mark logback-classic as optional in steve-core/pom.xml
Replace the direct logback binding so core only brings in slf4j-api by default:

--- steve-core/pom.xml
@@ -61,3 +61,5 @@
     <dependency>
       <groupId>ch.qos.logback</groupId>
       <artifactId>logback-classic</artifactId>
+      <optional>true</optional>
     </dependency>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<optional>true</optional>
</dependency>
🤖 Prompt for AI Agents
In steve-core/pom.xml around lines 61 to 64, the pom currently declares
logback-classic as a regular dependency which forces a concrete SLF4J binding
into consumers; mark that dependency optional so the module only brings in
slf4j-api by default by adding an <optional>true</optional> element to the
logback-classic dependency (or remove it and let consumers choose their
binding), leaving slf4j-api as the provided API.


<dependency>
<groupId>com.google.guava</groupId>
Expand All @@ -67,5 +71,9 @@
<groupId>com.neovisionaries</groupId>
<artifactId>nv-i18n</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.ee10</groupId>
<artifactId>jetty-ee10-webapp</artifactId>
</dependency>
</dependencies>
</project>
25 changes: 25 additions & 0 deletions steve-core/src/main/java/de/rwth/idsg/steve/JettyCustomizer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* SteVe - SteckdosenVerwaltung - https://github.com/steve-community/steve
* Copyright (C) 2013-2025 SteVe Community Team
* All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.rwth.idsg.steve;

import org.eclipse.jetty.ee10.webapp.WebAppContext;

public interface JettyCustomizer {
void configure(WebAppContext ctx);
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ public static class Paths {
private final String routerEndpointPath;

private final @Nullable String contextPath;

public String getLocation() {
return contextPath + managerMapping + "/home";
}

Comment on lines +52 to +55
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle nullable contextPath and slash normalization in getLocation().

Current code risks "null..." and double slashes.

-        public String getLocation() {
-            return contextPath + managerMapping + "/home";
-        }
+        public String getLocation() {
+            String ctx = (contextPath == null || "/".equals(contextPath)) ? "" : contextPath;
+            if (!managerMapping.startsWith("/")) {
+                // Ensure managerMapping is absolute
+                ctx = ctx + "/";
+            }
+            String base = (ctx.endsWith("/")) ? ctx.substring(0, ctx.length() - 1) : ctx;
+            return base + managerMapping + "/home";
+        }

Add unit tests for contextPath = null, "", and "/foo".

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In steve-core/src/main/java/de/rwth/idsg/steve/SteveConfiguration.java around
lines 52-55, getLocation() currently concatenates contextPath and managerMapping
directly which can produce "null" or double slashes; normalize by treating a
null contextPath as empty string, strip any trailing slash from contextPath,
ensure it has a leading slash only if non-empty, and join pieces so you never
produce duplicate slashes (e.g., ensure managerMapping begins with a single '/'
or use a safe join). Update getLocation() to apply this normalization and always
return a canonical path ending with "/home". Add unit tests covering contextPath
= null, "" and "/foo" to assert expected outputs (no "null" and no double
slashes).

public String getWsPathInfix() {
return routerEndpointPath + websocketMapping;
}
Comment on lines +56 to +58
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Normalize join for WebSocket path infix.

Avoid missing or duplicate slashes.

-        public String getWsPathInfix() {
-            return routerEndpointPath + websocketMapping;
-        }
+        public String getWsPathInfix() {
+            String left = routerEndpointPath.endsWith("/") ? routerEndpointPath.substring(0, routerEndpointPath.length()-1) : routerEndpointPath;
+            String right = websocketMapping.startsWith("/") ? websocketMapping : "/" + websocketMapping;
+            return left + right;
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public String getWsPathInfix() {
return routerEndpointPath + websocketMapping;
}
public String getWsPathInfix() {
String left = routerEndpointPath.endsWith("/")
? routerEndpointPath.substring(0, routerEndpointPath.length() - 1)
: routerEndpointPath;
String right = websocketMapping.startsWith("/")
? websocketMapping
: "/" + websocketMapping;
return left + right;
}
🤖 Prompt for AI Agents
In steve-core/src/main/java/de/rwth/idsg/steve/SteveConfiguration.java around
lines 56 to 58, the getWsPathInfix() simply concatenates routerEndpointPath and
websocketMapping which can produce missing or duplicate slashes; fix by
normalizing both parts before joining: trim any trailing slash from
routerEndpointPath and any leading slash from websocketMapping, then return the
two parts joined with a single "/" between them (ensure the result starts with
"/" if routerEndpointPath is empty or originally started with "/"); also handle
null or empty websocketMapping gracefully by returning the normalized
routerEndpointPath or "/" as appropriate.

}

private final Paths paths;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

/**
Expand Down Expand Up @@ -149,9 +148,4 @@ public static String timeElapsed(Instant from, Instant to) {

return sb.toString().trim();
}

public static long getOffsetFromUtcInSeconds() {
var offset = ZonedDateTime.now().getOffset();
return offset.getTotalSeconds();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package de.rwth.idsg.steve.config;

import com.google.common.collect.Lists;
import de.rwth.idsg.steve.SteveConfiguration;
import de.rwth.idsg.steve.ocpp.ws.OcppWebSocketHandshakeHandler;
import de.rwth.idsg.steve.ocpp.ws.ocpp12.Ocpp12WebSocketEndpoint;
import de.rwth.idsg.steve.ocpp.ws.ocpp15.Ocpp15WebSocketEndpoint;
Expand All @@ -45,13 +46,13 @@
@RequiredArgsConstructor
public class OcppWebSocketConfiguration implements WebSocketConfigurer {

public static final String PATH_INFIX = "/websocket/CentralSystemService/";
public static final Duration PING_INTERVAL = Duration.ofMinutes(15);
public static final Duration IDLE_TIMEOUT = Duration.ofHours(2);
public static final int MAX_MSG_SIZE = 8_388_608; // 8 MB for max message size
public static final Duration WS_PING_INTERVAL = Duration.ofMinutes(15);
public static final Duration WS_IDLE_TIMEOUT = Duration.ofHours(2);
public static final int WS_MAX_MSG_SIZE = 8_388_608; // 8 MB for max message size

private final ChargePointRegistrationService chargePointRegistrationService;
private final ChargeBoxIdValidator chargeBoxIdValidator;
private final SteveConfiguration config;

private final Ocpp12WebSocketEndpoint ocpp12WebSocketEndpoint;
private final Ocpp15WebSocketEndpoint ocpp15WebSocketEndpoint;
Expand All @@ -60,13 +61,16 @@ public class OcppWebSocketConfiguration implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {

OcppWebSocketHandshakeHandler handshakeHandler = new OcppWebSocketHandshakeHandler(
var handshakeHandler = new OcppWebSocketHandshakeHandler(
chargeBoxIdValidator,
new DefaultHandshakeHandler(),
Lists.newArrayList(ocpp16WebSocketEndpoint, ocpp15WebSocketEndpoint, ocpp12WebSocketEndpoint),
chargePointRegistrationService);
chargePointRegistrationService,
config.getPaths().getWsPathInfix() + "/");

registry.addHandler(handshakeHandler.getDummyWebSocketHandler(), PATH_INFIX + "*")
registry.addHandler(
handshakeHandler.getDummyWebSocketHandler(),
config.getPaths().getWsPathInfix() + "/*")
.setHandshakeHandler(handshakeHandler)
.setAllowedOrigins("*");
}
Comment on lines +71 to 76
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Restrict WebSocket allowed origins.

setAllowedOrigins("*") enables any origin. Prefer explicit origins or config-driven patterns.

-                .setAllowedOrigins("*");
+                // Prefer patterns or a configured list
+                .setAllowedOriginPatterns(config.getSecurity().getAllowedWsOrigins());

If no such config exists, introduce one or restrict to known UI origins.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
steve-ocpp-websocket/src/main/java/de/rwth/idsg/steve/config/OcppWebSocketConfiguration.java
around lines 71 to 76, the WebSocket mapping currently calls
setAllowedOrigins("*"), which allows any origin; replace this with a
config-driven, explicit allowed-origins value (e.g. config.getAllowedOrigins())
or introduce a new property if it doesn't exist, validate/parse it
(comma-separated list or patterns) and pass the resulting origin array to
setAllowedOrigins; ensure a sensible default (restrict to known UI host(s) or
fail fast) and avoid using the wildcard.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ public void onOpen(WebSocketSession session) throws Exception {
// the connection because of a idle timeout, we ping-pong at fixed intervals.
var pingSchedule = asyncTaskScheduler.scheduleAtFixedRate(
new PingTask(chargeBoxId, session),
Instant.now().plus(OcppWebSocketConfiguration.PING_INTERVAL),
OcppWebSocketConfiguration.PING_INTERVAL);
Instant.now().plus(OcppWebSocketConfiguration.WS_PING_INTERVAL),
OcppWebSocketConfiguration.WS_PING_INTERVAL);

futureResponseContextStore.addSession(session);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
public abstract class ConcurrentWebSocketHandler implements WebSocketHandler {

private static final int SEND_TIME_LIMIT = (int) TimeUnit.SECONDS.toMillis(10);
private static final int BUFFER_SIZE_LIMIT = 5 * OcppWebSocketConfiguration.MAX_MSG_SIZE;
private static final int BUFFER_SIZE_LIMIT = 5 * OcppWebSocketConfiguration.WS_MAX_MSG_SIZE;

private final Map<String, ConcurrentWebSocketSessionDecorator> sessions = new ConcurrentHashMap<>();

Expand Down
Loading
Loading