-
-
Notifications
You must be signed in to change notification settings - Fork 481
Adding antivirus scanning capabilities with ClamAV via API calls #454
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
added clav av scanning capabilities
added clamav scanning capabilities
added clamav capabilities
Added ClamAV REST API service and updated ports.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 issues found across 4 files
Prompt for AI agents (all 2 issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="compose.yaml">
<violation number="1" location="compose.yaml:19">
P1: Convertx injects `CLAMAV_URL` pointing to a non-existent Docker hostname (`clam_av_api`), so every server-side ClamAV fetch fails and uploads are never actually scanned, bypassing the antivirus workflow.</violation>
<violation number="2" location="compose.yaml:32">
P1: `CLAMD_IP` is left as the placeholder `CLAMAV_server_IP` even though the ClamAV daemon service defined below is named `clamav`. The REST API container will fail to connect to the daemon, so scans will always fail.</violation>
</file>
Since this is your first cubic review, here's how it works:
- cubic automatically reviews your code and comments on bugs and improvements
- Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
- Ask questions if you need clarification on any suggestion
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
| # field name expected in the multipart form | ||
| - APP_FORM_KEY=FILES | ||
| # talk to your existing ClamAV daemon | ||
| - CLAMD_IP=CLAMAV_server_IP |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: CLAMD_IP is left as the placeholder CLAMAV_server_IP even though the ClamAV daemon service defined below is named clamav. The REST API container will fail to connect to the daemon, so scans will always fail.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At compose.yaml, line 32:
<comment>`CLAMD_IP` is left as the placeholder `CLAMAV_server_IP` even though the ClamAV daemon service defined below is named `clamav`. The REST API container will fail to connect to the daemon, so scans will always fail.</comment>
<file context>
@@ -16,5 +16,32 @@ services:
+ # field name expected in the multipart form
+ - APP_FORM_KEY=FILES
+ # talk to your existing ClamAV daemon
+ - CLAMD_IP=CLAMAV_server_IP
+ - CLAMD_PORT=3310
+ # max allowed file size (here: 250 MB)
</file context>
| - CLAMD_IP=CLAMAV_server_IP | |
| - CLAMD_IP=clamav |
| # - HIDE_HISTORY=true # hides the history tab in the web interface, defaults to false | ||
| - TZ=Europe/Stockholm # set your timezone, defaults to UTC | ||
| # - UNAUTHENTICATED_USER_SHARING=true # for use with ALLOW_UNAUTHENTICATED=true to share history with all unauthenticated users / devices | ||
| - CLAMAV_URL=http://clam_av_api:3000/api/v1/scan |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: Convertx injects CLAMAV_URL pointing to a non-existent Docker hostname (clam_av_api), so every server-side ClamAV fetch fails and uploads are never actually scanned, bypassing the antivirus workflow.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At compose.yaml, line 19:
<comment>Convertx injects `CLAMAV_URL` pointing to a non-existent Docker hostname (`clam_av_api`), so every server-side ClamAV fetch fails and uploads are never actually scanned, bypassing the antivirus workflow.</comment>
<file context>
@@ -16,5 +16,32 @@ services:
# - HIDE_HISTORY=true # hides the history tab in the web interface, defaults to false
- TZ=Europe/Stockholm # set your timezone, defaults to UTC
# - UNAUTHENTICATED_USER_SHARING=true # for use with ALLOW_UNAUTHENTICATED=true to share history with all unauthenticated users / devices
+ - CLAMAV_URL=http://clam_av_api:3000/api/v1/scan
ports:
- - 3000:3000
</file context>
| - CLAMAV_URL=http://clam_av_api:3000/api/v1/scan | |
| + - CLAMAV_URL=http://clamav-rest-api:3000/api/v1/scan |
|
Nice idea! I would like this function to be behind a toggle. There isn't really that many things that could be infected since most conversions are images of different kinds. |
|
Hi, that will be also a good option, if you can help implementing it will be amassing, unfortunately something like that is over my skills. Thank you |
|
I have quite a lot to do at the moment sorry, but the toggle is just implementing an environment variable. Take a look at how the other ones are done if you want :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
3 issues found across 6 files
Prompt for AI agents (all 3 issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="compose.yaml">
<violation number="1" location="compose.yaml:19">
P1: Service hostname mismatch: `clam_av_api` should be `clamav-rest-api` to match the actual service name defined in this compose file. Docker Compose uses service names for internal DNS resolution.</violation>
<violation number="2" location="compose.yaml:32">
P1: Placeholder value not configured: `CLAMAV_server_IP` should be `clamav` to reference the ClamAV daemon service defined in this compose file. Docker Compose provides DNS resolution using service names.</violation>
<violation number="3" location="compose.yaml:40">
P0: YAML indentation error: The `clamav` service has 3 spaces of indentation instead of 2, which will cause a YAML parsing error and prevent the compose file from being loaded.</violation>
</file>
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
| # field name expected in the multipart form | ||
| - APP_FORM_KEY=FILES | ||
| # talk to your existing ClamAV daemon | ||
| - CLAMD_IP=CLAMAV_server_IP |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: Placeholder value not configured: CLAMAV_server_IP should be clamav to reference the ClamAV daemon service defined in this compose file. Docker Compose provides DNS resolution using service names.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At compose.yaml, line 32:
<comment>Placeholder value not configured: `CLAMAV_server_IP` should be `clamav` to reference the ClamAV daemon service defined in this compose file. Docker Compose provides DNS resolution using service names.</comment>
<file context>
@@ -16,5 +16,32 @@ services:
+ # field name expected in the multipart form
+ - APP_FORM_KEY=FILES
+ # talk to your existing ClamAV daemon
+ - CLAMD_IP=CLAMAV_server_IP
+ - CLAMD_PORT=3310
+ # max allowed file size (here: 250 MB)
</file context>
| - CLAMD_IP=CLAMAV_server_IP | |
| - CLAMD_IP=clamav |
| # - HIDE_HISTORY=true # hides the history tab in the web interface, defaults to false | ||
| - TZ=Europe/Stockholm # set your timezone, defaults to UTC | ||
| # - UNAUTHENTICATED_USER_SHARING=true # for use with ALLOW_UNAUTHENTICATED=true to share history with all unauthenticated users / devices | ||
| - CLAMAV_URL=http://clam_av_api:3000/api/v1/scan |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: Service hostname mismatch: clam_av_api should be clamav-rest-api to match the actual service name defined in this compose file. Docker Compose uses service names for internal DNS resolution.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At compose.yaml, line 19:
<comment>Service hostname mismatch: `clam_av_api` should be `clamav-rest-api` to match the actual service name defined in this compose file. Docker Compose uses service names for internal DNS resolution.</comment>
<file context>
@@ -16,5 +16,32 @@ services:
# - HIDE_HISTORY=true # hides the history tab in the web interface, defaults to false
- TZ=Europe/Stockholm # set your timezone, defaults to UTC
# - UNAUTHENTICATED_USER_SHARING=true # for use with ALLOW_UNAUTHENTICATED=true to share history with all unauthenticated users / devices
+ - CLAMAV_URL=http://clam_av_api:3000/api/v1/scan
ports:
- - 3000:3000
</file context>
| - CLAMAV_URL=http://clam_av_api:3000/api/v1/scan | |
| - CLAMAV_URL=http://clamav-rest-api:3000/api/v1/scan |
| # outside:inside | ||
| - "3000:3000" | ||
|
|
||
| clamav: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P0: YAML indentation error: The clamav service has 3 spaces of indentation instead of 2, which will cause a YAML parsing error and prevent the compose file from being loaded.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At compose.yaml, line 40:
<comment>YAML indentation error: The `clamav` service has 3 spaces of indentation instead of 2, which will cause a YAML parsing error and prevent the compose file from being loaded.</comment>
<file context>
@@ -16,5 +16,32 @@ services:
+ # outside:inside
+ - "3000:3000"
+
+ clamav:
+ image: clamav/clamav:latest
+ container_name: clamav
</file context>
| clamav: | |
| clamav: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
4 issues found across 5 files
Prompt for AI agents (all 4 issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="src/pages/upload.tsx">
<violation number="1" location="src/pages/upload.tsx:163">
P2: File overwrite risk when multiple files sanitize to the same name. If two files have identical sanitized names (or invalid names defaulting to "file"), later files silently overwrite earlier ones. Consider appending a suffix or checking for existing files.</violation>
</file>
<file name="compose.yaml">
<violation number="1" location="compose.yaml:19">
P1: Hostname mismatch: `clam_av_api` should be `clamav-rest-api` to match the service name. Docker Compose uses service names as DNS hostnames within the network.</violation>
<violation number="2" location="compose.yaml:32">
P1: Placeholder value: `CLAMAV_server_IP` should be `clamav` to reference the ClamAV daemon service defined in this compose file.</violation>
<violation number="3" location="compose.yaml:40">
P0: YAML syntax error: The `clamav:` service has 3 spaces indentation instead of 2 spaces like other services. This will cause a parsing error.</violation>
</file>
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
|
|
||
| for (const file of files) { | ||
| const originalName = (file as any).name ?? "upload"; | ||
| const sanitizedFileName = sanitize(originalName) || "file"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: File overwrite risk when multiple files sanitize to the same name. If two files have identical sanitized names (or invalid names defaulting to "file"), later files silently overwrite earlier ones. Consider appending a suffix or checking for existing files.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/pages/upload.tsx, line 163:
<comment>File overwrite risk when multiple files sanitize to the same name. If two files have identical sanitized names (or invalid names defaulting to "file"), later files silently overwrite earlier ones. Consider appending a suffix or checking for existing files.</comment>
<file context>
@@ -1,42 +1,219 @@
+
+ for (const file of files) {
+ const originalName = (file as any).name ?? "upload";
+ const sanitizedFileName = sanitize(originalName) || "file";
+ console.log("[Upload] Handling file:", originalName, "=> sanitized:", sanitizedFileName);
+
</file context>
| # field name expected in the multipart form | ||
| - APP_FORM_KEY=FILES | ||
| # talk to your existing ClamAV daemon | ||
| - CLAMD_IP=CLAMAV_server_IP |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: Placeholder value: CLAMAV_server_IP should be clamav to reference the ClamAV daemon service defined in this compose file.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At compose.yaml, line 32:
<comment>Placeholder value: `CLAMAV_server_IP` should be `clamav` to reference the ClamAV daemon service defined in this compose file.</comment>
<file context>
@@ -16,5 +16,32 @@ services:
+ # field name expected in the multipart form
+ - APP_FORM_KEY=FILES
+ # talk to your existing ClamAV daemon
+ - CLAMD_IP=CLAMAV_server_IP
+ - CLAMD_PORT=3310
+ # max allowed file size (here: 250 MB)
</file context>
| - CLAMD_IP=CLAMAV_server_IP | |
| - CLAMD_IP=clamav |
| # - HIDE_HISTORY=true # hides the history tab in the web interface, defaults to false | ||
| - TZ=Europe/Stockholm # set your timezone, defaults to UTC | ||
| # - UNAUTHENTICATED_USER_SHARING=true # for use with ALLOW_UNAUTHENTICATED=true to share history with all unauthenticated users / devices | ||
| - CLAMAV_URL=http://clam_av_api:3000/api/v1/scan |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: Hostname mismatch: clam_av_api should be clamav-rest-api to match the service name. Docker Compose uses service names as DNS hostnames within the network.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At compose.yaml, line 19:
<comment>Hostname mismatch: `clam_av_api` should be `clamav-rest-api` to match the service name. Docker Compose uses service names as DNS hostnames within the network.</comment>
<file context>
@@ -16,5 +16,32 @@ services:
# - HIDE_HISTORY=true # hides the history tab in the web interface, defaults to false
- TZ=Europe/Stockholm # set your timezone, defaults to UTC
# - UNAUTHENTICATED_USER_SHARING=true # for use with ALLOW_UNAUTHENTICATED=true to share history with all unauthenticated users / devices
+ - CLAMAV_URL=http://clam_av_api:3000/api/v1/scan
ports:
- - 3000:3000
</file context>
| - CLAMAV_URL=http://clam_av_api:3000/api/v1/scan | |
| - CLAMAV_URL=http://clamav-rest-api:3000/api/v1/scan |
| # outside:inside | ||
| - "3000:3000" | ||
|
|
||
| clamav: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P0: YAML syntax error: The clamav: service has 3 spaces indentation instead of 2 spaces like other services. This will cause a parsing error.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At compose.yaml, line 40:
<comment>YAML syntax error: The `clamav:` service has 3 spaces indentation instead of 2 spaces like other services. This will cause a parsing error.</comment>
<file context>
@@ -16,5 +16,32 @@ services:
+ # outside:inside
+ - "3000:3000"
+
+ clamav:
+ image: clamav/clamav:latest
+ container_name: clamav
</file context>
| clamav: | |
| clamav: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
5 issues found across 7 files
Prompt for AI agents (all 5 issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="compose.yaml">
<violation number="1" location="compose.yaml:19">
P1: Service name mismatch: `clam_av_api` doesn't match the defined service name `clamav-rest-api`. Docker Compose uses service names for DNS resolution, so this URL will fail to resolve.</violation>
<violation number="2" location="compose.yaml:32">
P1: Placeholder value `CLAMAV_server_IP` needs to be replaced with the actual ClamAV service name. Since the `clamav` service is in the same compose file, use `clamav` as the hostname.</violation>
<violation number="3" location="compose.yaml:40">
P0: YAML indentation error: `clamav:` has 3 spaces instead of 2. This will cause a YAML parsing error and prevent Docker Compose from running.</violation>
</file>
<file name="public/script.js">
<violation number="1" location="public/script.js:277">
P2: Failed upload doesn't remove file from `fileNames` array or UI. This leaves inconsistent state where user could attempt to convert a file that failed to upload.</violation>
</file>
<file name="src/pages/antivirus.tsx">
<violation number="1" location="src/pages/antivirus.tsx:22">
P1: Security: POST `/api/antivirus` endpoint lacks authentication. This allows unauthenticated users to disable antivirus scanning. Add `user` to the handler context to require authentication, similar to other protected endpoints like `deleteFile.tsx`.</violation>
</file>
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
| # field name expected in the multipart form | ||
| - APP_FORM_KEY=FILES | ||
| # talk to your existing ClamAV daemon | ||
| - CLAMD_IP=CLAMAV_server_IP |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: Placeholder value CLAMAV_server_IP needs to be replaced with the actual ClamAV service name. Since the clamav service is in the same compose file, use clamav as the hostname.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At compose.yaml, line 32:
<comment>Placeholder value `CLAMAV_server_IP` needs to be replaced with the actual ClamAV service name. Since the `clamav` service is in the same compose file, use `clamav` as the hostname.</comment>
<file context>
@@ -16,5 +16,32 @@ services:
+ # field name expected in the multipart form
+ - APP_FORM_KEY=FILES
+ # talk to your existing ClamAV daemon
+ - CLAMD_IP=CLAMAV_server_IP
+ - CLAMD_PORT=3310
+ # max allowed file size (here: 250 MB)
</file context>
| - CLAMD_IP=CLAMAV_server_IP | |
| - CLAMD_IP=clamav |
| # - HIDE_HISTORY=true # hides the history tab in the web interface, defaults to false | ||
| - TZ=Europe/Stockholm # set your timezone, defaults to UTC | ||
| # - UNAUTHENTICATED_USER_SHARING=true # for use with ALLOW_UNAUTHENTICATED=true to share history with all unauthenticated users / devices | ||
| - CLAMAV_URL=http://clam_av_api:3000/api/v1/scan |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: Service name mismatch: clam_av_api doesn't match the defined service name clamav-rest-api. Docker Compose uses service names for DNS resolution, so this URL will fail to resolve.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At compose.yaml, line 19:
<comment>Service name mismatch: `clam_av_api` doesn't match the defined service name `clamav-rest-api`. Docker Compose uses service names for DNS resolution, so this URL will fail to resolve.</comment>
<file context>
@@ -16,5 +16,32 @@ services:
# - HIDE_HISTORY=true # hides the history tab in the web interface, defaults to false
- TZ=Europe/Stockholm # set your timezone, defaults to UTC
# - UNAUTHENTICATED_USER_SHARING=true # for use with ALLOW_UNAUTHENTICATED=true to share history with all unauthenticated users / devices
+ - CLAMAV_URL=http://clam_av_api:3000/api/v1/scan
ports:
- - 3000:3000
</file context>
| - CLAMAV_URL=http://clam_av_api:3000/api/v1/scan | |
| - CLAMAV_URL=http://clamav-rest-api:3000/api/v1/scan |
| # outside:inside | ||
| - "3000:3000" | ||
|
|
||
| clamav: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P0: YAML indentation error: clamav: has 3 spaces instead of 2. This will cause a YAML parsing error and prevent Docker Compose from running.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At compose.yaml, line 40:
<comment>YAML indentation error: `clamav:` has 3 spaces instead of 2. This will cause a YAML parsing error and prevent Docker Compose from running.</comment>
<file context>
@@ -16,5 +16,32 @@ services:
+ # outside:inside
+ - "3000:3000"
+
+ clamav:
+ image: clamav/clamav:latest
+ container_name: clamav
</file context>
| clamav: | |
| clamav: |
| } | ||
|
|
||
| // Generic HTTP error | ||
| if (xhr.status !== 200) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Failed upload doesn't remove file from fileNames array or UI. This leaves inconsistent state where user could attempt to convert a file that failed to upload.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At public/script.js, line 277:
<comment>Failed upload doesn't remove file from `fileNames` array or UI. This leaves inconsistent state where user could attempt to convert a file that failed to upload.</comment>
<file context>
@@ -209,20 +202,104 @@ const uploadFile = (file) => {
+ }
+
+ // Generic HTTP error
+ if (xhr.status !== 200) {
+ console.error("Upload failed:", xhr.status, xhr.responseText);
+ alert("Upload failed. Please try again.");
</file context>
| // Update AV status | ||
| .post( | ||
| "/api/antivirus", | ||
| ({ body }) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: Security: POST /api/antivirus endpoint lacks authentication. This allows unauthenticated users to disable antivirus scanning. Add user to the handler context to require authentication, similar to other protected endpoints like deleteFile.tsx.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/pages/antivirus.tsx, line 22:
<comment>Security: POST `/api/antivirus` endpoint lacks authentication. This allows unauthenticated users to disable antivirus scanning. Add `user` to the handler context to require authentication, similar to other protected endpoints like `deleteFile.tsx`.</comment>
<file context>
@@ -0,0 +1,45 @@
+ // Update AV status
+ .post(
+ "/api/antivirus",
+ ({ body }) => {
+ const { enabled } = body;
+
</file context>
✅ Addressed in 3420464
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
5 issues found across 7 files
Prompt for AI agents (all 5 issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="public/script.js">
<violation number="1" location="public/script.js:463">
P2: Generic HTTP error handler doesn't remove the file from `fileNames` array or remove the row from the DOM. This leaves orphaned file entries in the UI that weren't actually uploaded.</violation>
</file>
<file name="compose.yaml">
<violation number="1" location="compose.yaml:19">
P1: Hostname mismatch: `clam_av_api` does not match the service name `clamav-rest-api`. Docker Compose uses service names as DNS hostnames, so this URL will fail to resolve.</violation>
<violation number="2" location="compose.yaml:32">
P1: Placeholder value not replaced: `CLAMAV_server_IP` should be `clamav` to reference the ClamAV daemon service defined in the same compose file.</violation>
<violation number="3" location="compose.yaml:40">
P0: YAML indentation error: This line has 3 spaces instead of 2, which breaks YAML parsing. Service definitions must be consistently indented.</violation>
</file>
<file name="src/pages/antivirus.tsx">
<violation number="1" location="src/pages/antivirus.tsx:14">
P0: The new /api/antivirus GET/POST endpoints are exposed without `{ auth: true }`, so unauthenticated callers can enable or disable the global scanning state used by the upload pipeline.</violation>
</file>
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
| convertButton.disabled = false; | ||
| convertButton.textContent = "Upload failed"; | ||
|
|
||
| const progressbar = file.htmlRow.getElementsByTagName("progress"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Generic HTTP error handler doesn't remove the file from fileNames array or remove the row from the DOM. This leaves orphaned file entries in the UI that weren't actually uploaded.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At public/script.js, line 463:
<comment>Generic HTTP error handler doesn't remove the file from `fileNames` array or remove the row from the DOM. This leaves orphaned file entries in the UI that weren't actually uploaded.</comment>
<file context>
@@ -209,20 +382,104 @@ const uploadFile = (file) => {
+ convertButton.disabled = false;
+ convertButton.textContent = "Upload failed";
+
+ const progressbar = file.htmlRow.getElementsByTagName("progress");
+ if (progressbar[0]?.parentElement) {
+ progressbar[0].parentElement.remove();
</file context>
| const progressbar = file.htmlRow.getElementsByTagName("progress"); | |
| // Remove row for this file | |
| if (file.htmlRow && file.htmlRow.remove) { | |
| file.htmlRow.remove(); | |
| } | |
| // Remove from internal list | |
| const idx = fileNames.indexOf(file.name); | |
| if (idx !== -1) { | |
| fileNames.splice(idx, 1); | |
| } | |
| const progressbar = file.htmlRow?.getElementsByTagName("progress"); |
| # field name expected in the multipart form | ||
| - APP_FORM_KEY=FILES | ||
| # talk to your existing ClamAV daemon | ||
| - CLAMD_IP=CLAMAV_server_IP |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: Placeholder value not replaced: CLAMAV_server_IP should be clamav to reference the ClamAV daemon service defined in the same compose file.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At compose.yaml, line 32:
<comment>Placeholder value not replaced: `CLAMAV_server_IP` should be `clamav` to reference the ClamAV daemon service defined in the same compose file.</comment>
<file context>
@@ -16,5 +16,32 @@ services:
+ # field name expected in the multipart form
+ - APP_FORM_KEY=FILES
+ # talk to your existing ClamAV daemon
+ - CLAMD_IP=CLAMAV_server_IP
+ - CLAMD_PORT=3310
+ # max allowed file size (here: 250 MB)
</file context>
| - CLAMD_IP=CLAMAV_server_IP | |
| - CLAMD_IP=clamav |
| # - HIDE_HISTORY=true # hides the history tab in the web interface, defaults to false | ||
| - TZ=Europe/Stockholm # set your timezone, defaults to UTC | ||
| # - UNAUTHENTICATED_USER_SHARING=true # for use with ALLOW_UNAUTHENTICATED=true to share history with all unauthenticated users / devices | ||
| - CLAMAV_URL=http://clam_av_api:3000/api/v1/scan |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: Hostname mismatch: clam_av_api does not match the service name clamav-rest-api. Docker Compose uses service names as DNS hostnames, so this URL will fail to resolve.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At compose.yaml, line 19:
<comment>Hostname mismatch: `clam_av_api` does not match the service name `clamav-rest-api`. Docker Compose uses service names as DNS hostnames, so this URL will fail to resolve.</comment>
<file context>
@@ -16,5 +16,32 @@ services:
# - HIDE_HISTORY=true # hides the history tab in the web interface, defaults to false
- TZ=Europe/Stockholm # set your timezone, defaults to UTC
# - UNAUTHENTICATED_USER_SHARING=true # for use with ALLOW_UNAUTHENTICATED=true to share history with all unauthenticated users / devices
+ - CLAMAV_URL=http://clam_av_api:3000/api/v1/scan
ports:
- - 3000:3000
</file context>
| - CLAMAV_URL=http://clam_av_api:3000/api/v1/scan | |
| - CLAMAV_URL=http://clamav-rest-api:3000/api/v1/scan |
| # outside:inside | ||
| - "3000:3000" | ||
|
|
||
| clamav: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P0: YAML indentation error: This line has 3 spaces instead of 2, which breaks YAML parsing. Service definitions must be consistently indented.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At compose.yaml, line 40:
<comment>YAML indentation error: This line has 3 spaces instead of 2, which breaks YAML parsing. Service definitions must be consistently indented.</comment>
<file context>
@@ -16,5 +16,32 @@ services:
+ # outside:inside
+ - "3000:3000"
+
+ clamav:
+ image: clamav/clamav:latest
+ container_name: clamav
</file context>
| clamav: | |
| clamav: |
src/pages/antivirus.tsx
Outdated
| export const antivirus = new Elysia() | ||
| .use(userService) | ||
| // Get current AV status | ||
| .get("/api/antivirus", () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P0: The new /api/antivirus GET/POST endpoints are exposed without { auth: true }, so unauthenticated callers can enable or disable the global scanning state used by the upload pipeline.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/pages/antivirus.tsx, line 14:
<comment>The new /api/antivirus GET/POST endpoints are exposed without `{ auth: true }`, so unauthenticated callers can enable or disable the global scanning state used by the upload pipeline.</comment>
<file context>
@@ -0,0 +1,45 @@
+export const antivirus = new Elysia()
+ .use(userService)
+ // Get current AV status
+ .get("/api/antivirus", () => {
+ const available = isAntivirusAvailable();
+ const enabled = isAntivirusEnabled();
</file context>
✅ Addressed in 3420464
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
5 issues found across 7 files
Prompt for AI agents (all 5 issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="src/pages/antivirus.tsx">
<violation number="1" location="src/pages/antivirus.tsx:39">
P1: Missing authentication on POST `/api/antivirus` endpoint. This allows any user to disable antivirus scanning without being logged in, which is a security vulnerability. Add `auth: true` to the endpoint configuration like other sensitive endpoints in this codebase.</violation>
</file>
<file name="compose.yaml">
<violation number="1" location="compose.yaml:19">
P1: Service name mismatch: `CLAMAV_URL` references `clam_av_api` but the service is named `clamav-rest-api`. The antivirus scanning will fail to connect. Use `http://clamav-rest-api:3000/api/v1/scan` instead.</violation>
<violation number="2" location="compose.yaml:32">
P1: Placeholder value not replaced: `CLAMD_IP=CLAMAV_server_IP` should be `CLAMD_IP=clamav` to reference the clamav service defined in this compose file. The REST API won't be able to connect to the ClamAV daemon.</violation>
<violation number="3" location="compose.yaml:40">
P0: YAML indentation error: `clamav` service has 3 spaces instead of 2. This will cause YAML parsing to fail or produce unexpected structure.</violation>
</file>
<file name="src/pages/upload.tsx">
<violation number="1" location="src/pages/upload.tsx:180">
P2: When `sanitize()` returns an empty string, the fallback to "file" could cause filename collisions. If multiple files in the same batch have invalid names, they will all write to the same path, with each overwriting the previous. Consider appending a unique suffix (e.g., index or timestamp) to prevent data loss.</violation>
</file>
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
| }, | ||
| { | ||
| body: t.Object({ | ||
| enabled: t.Boolean(), | ||
| }), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: Missing authentication on POST /api/antivirus endpoint. This allows any user to disable antivirus scanning without being logged in, which is a security vulnerability. Add auth: true to the endpoint configuration like other sensitive endpoints in this codebase.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/pages/antivirus.tsx, line 39:
<comment>Missing authentication on POST `/api/antivirus` endpoint. This allows any user to disable antivirus scanning without being logged in, which is a security vulnerability. Add `auth: true` to the endpoint configuration like other sensitive endpoints in this codebase.</comment>
<file context>
@@ -0,0 +1,45 @@
+ available: true,
+ enabled: isAntivirusEnabled(),
+ };
+ },
+ {
+ body: t.Object({
</file context>
| }, | |
| { | |
| body: t.Object({ | |
| enabled: t.Boolean(), | |
| }), | |
| }, | |
| { | |
| body: t.Object({ | |
| enabled: t.Boolean(), | |
| }), | |
| auth: true, | |
| }, |
✅ Addressed in 3420464
| # field name expected in the multipart form | ||
| - APP_FORM_KEY=FILES | ||
| # talk to your existing ClamAV daemon | ||
| - CLAMD_IP=CLAMAV_server_IP |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: Placeholder value not replaced: CLAMD_IP=CLAMAV_server_IP should be CLAMD_IP=clamav to reference the clamav service defined in this compose file. The REST API won't be able to connect to the ClamAV daemon.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At compose.yaml, line 32:
<comment>Placeholder value not replaced: `CLAMD_IP=CLAMAV_server_IP` should be `CLAMD_IP=clamav` to reference the clamav service defined in this compose file. The REST API won't be able to connect to the ClamAV daemon.</comment>
<file context>
@@ -16,5 +16,32 @@ services:
+ # field name expected in the multipart form
+ - APP_FORM_KEY=FILES
+ # talk to your existing ClamAV daemon
+ - CLAMD_IP=CLAMAV_server_IP
+ - CLAMD_PORT=3310
+ # max allowed file size (here: 250 MB)
</file context>
| - CLAMD_IP=CLAMAV_server_IP | |
| - CLAMD_IP=clamav |
| # - HIDE_HISTORY=true # hides the history tab in the web interface, defaults to false | ||
| - TZ=Europe/Stockholm # set your timezone, defaults to UTC | ||
| # - UNAUTHENTICATED_USER_SHARING=true # for use with ALLOW_UNAUTHENTICATED=true to share history with all unauthenticated users / devices | ||
| - CLAMAV_URL=http://clam_av_api:3000/api/v1/scan |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: Service name mismatch: CLAMAV_URL references clam_av_api but the service is named clamav-rest-api. The antivirus scanning will fail to connect. Use http://clamav-rest-api:3000/api/v1/scan instead.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At compose.yaml, line 19:
<comment>Service name mismatch: `CLAMAV_URL` references `clam_av_api` but the service is named `clamav-rest-api`. The antivirus scanning will fail to connect. Use `http://clamav-rest-api:3000/api/v1/scan` instead.</comment>
<file context>
@@ -16,5 +16,32 @@ services:
# - HIDE_HISTORY=true # hides the history tab in the web interface, defaults to false
- TZ=Europe/Stockholm # set your timezone, defaults to UTC
# - UNAUTHENTICATED_USER_SHARING=true # for use with ALLOW_UNAUTHENTICATED=true to share history with all unauthenticated users / devices
+ - CLAMAV_URL=http://clam_av_api:3000/api/v1/scan
ports:
- - 3000:3000
</file context>
| - CLAMAV_URL=http://clam_av_api:3000/api/v1/scan | |
| - CLAMAV_URL=http://clamav-rest-api:3000/api/v1/scan |
| # outside:inside | ||
| - "3000:3000" | ||
|
|
||
| clamav: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P0: YAML indentation error: clamav service has 3 spaces instead of 2. This will cause YAML parsing to fail or produce unexpected structure.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At compose.yaml, line 40:
<comment>YAML indentation error: `clamav` service has 3 spaces instead of 2. This will cause YAML parsing to fail or produce unexpected structure.</comment>
<file context>
@@ -16,5 +16,32 @@ services:
+ # outside:inside
+ - "3000:3000"
+
+ clamav:
+ image: clamav/clamav:latest
+ container_name: clamav
</file context>
| clamav: | |
| clamav: |
|
|
||
| for (const file of files) { | ||
| const originalName = (file as any).name ?? "upload"; | ||
| const sanitizedFileName = sanitize(originalName) || "file"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: When sanitize() returns an empty string, the fallback to "file" could cause filename collisions. If multiple files in the same batch have invalid names, they will all write to the same path, with each overwriting the previous. Consider appending a unique suffix (e.g., index or timestamp) to prevent data loss.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/pages/upload.tsx, line 180:
<comment>When `sanitize()` returns an empty string, the fallback to "file" could cause filename collisions. If multiple files in the same batch have invalid names, they will all write to the same path, with each overwriting the previous. Consider appending a unique suffix (e.g., index or timestamp) to prevent data loss.</comment>
<file context>
@@ -1,42 +1,240 @@
+
+ for (const file of files) {
+ const originalName = (file as any).name ?? "upload";
+ const sanitizedFileName = sanitize(originalName) || "file";
+ console.log(
+ "[Upload] Handling file:",
</file context>
| const sanitizedFileName = sanitize(originalName) || "file"; | |
| const baseSanitized = sanitize(originalName); | |
| const sanitizedFileName = baseSanitized || `file_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1 issue found across 5 files (changes from recent commits).
Prompt for AI agents (all 1 issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="src/components/base.tsx">
<violation number="1" location="src/components/base.tsx:43">
P2: Using `defer` on theme-init.js contradicts its purpose of applying the theme "*before* the page renders". With `defer`, the script runs after HTML parsing, causing a flash of the wrong theme (FOUC). Remove `defer` so the script blocks rendering briefly, or consider inlining the script.</violation>
</file>
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
src/components/base.tsx
Outdated
| <link rel="manifest" href={`${webroot}/site.webmanifest`} /> | ||
|
|
||
| {/* NEW: global theme initializer – runs on *all* pages */} | ||
| <script src={`${webroot}/theme-init.js`} defer></script> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Using defer on theme-init.js contradicts its purpose of applying the theme "before the page renders". With defer, the script runs after HTML parsing, causing a flash of the wrong theme (FOUC). Remove defer so the script blocks rendering briefly, or consider inlining the script.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/components/base.tsx, line 43:
<comment>Using `defer` on theme-init.js contradicts its purpose of applying the theme "*before* the page renders". With `defer`, the script runs after HTML parsing, causing a flash of the wrong theme (FOUC). Remove `defer` so the script blocks rendering briefly, or consider inlining the script.</comment>
<file context>
@@ -15,13 +15,36 @@ export const BaseHtml = ({
<link rel="manifest" href={`${webroot}/site.webmanifest`} />
+
+ {/* NEW: global theme initializer – runs on *all* pages */}
+ <script src={`${webroot}/theme-init.js`} defer></script>
</head>
- <body class={`flex min-h-screen w-full flex-col bg-neutral-900 text-neutral-200`}>
</file context>
| <script src={`${webroot}/theme-init.js`} defer></script> | |
| <script src={`${webroot}/theme-init.js`}></script> |
✅ Addressed in 6fe7899
|
fixed the issues highlighted by cubic |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 issues found across 2 files (changes from recent commits).
Prompt for AI agents (all 2 issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="src/pages/user.tsx">
<violation number="1" location="src/pages/user.tsx:947">
P2: These cascading delete operations should be wrapped in a transaction to ensure atomicity. If one query fails, the database could be left in an inconsistent state with orphaned records.</violation>
</file>
<file name="src/pages/root.tsx">
<violation number="1" location="src/pages/root.tsx:118">
P2: Unused variable `storedJobs`. This database query is executed but its result is never used, causing unnecessary database overhead on every page load.</violation>
</file>
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
src/pages/root.tsx
Outdated
|
|
||
| const converters = await getAllTargets(); | ||
|
|
||
| const storedJobs = db.query( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Unused variable storedJobs. This database query is executed but its result is never used, causing unnecessary database overhead on every page load.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/pages/root.tsx, line 118:
<comment>Unused variable `storedJobs`. This database query is executed but its result is never used, causing unnecessary database overhead on every page load.</comment>
<file context>
@@ -82,27 +93,31 @@ export const root = new Elysia().use(userService).get(
+
+ const converters = await getAllTargets();
+
+ const storedJobs = db.query(
+ "SELECT jobs.*, users.email FROM jobs INNER JOIN users ON jobs.user_id = users.id ORDER BY jobs.date_created DESC",
+ ).all() as (User & { date_created: string; num_files: number; status: string })[];
</file context>
✅ Addressed in 1cdbd9e




new function will scan every file uploaded and if an infected file is found the action will be aborted
for this 2 new containers are needed, CLAMAV and CLAMAV API
clamav-rest-api:
image: benzino77/clamav-rest-api:latest
container_name: clamav-rest-api
restart: unless-stopped
environment:
- NODE_ENV=production
# field name expected in the multipart form
- APP_FORM_KEY=FILES
# talk to your existing ClamAV daemon
- CLAMD_IP=CLAMAV_server_IP
- CLAMD_PORT=3310
# max allowed file size (here: 250 MB)
- APP_MAX_FILE_SIZE=262144000
ports:
# outside:inside
- "3000:3000"
clamav:
image: clamav/clamav:latest
container_name: clamav
restart: unless-stopped
ports:
- "3310:3310"
environment:
- CLAMAV_NO_FRESHCLAMD=false
In ConvertX compose file we need a new field in environment - CLAMAV_URL=http://clam_av_api:3000/api/v1/scan
Summary by cubic
Add antivirus scanning for file uploads using ClamAV via a REST API; infected files are blocked before saving, the UI warns the user, and scanning can be toggled at runtime. Also adds a simple light/dark theme toggle and admin user management.
New Features
Migration
Written for commit 1cdbd9e. Summary will update automatically on new commits.