Add input validation for project and request names

This commit is contained in:
Pavel Baksy 2026-01-05 11:38:58 +01:00
parent 3389a87678
commit 74acbcca7c

View File

@ -758,6 +758,62 @@ class RosterWindow(Adw.ApplicationWindow):
# Project Management Methods
def _validate_project_name(self, name: str) -> tuple[bool, str]:
"""
Validate project name.
Args:
name: The project name to validate
Returns:
Tuple of (is_valid, error_message)
"""
# Check if empty
if not name or not name.strip():
return False, "Project name cannot be empty"
# Check length (max 100 characters)
if len(name) > 100:
return False, "Project name is too long (max 100 characters)"
# Check for invalid characters (file system unsafe characters)
invalid_chars = ['/', '\\', ':', '*', '?', '"', '<', '>', '|', '\0']
for char in invalid_chars:
if char in name:
return False, f"Project name cannot contain '{char}'"
# Check if it's only whitespace
if name.strip() == '':
return False, "Project name cannot be only whitespace"
return True, ""
def _validate_request_name(self, name: str) -> tuple[bool, str]:
"""
Validate request name.
Args:
name: The request name to validate
Returns:
Tuple of (is_valid, error_message)
"""
# Check if empty
if not name or not name.strip():
return False, "Request name cannot be empty"
# Check length (max 200 characters)
if len(name) > 200:
return False, "Request name is too long (max 200 characters)"
# Check for invalid characters (file system unsafe characters)
invalid_chars = ['/', '\\', ':', '*', '?', '"', '<', '>', '|', '\0']
for char in invalid_chars:
if char in name:
return False, f"Request name cannot contain '{char}'"
return True, ""
def _load_projects(self) -> None:
"""Load and display projects."""
# Clear existing
@ -796,9 +852,13 @@ class RosterWindow(Adw.ApplicationWindow):
def on_response(dlg, response):
if response == "create":
name = entry.get_text().strip()
if name:
is_valid, error_msg = self._validate_project_name(name)
if is_valid:
self.project_manager.add_project(name)
self._load_projects()
self._show_toast(f"Project '{name}' created")
else:
self._show_toast(error_msg)
dialog.connect("response", on_response)
dialog.present(self)
@ -848,9 +908,13 @@ class RosterWindow(Adw.ApplicationWindow):
if response == "save":
new_name = entry.get_text().strip()
new_icon = icon_button.selected_icon
if new_name:
is_valid, error_msg = self._validate_project_name(new_name)
if is_valid:
self.project_manager.update_project(project.id, new_name, new_icon)
self._load_projects()
self._show_toast(f"Project updated")
else:
self._show_toast(error_msg)
dialog.connect("response", on_response)
dialog.present(self)
@ -982,7 +1046,8 @@ class RosterWindow(Adw.ApplicationWindow):
def on_response(dlg, response):
if response == "save":
name = entry.get_text().strip()
if name:
is_valid, error_msg = self._validate_request_name(name)
if is_valid:
selected = dropdown.get_selected()
project = projects[selected]
# Check for duplicate name
@ -998,6 +1063,8 @@ class RosterWindow(Adw.ApplicationWindow):
# Clear modified flag on current tab
self._mark_tab_as_saved(saved_request.id, name, request, scripts)
else:
self._show_toast(error_msg)
dialog.connect("response", on_response)
dialog.present(self)
@ -1094,7 +1161,8 @@ class RosterWindow(Adw.ApplicationWindow):
def on_response(dlg, response):
if response == "save":
name = entry.get_text().strip()
if name:
is_valid, error_msg = self._validate_request_name(name)
if is_valid:
# Check for duplicate name
existing = self.project_manager.find_request_by_name(project.id, name)
if existing:
@ -1108,6 +1176,8 @@ class RosterWindow(Adw.ApplicationWindow):
# Clear modified flag on current tab
self._mark_tab_as_saved(saved_request.id, name, request)
else:
self._show_toast(error_msg)
dialog.connect("response", on_response)
dialog.present(self)