Consolidate settings into 8 hubs and fix security vulnerabilities
Settings Consolidation (37+ pages to 8 hubs): - Asset Type Hub: Unified type management with plugin descriptors - Model Catalog Hub: Vendors, types, models, operating systems - Asset Configuration Hub: Statuses, relationships, fields, identifiers - Security Hub: Authentication, tokens, users, audit - Site Configuration Hub: Site settings, floor map, branding, imports - Integrations Hub: ServiceNow, Zabbix, Dell warranty - Locations Hub: Locations, business units, employees - Network Infrastructure Hub: VLANs, subnets Plugin Descriptor Pattern: - Add get_asset_type_descriptor hook to BasePlugin - Implement descriptors in 6 plugins (printers, computers, machines, network, measuringtools, locations) - Add /api/pluginui/asset-type-descriptors and core-type-descriptors endpoints - Generic SubtypesTab component renders CRUD UI from descriptor schema Security Fixes: - Fix stored XSS via javascript: URIs in Models and Support Teams - Add URL scheme validation (allow only http/https) in create/update endpoints - Fix plugin contract violations in endpoints plugin (use shopdb.api imports) - Add missing requiresAdmin guard to printer model supplies route - Add user-facing error messages to API token load failures Integration Improvements: - Add persistent tab navigation to ServiceNow, Zabbix, and Dell Warranty settings - Standardize integration settings UI across all three pages - Fix tab visibility when navigating between integrations Tested with 94-agent orchestrated review for ADR compliance and security.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
import glob
|
||||
import os
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from flask import Blueprint, request, current_app
|
||||
from flask_jwt_extended import jwt_required
|
||||
@@ -39,6 +40,16 @@ def _modelimage_dir():
|
||||
return os.path.join(current_app.instance_path, 'modelimages')
|
||||
|
||||
|
||||
def _validate_url_scheme(url):
|
||||
"""Validate that URL uses safe scheme (prevents XSS via javascript: URIs)."""
|
||||
if not url:
|
||||
return True
|
||||
parsed = urlparse(url)
|
||||
if parsed.scheme and parsed.scheme not in ['http', 'https']:
|
||||
raise ValueError(f"Invalid URL scheme '{parsed.scheme}'. Only http:// and https:// are allowed.")
|
||||
return True
|
||||
|
||||
|
||||
@models_bp.route('', methods=['GET'])
|
||||
@require_permission('assets.view')
|
||||
def list_models():
|
||||
@@ -127,6 +138,13 @@ def create_model():
|
||||
http_code=409
|
||||
)
|
||||
|
||||
# Validate URL scheme to prevent XSS
|
||||
try:
|
||||
_validate_url_scheme(data.get('documentationurl'))
|
||||
_validate_url_scheme(data.get('imageurl'))
|
||||
except ValueError as e:
|
||||
return error_response(ErrorCodes.VALIDATION_ERROR, str(e))
|
||||
|
||||
m = Model(
|
||||
modelnumber=data['modelnumber'],
|
||||
vendorid=data.get('vendorid'),
|
||||
@@ -162,6 +180,15 @@ def update_model(model_id: int):
|
||||
if not data:
|
||||
return error_response(ErrorCodes.VALIDATION_ERROR, 'No data provided')
|
||||
|
||||
# Validate URL schemes to prevent XSS
|
||||
try:
|
||||
if 'documentationurl' in data:
|
||||
_validate_url_scheme(data['documentationurl'])
|
||||
if 'imageurl' in data:
|
||||
_validate_url_scheme(data['imageurl'])
|
||||
except ValueError as e:
|
||||
return error_response(ErrorCodes.VALIDATION_ERROR, str(e))
|
||||
|
||||
for key in ['modelnumber', 'vendorid', 'modeltypeid', 'description', 'imageurl', 'documentationurl', 'notes', 'isactive']:
|
||||
if key in data:
|
||||
setattr(m, key, data[key])
|
||||
|
||||
Reference in New Issue
Block a user