04/23 Enhance app functionalities 2

This commit is contained in:
2026-04-23 17:32:44 -04:00
parent f4eea48e4d
commit 58c6218c14
8 changed files with 609 additions and 28 deletions
+54
View File
@@ -427,6 +427,21 @@ class WebsiteDialog(tk.Toplevel):
if not name or not url:
show_error("Name and URL are required.")
return
# Normalise and validate URL before writing to the database.
# Reject schemes that could be executed in-browser (javascript:, data:, etc.)
# and enforce that a host is present so the health-check thread and the
# "open in browser" action both receive a usable address.
url = _validate_and_normalise_url(url)
if url is None:
show_error(
"The URL entered is not valid.\n\n"
"Please enter a full web address, e.g.:\n"
" https://www.example.com\n"
" http://intranet.local/app"
)
return
if visibility == "assigned" and not assigned_user_ids:
show_error("Please assign at least one user, or set visibility to All Users.")
return
@@ -463,3 +478,42 @@ class WebsiteDialog(tk.Toplevel):
self.destroy()
except Exception as e:
show_error(f"Save failed:\n{e}")
# ─── URL validation helper ────────────────────────────────────────────────────
def _validate_and_normalise_url(raw: str) -> "str | None":
"""
Validate and normalise a user-supplied URL string.
Rules:
- If no scheme is present, prepend 'https://'.
- Only 'http' and 'https' schemes are accepted.
- A non-empty netloc (host) must be present.
- Returns the normalised URL string on success, None on failure.
This prevents dangerous schemes (javascript:, data:, file:, etc.) from
reaching the database, the health-check thread, or webbrowser.open().
"""
import urllib.parse
if not raw:
return None
# Prepend https:// if no scheme is given so urlparse can parse the host
if "://" not in raw:
raw = "https://" + raw
try:
parts = urllib.parse.urlparse(raw)
except Exception:
return None
if parts.scheme.lower() not in ("http", "https"):
return None
if not parts.netloc:
return None
# Reconstruct a clean URL (strips any leading/trailing whitespace artefacts)
return urllib.parse.urlunparse(parts)