Skip to content
Merged
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
4 changes: 4 additions & 0 deletions docs/CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,7 @@ This intentionally changes the previous ability to pass arbitrary remote URLs. T
The local Spring Boot `/files/upload` and `/files/editor/upload` endpoints now discard directory components from browser-supplied filenames, reject empty/control-character/oversized names with HTTP 400, and stream upload bytes into the configured local `backend/files/` directory instead of loading whole files into memory. Returned upload URLs encode the stored filename. Downloads match either the exact generated filename or the generated UUID followed by an underscore, avoiding arbitrary substring matches.

**Scope:** This is path and memory hygiene for a local prototype, **not** user authentication or upload content validation. Limit public access, review content-type restrictions, enforce quotas and scan untrusted files before production use. Existing previously uploaded files are not renamed.

## Local video progress WebSocket

The Flask-SocketIO progress channel accepts browser origins only from `http://localhost:8100` and `http://127.0.0.1:8100`; wildcard CORS has been removed. This matches the loopback-only Vite development server. If you use a different frontend origin, do **not** remove the restriction by setting `*`; implement a deployment-specific authenticated origin and access policy instead. An allowed browser Origin is not proof of a trusted user.
3 changes: 2 additions & 1 deletion inference/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from predict import predictImg
from input_validation import resolve_weight_file, validate_local_media_url
from image_requests import process_image
from socket_policy import LOCAL_VITE_ORIGINS
from flask_socketio import SocketIO, emit


Expand All @@ -16,7 +17,7 @@ class VideoProcessingApp:
def __init__(self, host='127.0.0.1', port=5000):
"""初始化 Flask 应用并设置路由"""
self.app = Flask(__name__)
self.socketio = SocketIO(self.app, cors_allowed_origins="*") # 初始化 SocketIO
self.socketio = SocketIO(self.app, cors_allowed_origins=list(LOCAL_VITE_ORIGINS))
self.host = host
self.port = port
self.setup_routes()
Expand Down
10 changes: 10 additions & 0 deletions inference/socket_policy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""Allowed browser origins for CropLens' localhost-only Socket.IO demo.

This is origin-based defense-in-depth, not authentication. Keep the
inference server on loopback; never treat this as a public access policy.
"""

LOCAL_VITE_ORIGINS = (
"http://localhost:8100",
"http://127.0.0.1:8100",
)
22 changes: 22 additions & 0 deletions inference/tests/test_socket_policy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""Regression guardrails for the local demo's websocket Origin allowlist."""
import unittest

from socket_policy import LOCAL_VITE_ORIGINS


class SocketOriginPolicyTests(unittest.TestCase):
def test_only_local_vite_origins_are_allowed(self):
self.assertEqual(
set(LOCAL_VITE_ORIGINS),
{"http://localhost:8100", "http://127.0.0.1:8100"},
)

def test_no_wildcard_or_remote_origin(self):
for origin in LOCAL_VITE_ORIGINS:
self.assertNotIn("*", origin)
self.assertNotIn("0.0.0.0", origin)
self.assertNotIn("https://", origin)


if __name__ == "__main__":
unittest.main()
Loading