modified: app.py
modified: bot.py modified: templates/server_settings.html
This commit is contained in:
65
app.py
65
app.py
@@ -46,6 +46,17 @@ app.config["SESSION_TYPE"] = "filesystem" # Oder 'redis' für Redis-basierte Sp
|
|||||||
Session(app)
|
Session(app)
|
||||||
print(f"Session Type: {app.config['SESSION_TYPE']}")
|
print(f"Session Type: {app.config['SESSION_TYPE']}")
|
||||||
|
|
||||||
|
import json as _json
|
||||||
|
|
||||||
|
@app.template_filter("from_json_ids")
|
||||||
|
def from_json_ids(value):
|
||||||
|
"""Converts a JSON list of role ID strings to a space-separated string for display."""
|
||||||
|
try:
|
||||||
|
ids = _json.loads(value)
|
||||||
|
return " ".join(str(i) for i in ids)
|
||||||
|
except Exception:
|
||||||
|
return value or ""
|
||||||
|
|
||||||
DB_HOST = os.getenv("DB_HOST")
|
DB_HOST = os.getenv("DB_HOST")
|
||||||
DB_PORT = os.getenv("DB_PORT")
|
DB_PORT = os.getenv("DB_PORT")
|
||||||
DB_USER = os.getenv("DB_USER")
|
DB_USER = os.getenv("DB_USER")
|
||||||
@@ -735,7 +746,23 @@ def server_settings(guild_id):
|
|||||||
auto_mute_duration = request.form.get("auto_mute_duration", "1h")
|
auto_mute_duration = request.form.get("auto_mute_duration", "1h")
|
||||||
log_channel_id = request.form.get("log_channel_id")
|
log_channel_id = request.form.get("log_channel_id")
|
||||||
mod_log_enabled = bool(request.form.get("mod_log_enabled"))
|
mod_log_enabled = bool(request.form.get("mod_log_enabled"))
|
||||||
|
|
||||||
|
# Honeypot fields
|
||||||
|
honeypot_enabled = bool(request.form.get("honeypot_enabled"))
|
||||||
|
honeypot_channel_id = request.form.get("honeypot_channel_id")
|
||||||
|
honeypot_preserve_old_accounts = bool(request.form.get("honeypot_preserve_old_accounts"))
|
||||||
|
honeypot_get_role = request.form.get("honeypot_get_role") or None
|
||||||
|
honeypot_log_channel_id = request.form.get("honeypot_log_channel_id")
|
||||||
|
honeypot_ignore_roles_raw = request.form.get("honeypot_ignore_roles", "").strip()
|
||||||
|
honeypot_acc_age_min = int(request.form.get("honeypot_acc_age_min", 30))
|
||||||
|
|
||||||
|
# Build ignore roles JSON
|
||||||
|
import json as _json
|
||||||
|
honeypot_ignore_roles = None
|
||||||
|
if honeypot_ignore_roles_raw:
|
||||||
|
ids = [r.strip() for r in honeypot_ignore_roles_raw.replace(",", " ").split() if r.strip().isdigit()]
|
||||||
|
honeypot_ignore_roles = _json.dumps(ids) if ids else None
|
||||||
|
|
||||||
# Validierung
|
# Validierung
|
||||||
if max_warn_threshold < 1 or max_warn_threshold > 10:
|
if max_warn_threshold < 1 or max_warn_threshold > 10:
|
||||||
flash("Warn-Limit muss zwischen 1 und 10 liegen.", "danger")
|
flash("Warn-Limit muss zwischen 1 und 10 liegen.", "danger")
|
||||||
@@ -750,25 +777,38 @@ def server_settings(guild_id):
|
|||||||
# Konvertiere leere Strings zu NULL
|
# Konvertiere leere Strings zu NULL
|
||||||
mute_role_id = int(mute_role_id) if mute_role_id and mute_role_id.isdigit() else None
|
mute_role_id = int(mute_role_id) if mute_role_id and mute_role_id.isdigit() else None
|
||||||
log_channel_id = int(log_channel_id) if log_channel_id and log_channel_id.isdigit() else None
|
log_channel_id = int(log_channel_id) if log_channel_id and log_channel_id.isdigit() else None
|
||||||
|
honeypot_channel_id = int(honeypot_channel_id) if honeypot_channel_id and honeypot_channel_id.isdigit() else None
|
||||||
|
honeypot_log_channel_id = int(honeypot_log_channel_id) if honeypot_log_channel_id and honeypot_log_channel_id.isdigit() else None
|
||||||
|
|
||||||
# Update oder Insert Einstellungen
|
# Update oder Insert Einstellungen
|
||||||
if current_settings:
|
if current_settings:
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
UPDATE guild_settings
|
UPDATE guild_settings
|
||||||
SET mute_role_id = %s, mute_role_name = %s, auto_create_mute_role = %s,
|
SET mute_role_id = %s, mute_role_name = %s, auto_create_mute_role = %s,
|
||||||
max_warn_threshold = %s, auto_mute_on_warns = %s, auto_mute_duration = %s,
|
max_warn_threshold = %s, auto_mute_on_warns = %s, auto_mute_duration = %s,
|
||||||
log_channel_id = %s, mod_log_enabled = %s
|
log_channel_id = %s, mod_log_enabled = %s,
|
||||||
|
honeypot_enabled = %s, honeypot_channel_id = %s,
|
||||||
|
honeypot_preserve_old_accounts = %s, honeypot_get_role = %s,
|
||||||
|
honeypot_log_channel_id = %s, honeypot_ignore_roles = %s,
|
||||||
|
honeypot_acc_age_min = %s
|
||||||
WHERE guild_id = %s
|
WHERE guild_id = %s
|
||||||
""", (mute_role_id, mute_role_name, auto_create_mute_role, max_warn_threshold,
|
""", (mute_role_id, mute_role_name, auto_create_mute_role, max_warn_threshold,
|
||||||
auto_mute_on_warns, auto_mute_duration, log_channel_id, mod_log_enabled, guild_id))
|
auto_mute_on_warns, auto_mute_duration, log_channel_id, mod_log_enabled,
|
||||||
|
honeypot_enabled, honeypot_channel_id, honeypot_preserve_old_accounts,
|
||||||
|
honeypot_get_role, honeypot_log_channel_id, honeypot_ignore_roles,
|
||||||
|
honeypot_acc_age_min, guild_id))
|
||||||
else:
|
else:
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
INSERT INTO guild_settings
|
INSERT INTO guild_settings
|
||||||
(guild_id, mute_role_id, mute_role_name, auto_create_mute_role, max_warn_threshold,
|
(guild_id, mute_role_id, mute_role_name, auto_create_mute_role, max_warn_threshold,
|
||||||
auto_mute_on_warns, auto_mute_duration, log_channel_id, mod_log_enabled)
|
auto_mute_on_warns, auto_mute_duration, log_channel_id, mod_log_enabled,
|
||||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
|
honeypot_enabled, honeypot_channel_id, honeypot_preserve_old_accounts,
|
||||||
|
honeypot_get_role, honeypot_log_channel_id, honeypot_ignore_roles, honeypot_acc_age_min)
|
||||||
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||||
""", (guild_id, mute_role_id, mute_role_name, auto_create_mute_role, max_warn_threshold,
|
""", (guild_id, mute_role_id, mute_role_name, auto_create_mute_role, max_warn_threshold,
|
||||||
auto_mute_on_warns, auto_mute_duration, log_channel_id, mod_log_enabled))
|
auto_mute_on_warns, auto_mute_duration, log_channel_id, mod_log_enabled,
|
||||||
|
honeypot_enabled, honeypot_channel_id, honeypot_preserve_old_accounts,
|
||||||
|
honeypot_get_role, honeypot_log_channel_id, honeypot_ignore_roles, honeypot_acc_age_min))
|
||||||
|
|
||||||
connection.commit()
|
connection.commit()
|
||||||
flash("Server-Einstellungen erfolgreich gespeichert!", "success")
|
flash("Server-Einstellungen erfolgreich gespeichert!", "success")
|
||||||
@@ -794,7 +834,14 @@ def server_settings(guild_id):
|
|||||||
"auto_mute_on_warns": False,
|
"auto_mute_on_warns": False,
|
||||||
"auto_mute_duration": "1h",
|
"auto_mute_duration": "1h",
|
||||||
"log_channel_id": None,
|
"log_channel_id": None,
|
||||||
"mod_log_enabled": True
|
"mod_log_enabled": True,
|
||||||
|
"honeypot_enabled": False,
|
||||||
|
"honeypot_channel_id": None,
|
||||||
|
"honeypot_preserve_old_accounts": False,
|
||||||
|
"honeypot_get_role": None,
|
||||||
|
"honeypot_log_channel_id": None,
|
||||||
|
"honeypot_ignore_roles": None,
|
||||||
|
"honeypot_acc_age_min": 30
|
||||||
}
|
}
|
||||||
|
|
||||||
# Hole Servername
|
# Hole Servername
|
||||||
|
|||||||
224
bot.py
224
bot.py
@@ -2873,8 +2873,140 @@ async def on_message(message):
|
|||||||
user_id = message.author.id
|
user_id = message.author.id
|
||||||
guild_id = message.guild.id
|
guild_id = message.guild.id
|
||||||
member = message.author # Das Member-Objekt für Datenaktualisierung
|
member = message.author # Das Member-Objekt für Datenaktualisierung
|
||||||
|
|
||||||
# XP-Cooldown überprüfen (60 Sekunden)
|
# ── Honeypot check ──────────────────────────────────────────────────────────
|
||||||
|
guild_settings = get_guild_settings(guild_id)
|
||||||
|
if guild_settings.get("honeypot_enabled") and guild_settings.get("honeypot_channel_id"):
|
||||||
|
if message.channel.id == int(guild_settings["honeypot_channel_id"]):
|
||||||
|
# Build ignore-role set
|
||||||
|
ignore_role_ids = set()
|
||||||
|
raw_ignore = guild_settings.get("honeypot_ignore_roles")
|
||||||
|
if raw_ignore:
|
||||||
|
try:
|
||||||
|
ignore_role_ids = {int(r) for r in json.loads(raw_ignore)}
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
member_role_ids = {role.id for role in member.roles}
|
||||||
|
if not (ignore_role_ids & member_role_ids):
|
||||||
|
# Delete the honeypot message
|
||||||
|
try:
|
||||||
|
await message.delete()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
action_taken = None
|
||||||
|
acc_age_min = int(guild_settings.get("honeypot_acc_age_min") or 30)
|
||||||
|
preserve = guild_settings.get("honeypot_preserve_old_accounts", False)
|
||||||
|
|
||||||
|
# Determine: old-account mute vs ban
|
||||||
|
if preserve and member.joined_at:
|
||||||
|
now_aware = datetime.now(member.joined_at.tzinfo)
|
||||||
|
days_on_server = (now_aware - member.joined_at).days
|
||||||
|
is_old_account = days_on_server >= acc_age_min
|
||||||
|
else:
|
||||||
|
is_old_account = False
|
||||||
|
|
||||||
|
if is_old_account:
|
||||||
|
# Apply 1-year (365 days) mute via the mute system
|
||||||
|
honeypot_role = None
|
||||||
|
hp_role_id = guild_settings.get("honeypot_get_role")
|
||||||
|
if hp_role_id:
|
||||||
|
try:
|
||||||
|
honeypot_role = message.guild.get_role(int(hp_role_id))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if honeypot_role is None:
|
||||||
|
honeypot_role = await get_or_create_mute_role(message.guild, guild_settings)
|
||||||
|
|
||||||
|
if honeypot_role:
|
||||||
|
try:
|
||||||
|
await member.add_roles(
|
||||||
|
honeypot_role,
|
||||||
|
reason="Honeypot: wrote in honeypot channel (account protected as old member)"
|
||||||
|
)
|
||||||
|
# Persist mute record for 365 days
|
||||||
|
start_time = datetime.now()
|
||||||
|
end_time = start_time + timedelta(days=365)
|
||||||
|
process_data = {
|
||||||
|
"user_id": member.id,
|
||||||
|
"guild_id": guild_id,
|
||||||
|
"channel_id": message.channel.id,
|
||||||
|
"reason": "Honeypot trigger",
|
||||||
|
"moderator_id": client.user.id,
|
||||||
|
"mute_role_id": honeypot_role.id
|
||||||
|
}
|
||||||
|
process_uuid = create_active_process(
|
||||||
|
process_type="mute",
|
||||||
|
guild_id=guild_id,
|
||||||
|
channel_id=message.channel.id,
|
||||||
|
user_id=member.id,
|
||||||
|
target_id=member.id,
|
||||||
|
end_time=end_time,
|
||||||
|
data=process_data
|
||||||
|
)
|
||||||
|
await save_mute_to_database(
|
||||||
|
user_id=member.id,
|
||||||
|
guild_id=guild_id,
|
||||||
|
moderator_id=client.user.id,
|
||||||
|
reason="Honeypot: wrote in honeypot channel (account protected as old member)",
|
||||||
|
duration="365d",
|
||||||
|
start_time=start_time,
|
||||||
|
end_time=end_time,
|
||||||
|
process_uuid=process_uuid,
|
||||||
|
channel_id=message.channel.id,
|
||||||
|
mute_role_id=honeypot_role.id
|
||||||
|
)
|
||||||
|
action_taken = "mute"
|
||||||
|
except discord.Forbidden:
|
||||||
|
logger.warning(f"Honeypot: no permission to mute {member.id} in guild {guild_id}")
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
await message.guild.ban(
|
||||||
|
member,
|
||||||
|
reason="Honeypot: wrote in honeypot channel",
|
||||||
|
delete_message_days=1
|
||||||
|
)
|
||||||
|
action_taken = "ban"
|
||||||
|
except discord.Forbidden:
|
||||||
|
logger.warning(f"Honeypot: no permission to ban {member.id} in guild {guild_id}")
|
||||||
|
|
||||||
|
# Send log embed
|
||||||
|
hp_log_ch_id = guild_settings.get("honeypot_log_channel_id")
|
||||||
|
if action_taken and hp_log_ch_id:
|
||||||
|
try:
|
||||||
|
log_ch = message.guild.get_channel(int(hp_log_ch_id))
|
||||||
|
if log_ch:
|
||||||
|
color = 0x8b0000 if action_taken == "ban" else 0xff9500
|
||||||
|
action_label = "🔨 Banned" if action_taken == "ban" else "🔇 Muted (1 year)"
|
||||||
|
embed = discord.Embed(
|
||||||
|
title="🍯 Honeypot triggered",
|
||||||
|
description=f"{member.mention} wrote in the honeypot channel.",
|
||||||
|
color=color,
|
||||||
|
timestamp=datetime.now()
|
||||||
|
)
|
||||||
|
embed.add_field(name="Action", value=action_label, inline=True)
|
||||||
|
embed.add_field(name="User", value=f"{member} (`{member.id}`)", inline=True)
|
||||||
|
embed.add_field(name="Channel", value=f"<#{message.channel.id}>", inline=True)
|
||||||
|
if preserve:
|
||||||
|
embed.add_field(
|
||||||
|
name="Account age on server",
|
||||||
|
value=f"{days_on_server if is_old_account else 'N/A'} days (Minimum: {acc_age_min}d)",
|
||||||
|
inline=False
|
||||||
|
)
|
||||||
|
if message.content:
|
||||||
|
embed.add_field(
|
||||||
|
name="Message content",
|
||||||
|
value=message.content[:500],
|
||||||
|
inline=False
|
||||||
|
)
|
||||||
|
embed.set_thumbnail(url=member.display_avatar.url)
|
||||||
|
await log_ch.send(embed=embed)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Honeypot: error sending log: {e}")
|
||||||
|
|
||||||
|
return # Never process further for honeypot channel messages
|
||||||
|
# ── End honeypot check ──────────────────────────────────────────────────────
|
||||||
cooldown_key = (user_id, guild_id)
|
cooldown_key = (user_id, guild_id)
|
||||||
current_time = time.time()
|
current_time = time.time()
|
||||||
|
|
||||||
@@ -3747,7 +3879,14 @@ def get_guild_settings(guild_id):
|
|||||||
"auto_mute_on_warns": bool(result[5]) if result[5] is not None else False,
|
"auto_mute_on_warns": bool(result[5]) if result[5] is not None else False,
|
||||||
"auto_mute_duration": result[6] or "1h",
|
"auto_mute_duration": result[6] or "1h",
|
||||||
"log_channel_id": result[7],
|
"log_channel_id": result[7],
|
||||||
"mod_log_enabled": bool(result[8]) if result[8] is not None else True
|
"mod_log_enabled": bool(result[8]) if result[8] is not None else True,
|
||||||
|
"honeypot_enabled": bool(result[9]) if len(result) > 9 and result[9] is not None else False,
|
||||||
|
"honeypot_channel_id": result[10] if len(result) > 10 else None,
|
||||||
|
"honeypot_preserve_old_accounts": bool(result[11]) if len(result) > 11 and result[11] is not None else False,
|
||||||
|
"honeypot_get_role": result[12] if len(result) > 12 else None,
|
||||||
|
"honeypot_log_channel_id": result[13] if len(result) > 13 else None,
|
||||||
|
"honeypot_ignore_roles": result[14] if len(result) > 14 else None,
|
||||||
|
"honeypot_acc_age_min": result[15] if len(result) > 15 and result[15] is not None else 30
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
# Erstelle Default-Einstellungen
|
# Erstelle Default-Einstellungen
|
||||||
@@ -3760,7 +3899,14 @@ def get_guild_settings(guild_id):
|
|||||||
"auto_mute_on_warns": False,
|
"auto_mute_on_warns": False,
|
||||||
"auto_mute_duration": "1h",
|
"auto_mute_duration": "1h",
|
||||||
"log_channel_id": None,
|
"log_channel_id": None,
|
||||||
"mod_log_enabled": True
|
"mod_log_enabled": True,
|
||||||
|
"honeypot_enabled": False,
|
||||||
|
"honeypot_channel_id": None,
|
||||||
|
"honeypot_preserve_old_accounts": False,
|
||||||
|
"honeypot_get_role": None,
|
||||||
|
"honeypot_log_channel_id": None,
|
||||||
|
"honeypot_ignore_roles": None,
|
||||||
|
"honeypot_acc_age_min": 30
|
||||||
}
|
}
|
||||||
save_guild_settings(guild_id, default_settings)
|
save_guild_settings(guild_id, default_settings)
|
||||||
return default_settings
|
return default_settings
|
||||||
@@ -3777,7 +3923,14 @@ def get_guild_settings(guild_id):
|
|||||||
"auto_mute_on_warns": False,
|
"auto_mute_on_warns": False,
|
||||||
"auto_mute_duration": "1h",
|
"auto_mute_duration": "1h",
|
||||||
"log_channel_id": None,
|
"log_channel_id": None,
|
||||||
"mod_log_enabled": True
|
"mod_log_enabled": True,
|
||||||
|
"honeypot_enabled": False,
|
||||||
|
"honeypot_channel_id": None,
|
||||||
|
"honeypot_preserve_old_accounts": False,
|
||||||
|
"honeypot_get_role": None,
|
||||||
|
"honeypot_log_channel_id": None,
|
||||||
|
"honeypot_ignore_roles": None,
|
||||||
|
"honeypot_acc_age_min": 30
|
||||||
}
|
}
|
||||||
finally:
|
finally:
|
||||||
if cursor:
|
if cursor:
|
||||||
@@ -3785,6 +3938,41 @@ def get_guild_settings(guild_id):
|
|||||||
if connection:
|
if connection:
|
||||||
close_database_connection(connection)
|
close_database_connection(connection)
|
||||||
|
|
||||||
|
def migrate_guild_settings_table():
|
||||||
|
"""Adds new honeypot columns to guild_settings if they don't already exist"""
|
||||||
|
connection = None
|
||||||
|
cursor = None
|
||||||
|
try:
|
||||||
|
connection = connect_to_database()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
|
||||||
|
alter_queries = [
|
||||||
|
"ALTER TABLE guild_settings ADD COLUMN honeypot_enabled BOOLEAN DEFAULT FALSE",
|
||||||
|
"ALTER TABLE guild_settings ADD COLUMN honeypot_channel_id BIGINT NULL",
|
||||||
|
"ALTER TABLE guild_settings ADD COLUMN honeypot_preserve_old_accounts BOOLEAN DEFAULT FALSE",
|
||||||
|
"ALTER TABLE guild_settings ADD COLUMN honeypot_get_role VARCHAR(255) NULL",
|
||||||
|
"ALTER TABLE guild_settings ADD COLUMN honeypot_log_channel_id BIGINT NULL",
|
||||||
|
"ALTER TABLE guild_settings ADD COLUMN honeypot_ignore_roles TEXT NULL",
|
||||||
|
"ALTER TABLE guild_settings ADD COLUMN honeypot_acc_age_min INT DEFAULT 30",
|
||||||
|
]
|
||||||
|
|
||||||
|
for query in alter_queries:
|
||||||
|
try:
|
||||||
|
cursor.execute(query)
|
||||||
|
except Exception:
|
||||||
|
pass # Column already exists
|
||||||
|
|
||||||
|
connection.commit()
|
||||||
|
logger.info("guild_settings table migration completed")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error migrating guild_settings table: {e}")
|
||||||
|
finally:
|
||||||
|
if cursor:
|
||||||
|
cursor.close()
|
||||||
|
if connection:
|
||||||
|
close_database_connection(connection)
|
||||||
|
|
||||||
def save_guild_settings(guild_id, settings):
|
def save_guild_settings(guild_id, settings):
|
||||||
"""Speichert Guild-Einstellungen in der Datenbank"""
|
"""Speichert Guild-Einstellungen in der Datenbank"""
|
||||||
connection = None
|
connection = None
|
||||||
@@ -3796,8 +3984,11 @@ def save_guild_settings(guild_id, settings):
|
|||||||
insert_query = """
|
insert_query = """
|
||||||
INSERT INTO guild_settings (guild_id, mute_role_id, mute_role_name, auto_create_mute_role,
|
INSERT INTO guild_settings (guild_id, mute_role_id, mute_role_name, auto_create_mute_role,
|
||||||
max_warn_threshold, auto_mute_on_warns, auto_mute_duration,
|
max_warn_threshold, auto_mute_on_warns, auto_mute_duration,
|
||||||
log_channel_id, mod_log_enabled)
|
log_channel_id, mod_log_enabled,
|
||||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
|
honeypot_enabled, honeypot_channel_id, honeypot_preserve_old_accounts,
|
||||||
|
honeypot_get_role, honeypot_log_channel_id, honeypot_ignore_roles,
|
||||||
|
honeypot_acc_age_min)
|
||||||
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||||
ON DUPLICATE KEY UPDATE
|
ON DUPLICATE KEY UPDATE
|
||||||
mute_role_id = VALUES(mute_role_id),
|
mute_role_id = VALUES(mute_role_id),
|
||||||
mute_role_name = VALUES(mute_role_name),
|
mute_role_name = VALUES(mute_role_name),
|
||||||
@@ -3806,7 +3997,14 @@ def save_guild_settings(guild_id, settings):
|
|||||||
auto_mute_on_warns = VALUES(auto_mute_on_warns),
|
auto_mute_on_warns = VALUES(auto_mute_on_warns),
|
||||||
auto_mute_duration = VALUES(auto_mute_duration),
|
auto_mute_duration = VALUES(auto_mute_duration),
|
||||||
log_channel_id = VALUES(log_channel_id),
|
log_channel_id = VALUES(log_channel_id),
|
||||||
mod_log_enabled = VALUES(mod_log_enabled)
|
mod_log_enabled = VALUES(mod_log_enabled),
|
||||||
|
honeypot_enabled = VALUES(honeypot_enabled),
|
||||||
|
honeypot_channel_id = VALUES(honeypot_channel_id),
|
||||||
|
honeypot_preserve_old_accounts = VALUES(honeypot_preserve_old_accounts),
|
||||||
|
honeypot_get_role = VALUES(honeypot_get_role),
|
||||||
|
honeypot_log_channel_id = VALUES(honeypot_log_channel_id),
|
||||||
|
honeypot_ignore_roles = VALUES(honeypot_ignore_roles),
|
||||||
|
honeypot_acc_age_min = VALUES(honeypot_acc_age_min)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cursor.execute(insert_query, (
|
cursor.execute(insert_query, (
|
||||||
@@ -3818,7 +4016,14 @@ def save_guild_settings(guild_id, settings):
|
|||||||
settings.get("auto_mute_on_warns", False),
|
settings.get("auto_mute_on_warns", False),
|
||||||
settings.get("auto_mute_duration", "1h"),
|
settings.get("auto_mute_duration", "1h"),
|
||||||
settings.get("log_channel_id"),
|
settings.get("log_channel_id"),
|
||||||
settings.get("mod_log_enabled", True)
|
settings.get("mod_log_enabled", True),
|
||||||
|
settings.get("honeypot_enabled", False),
|
||||||
|
settings.get("honeypot_channel_id"),
|
||||||
|
settings.get("honeypot_preserve_old_accounts", False),
|
||||||
|
settings.get("honeypot_get_role"),
|
||||||
|
settings.get("honeypot_log_channel_id"),
|
||||||
|
settings.get("honeypot_ignore_roles"),
|
||||||
|
settings.get("honeypot_acc_age_min", 30)
|
||||||
))
|
))
|
||||||
connection.commit()
|
connection.commit()
|
||||||
|
|
||||||
@@ -7823,6 +8028,7 @@ try:
|
|||||||
create_warnings_table()
|
create_warnings_table()
|
||||||
create_mutes_table()
|
create_mutes_table()
|
||||||
create_contact_messages_table()
|
create_contact_messages_table()
|
||||||
|
migrate_guild_settings_table()
|
||||||
logger.info("Database tables initialized successfully")
|
logger.info("Database tables initialized successfully")
|
||||||
|
|
||||||
loop.run_until_complete(client.start(TOKEN))
|
loop.run_until_complete(client.start(TOKEN))
|
||||||
|
|||||||
@@ -350,6 +350,110 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Honeypot Settings -->
|
||||||
|
<div class="settings-section">
|
||||||
|
<h3 class="section-title">
|
||||||
|
<i class="fas fa-spider section-icon"></i>
|
||||||
|
Honeypot System
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div class="info-card">
|
||||||
|
<div class="info-card-title">
|
||||||
|
<i class="fas fa-info-circle"></i>
|
||||||
|
What is a Honeypot?
|
||||||
|
</div>
|
||||||
|
<p class="info-card-text">
|
||||||
|
A honeypot channel is a hidden channel that attracts bots and spam accounts.
|
||||||
|
Any user who writes there will be automatically banned — or if old account protection
|
||||||
|
is enabled, muted for 1 year.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="honeypot_enabled"
|
||||||
|
name="honeypot_enabled" {% if settings.honeypot_enabled %}checked{% endif %}>
|
||||||
|
<label class="form-check-label" for="honeypot_enabled">
|
||||||
|
Enable Honeypot System
|
||||||
|
</label>
|
||||||
|
<small class="help-text d-block">Enables automatic detection in the honeypot channel</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mt-3">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="honeypot_channel_id">Honeypot Channel ID</label>
|
||||||
|
<input type="text" class="form-control" id="honeypot_channel_id"
|
||||||
|
name="honeypot_channel_id"
|
||||||
|
value="{{ settings.honeypot_channel_id or '' }}"
|
||||||
|
placeholder="e.g. 123456789012345678">
|
||||||
|
<small class="help-text">Channel where messages trigger a ban</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="honeypot_log_channel_id">Honeypot Log Channel ID</label>
|
||||||
|
<input type="text" class="form-control" id="honeypot_log_channel_id"
|
||||||
|
name="honeypot_log_channel_id"
|
||||||
|
value="{{ settings.honeypot_log_channel_id or '' }}"
|
||||||
|
placeholder="e.g. 123456789012345678">
|
||||||
|
<small class="help-text">Channel for honeypot logs (empty = disabled)</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="honeypot_preserve_old_accounts"
|
||||||
|
name="honeypot_preserve_old_accounts"
|
||||||
|
{% if settings.honeypot_preserve_old_accounts %}checked{% endif %}>
|
||||||
|
<label class="form-check-label" for="honeypot_preserve_old_accounts">
|
||||||
|
Enable Old Account Protection
|
||||||
|
</label>
|
||||||
|
<small class="help-text d-block">
|
||||||
|
Users who have been on the server longer than the minimum age will not be banned,
|
||||||
|
but only muted for 1 year (for possibly hacked accounts)
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mt-3">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="honeypot_acc_age_min">Minimum Server Age (Days)</label>
|
||||||
|
<input type="number" class="form-control" id="honeypot_acc_age_min"
|
||||||
|
name="honeypot_acc_age_min"
|
||||||
|
value="{{ settings.honeypot_acc_age_min or 30 }}" min="1">
|
||||||
|
<small class="help-text">
|
||||||
|
Users must be on the server for at least this many days
|
||||||
|
to be considered an "old account"
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="honeypot_get_role">Mute Role ID (Old Accounts)</label>
|
||||||
|
<input type="text" class="form-control" id="honeypot_get_role"
|
||||||
|
name="honeypot_get_role"
|
||||||
|
value="{{ settings.honeypot_get_role or '' }}"
|
||||||
|
placeholder="e.g. 123456789012345678">
|
||||||
|
<small class="help-text">
|
||||||
|
Role for muted old accounts. Empty = use normal mute role
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="honeypot_ignore_roles">Ignored Roles (Mod Roles, etc.)</label>
|
||||||
|
<input type="text" class="form-control" id="honeypot_ignore_roles"
|
||||||
|
name="honeypot_ignore_roles"
|
||||||
|
value="{{ settings.honeypot_ignore_roles | from_json_ids if settings.honeypot_ignore_roles else '' }}"
|
||||||
|
placeholder="e.g. 111222333444 555666777888">
|
||||||
|
<small class="help-text">
|
||||||
|
Space- or comma-separated role IDs that are exempt from honeypot
|
||||||
|
(e.g., mod roles)
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Action Buttons -->
|
<!-- Action Buttons -->
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<button type="submit" class="btn btn-primary mr-3">
|
<button type="submit" class="btn btn-primary mr-3">
|
||||||
@@ -371,6 +475,10 @@
|
|||||||
const muteRoleId = document.getElementById('mute_role_id').value;
|
const muteRoleId = document.getElementById('mute_role_id').value;
|
||||||
const logChannelId = document.getElementById('log_channel_id').value;
|
const logChannelId = document.getElementById('log_channel_id').value;
|
||||||
const muteDuration = document.getElementById('auto_mute_duration').value;
|
const muteDuration = document.getElementById('auto_mute_duration').value;
|
||||||
|
const honeypotChannelId = document.getElementById('honeypot_channel_id').value;
|
||||||
|
const honeypotLogChannelId = document.getElementById('honeypot_log_channel_id').value;
|
||||||
|
const honeypotGetRole = document.getElementById('honeypot_get_role').value;
|
||||||
|
const honeypotAccAgeMin = document.getElementById('honeypot_acc_age_min').value;
|
||||||
|
|
||||||
// Validate role ID format (if provided)
|
// Validate role ID format (if provided)
|
||||||
if (muteRoleId && !/^\d{17,19}$/.test(muteRoleId)) {
|
if (muteRoleId && !/^\d{17,19}$/.test(muteRoleId)) {
|
||||||
@@ -392,6 +500,27 @@
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Honeypot validations
|
||||||
|
if (honeypotChannelId && !/^\d{17,19}$/.test(honeypotChannelId)) {
|
||||||
|
alert('Honeypot channel ID must be a 17–19 digit number');
|
||||||
|
e.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (honeypotLogChannelId && !/^\d{17,19}$/.test(honeypotLogChannelId)) {
|
||||||
|
alert('Honeypot log channel ID must be a 17–19 digit number');
|
||||||
|
e.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (honeypotGetRole && !/^\d{17,19}$/.test(honeypotGetRole)) {
|
||||||
|
alert('Mute role ID must be a 17–19 digit number');
|
||||||
|
e.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (honeypotAccAgeMin && (isNaN(honeypotAccAgeMin) || parseInt(honeypotAccAgeMin) < 1)) {
|
||||||
|
alert('Minimum account age must be at least 1 day');
|
||||||
|
e.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
Reference in New Issue
Block a user