Files
M-CTF-2025/rodchenko/app/utils/security.py

84 lines
2.0 KiB
Python
Raw Normal View History

2025-12-14 10:39:18 +03:00
import socket
2025-12-14 10:49:32 +03:00
import json
2025-12-14 10:39:18 +03:00
import base64
import ipaddress
from urllib.parse import urlparse
2025-12-14 10:49:32 +03:00
2025-12-14 10:39:18 +03:00
def load_artwork_settings(settings_data):
2025-12-14 10:49:32 +03:00
if not settings_data:
return None
2025-12-14 10:39:18 +03:00
try:
2025-12-14 10:49:32 +03:00
# Пробуем base64 + JSON
try:
raw = base64.b64decode(settings_data)
return json.loads(raw)
except:
pass
# Просто JSON
2025-12-14 10:39:18 +03:00
try:
2025-12-14 10:49:32 +03:00
return json.loads(settings_data)
2025-12-14 10:39:18 +03:00
except:
pass
2025-12-14 10:49:32 +03:00
# Fallback — plain text description
return {'description': settings_data}
except:
2025-12-14 10:39:18 +03:00
return {'description': settings_data}
def save_artwork_description(description):
if not description:
return None
2025-12-14 10:49:32 +03:00
return json.dumps({'description': description})
2025-12-14 10:39:18 +03:00
class ArtworkConfig:
def __init__(self, colors=None, animation=False, public=True):
self.colors = colors or ["#FF0000", "#00FF00", "#0000FF"]
self.animation = animation
self.public = public
def __repr__(self):
return f"ArtworkConfig(colors={self.colors}, animation={self.animation}, public={self.public})"
def __str__(self):
return self.__repr__()
def __reduce__(self):
return (self.__class__, (self.colors, self.animation, self.public))
def is_safe_url(url: str):
try:
parsed = urlparse(url)
if parsed.scheme not in ("http", "https"):
return False, "403"
hostname = parsed.hostname
if not hostname:
return False, "403"
try:
ip_str = socket.gethostbyname(hostname)
except socket.gaierror:
return False, "403"
try:
ip = ipaddress.ip_address(ip_str)
except ValueError:
return False, "403"
if (
ip.is_loopback
or ip.is_private
or ip.is_link_local
or ip.is_unspecified
):
return False, "403"
return True, ip_str
except Exception:
return False, "403"