This commit is contained in:
copyrighttxt
2026-08-03 17:49:31 -04:00
committed by GitHub
parent 7ddc6a3346
commit cec64d598f
2 changed files with 1 additions and 131 deletions
+1 -18
View File
@@ -22,7 +22,7 @@ from config import Config
config = Config()
from app.routes.asset import migrateAsset
from app.util import auth, assetversion, discord, redislock, announcement
from app.util import auth, assetversion, discord, redislock
from app.services import economy, gameserver_comm
from app.models.admin_permissions import AdminPermissions
from app.models.user import User
@@ -297,23 +297,6 @@ def websitemessage():
def websitemessage_post():
AdminPermissionRequired('UpdateWebsiteMessage')
raw_message = request.form.get('message', '').strip()
is_valid, error_msg = announcement.validate_announcement(raw_message)
if not is_valid:
flash(f"Invalid announcement: {error_msg}", "danger")
return redirect("/admin/websitemessage")
sanitized_message = announcement.sanitize_announcement(raw_message)
AuthenticatedUser: User = auth.GetCurrentUser()
announcement.log_announcement_to_discord(
username=AuthenticatedUser.username,
user_id=AuthenticatedUser.id,
message=sanitized_message,
action="updated"
)
redis_controller.set("website_wide_message", sanitized_message)
flash("Announcement updated successfully", "success")
return redirect("/admin/websitemessage")
-113
View File
@@ -1,113 +0,0 @@
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