Word
This commit is contained in:
@@ -22,7 +22,7 @@ from config import Config
|
|||||||
config = Config()
|
config = Config()
|
||||||
|
|
||||||
from app.routes.asset import migrateAsset
|
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.services import economy, gameserver_comm
|
||||||
from app.models.admin_permissions import AdminPermissions
|
from app.models.admin_permissions import AdminPermissions
|
||||||
from app.models.user import User
|
from app.models.user import User
|
||||||
@@ -297,23 +297,6 @@ def websitemessage():
|
|||||||
def websitemessage_post():
|
def websitemessage_post():
|
||||||
AdminPermissionRequired('UpdateWebsiteMessage')
|
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)
|
redis_controller.set("website_wide_message", sanitized_message)
|
||||||
flash("Announcement updated successfully", "success")
|
flash("Announcement updated successfully", "success")
|
||||||
return redirect("/admin/websitemessage")
|
return redirect("/admin/websitemessage")
|
||||||
|
|||||||
@@ -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
|
|
||||||
|
|||||||
Reference in New Issue
Block a user