114 lines
3.0 KiB
Python
114 lines
3.0 KiB
Python
import re
|
|
import logging
|
|
import requests
|
|
import threading
|
|
from datetime import datetime
|
|
from config import Config
|
|
|
|
config = Config()
|
|
|
|
|
|
def sanitize_announcement(message: str) -> str:
|
|
if not isinstance(message, str):
|
|
return ""
|
|
|
|
message = message.strip()
|
|
|
|
if not message:
|
|
return ""
|
|
|
|
message = re.sub(r'<[^>]+>', '', message)
|
|
message = re.sub(r'(javascript|data|vbscript):', '', message, flags=re.IGNORECASE)
|
|
message = re.sub(r'\s*on\w+\s*=', '', message, flags=re.IGNORECASE)
|
|
message = message[:500]
|
|
|
|
return message
|
|
|
|
|
|
def validate_announcement(message: str) -> tuple[bool, str]:
|
|
if not isinstance(message, str):
|
|
return False, "Message must be a string"
|
|
|
|
if len(message.strip()) == 0:
|
|
return False, "Message cannot be empty"
|
|
|
|
if len(message) > 500:
|
|
return False, "Message is too long (max 500 characters)"
|
|
|
|
suspicious_patterns = [
|
|
r'<script',
|
|
r'javascript:',
|
|
r'onerror\s*=',
|
|
r'onclick\s*=',
|
|
r'onload\s*=',
|
|
r'data:text/html',
|
|
r'vbscript:',
|
|
r'<iframe',
|
|
r'<object',
|
|
r'<embed',
|
|
]
|
|
|
|
for pattern in suspicious_patterns:
|
|
if re.search(pattern, message, re.IGNORECASE):
|
|
return False, "Message contains potentially dangerous content"
|
|
|
|
return True, ""
|
|
|
|
|
|
def log_announcement_to_discord(
|
|
username: str,
|
|
user_id: int,
|
|
message: str,
|
|
action: str = "updated",
|
|
avatar_url: str = None
|
|
) -> bool:
|
|
if not config.DISCORD_ADMIN_LOGS_WEBHOOK:
|
|
logging.warning("Discord webhook not configured for announcement logging")
|
|
return False
|
|
|
|
if avatar_url is None:
|
|
avatar_url = f"https://www.nexium.fit/Thumbs/Head.ashx?x=48&y=48&userId={str(user_id)}"
|
|
|
|
embed = {
|
|
"type": "rich",
|
|
"title": f"Website Announcement {action.capitalize()}",
|
|
"description": message if message else "(empty message)",
|
|
"color": 0x2196F3,
|
|
"author": {
|
|
"name": username,
|
|
"icon_url": avatar_url
|
|
},
|
|
"footer": {
|
|
"text": "NEXIUM - Announcement Logs"
|
|
},
|
|
"timestamp": datetime.utcnow().isoformat()
|
|
}
|
|
|
|
def send_webhook():
|
|
try:
|
|
response = requests.post(
|
|
url=config.DISCORD_ADMIN_LOGS_WEBHOOK,
|
|
json={
|
|
"username": "NEXIUM - Announcement Logs",
|
|
"embeds": [embed],
|
|
"avatar_url": avatar_url
|
|
},
|
|
timeout=15
|
|
)
|
|
if response.status_code not in [200, 204]:
|
|
logging.warning(
|
|
f"Failed to log announcement to Discord: "
|
|
f"status={response.status_code}, response={response.text}"
|
|
)
|
|
return False
|
|
return True
|
|
except Exception as e:
|
|
logging.error(f"Exception while logging announcement to Discord: {str(e)}")
|
|
return False
|
|
|
|
thread = threading.Thread(target=send_webhook)
|
|
thread.daemon = True
|
|
thread.start()
|
|
|
|
return True
|