Guest User

discord bot

a guest
Jan 30th, 2025
47
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.57 KB | None | 0 0
  1. import os
  2. import json
  3. import random
  4. import string
  5. import discord
  6. from discord import app_commands
  7. from discord.ext import tasks
  8. from dotenv import load_dotenv
  9. from ldap3 import Server, Connection, ALL, MODIFY_REPLACE
  10. from ldap3 import MODIFY_ADD
  11.  
  12. # Load environment variables
  13. load_dotenv()
  14.  
  15. DISCORD_BOT_TOKEN = os.getenv("DISCORD_BOT_TOKEN")
  16. LDAP_SERVER_URL = os.getenv("LDAP_SERVER_URL")
  17. LDAP_BIND_DN = os.getenv("LDAP_BIND_DN")
  18. LDAP_BIND_PASSWORD = os.getenv("LDAP_BIND_PASSWORD")
  19. LDAP_BASE_DN = os.getenv("LDAP_BASE_DN")
  20. LLDAP_LOGIN_URL = os.getenv("LLDAP_LOGIN_URL")
  21. SUBSCRIBER_ROLE_NAME = os.getenv("SUBSCRIBER_ROLE_NAME")
  22.  
  23. LDAP_USERS_DN = f"ou=people,{LDAP_BASE_DN}"  # Remove duplicate ou=people
  24.  
  25. LDAP_GROUPS_DN = f"ou=groups,{LDAP_BASE_DN}"
  26. SUBSCRIBERS_GROUP_DN = f"cn=subscribers,{LDAP_GROUPS_DN}"
  27.  
  28. ASSOCIATION_FILE = "user_associations.json"
  29.  
  30. # Bot setup
  31. intents = discord.Intents.default()
  32. intents.guilds = True
  33. intents.members = True
  34. bot = discord.Client(intents=intents)
  35. tree = app_commands.CommandTree(bot)
  36.  
  37. # -------------------------------
  38. # Utility Functions
  39. # -------------------------------
  40. def load_associations():
  41.     if not os.path.exists(ASSOCIATION_FILE):
  42.         return {}
  43.     with open(ASSOCIATION_FILE, "r") as f:
  44.         return json.load(f)
  45.  
  46. def save_associations(data):
  47.     with open(ASSOCIATION_FILE, "w") as f:
  48.         json.dump(data, f)
  49.  
  50. def generate_random_password(length=12):
  51.     chars = string.ascii_letters + string.digits + "!@#$%^&*"
  52.     return ''.join(random.choice(chars) for _ in range(length))
  53.  
  54. def ldap_connect():
  55.     server = Server(LDAP_SERVER_URL, get_info=ALL)
  56.     conn = Connection(server, user=LDAP_BIND_DN, password=LDAP_BIND_PASSWORD, auto_bind=True)
  57.     return conn
  58.  
  59. def create_ldap_user(conn, username, email, password):
  60.     user_dn = f"uid={username},{LDAP_USERS_DN}"
  61.     conn.add(
  62.         dn=user_dn,
  63.         object_class=["inetOrgPerson", "organizationalPerson", "person", "top"],
  64.         attributes={
  65.             "cn": username,
  66.             "sn": username,
  67.             "mail": email,
  68.             "uid": username,
  69.             "userPassword": password
  70.         }
  71.     )
  72.     return conn.result["description"] == "success"
  73.  
  74. def add_user_to_subscribers(conn, user_dn):
  75.     print(f"\n🔍 DEBUG: Checking if user exists: {user_dn}")
  76.  
  77.     # Ensure user exists before modifying group
  78.     search_filter = f"(uid={user_dn.split(',')[0].split('=')[1]})"
  79.     conn.search(LDAP_USERS_DN, search_filter, attributes=["dn"])
  80.  
  81.     if not conn.entries:
  82.         print(f"❌ ERROR: User {user_dn} not found in LDAP. Cannot add to Subscribers group.")
  83.         return False
  84.  
  85.     print(f"✅ User found in LDAP: {user_dn}")
  86.  
  87.     # DEBUG: Check existing members of the group
  88.     print(f"\n🔍 DEBUG: Checking existing members of {SUBSCRIBERS_GROUP_DN}")
  89.     conn.search(SUBSCRIBERS_GROUP_DN, "(objectClass=groupOfNames)", attributes=["member"])
  90.  
  91.     current_members = []
  92.     if conn.entries:
  93.         current_members = conn.entries[0]["member"] if "member" in conn.entries[0] else []
  94.         print(f"📜 Current members before modification: {current_members}")
  95.     else:
  96.         print("❌ ERROR: Subscribers group not found or empty.")
  97.  
  98.     # Use the correct modify request format
  99.         modify_request = {"memberUid": [(MODIFY_ADD, [user_dn.split(',')[0].split('=')[1]])]}  # Extracts only the username
  100.  
  101.  
  102.         # DEBUG: Print the request being sent
  103.         print(f"\n✏️ DEBUG: Attempting to add {user_dn} to {SUBSCRIBERS_GROUP_DN}")
  104.         print(f"📜 LDAP Modify Request: {modify_request}")
  105.  
  106.         conn.modify(SUBSCRIBERS_GROUP_DN, modify_request)
  107.  
  108.  
  109.  
  110.  
  111.  
  112.     if conn.result["description"] != "success":
  113.         print(f"❌ LDAP Modify Error: {conn.result}")
  114.     else:
  115.         print(f"✅ Successfully added {user_dn} to {SUBSCRIBERS_GROUP_DN}")
  116.  
  117.     return conn.result["description"] == "success"
  118.  
  119.  
  120.  
  121. def remove_user_from_subscribers(conn, user_dn):
  122.     conn.modify(
  123.         SUBSCRIBERS_GROUP_DN,
  124.         {"member": [(MODIFY_REPLACE, __update_member_list(conn, SUBSCRIBERS_GROUP_DN, user_dn, add=False))]}
  125.     )
  126.  
  127. def __update_member_list(conn, group_dn, user_dn, add=True):
  128.     conn.search(group_dn, "(objectClass=groupOfNames)", attributes=["member"])
  129.     current_members = conn.entries[0].member if conn.entries and conn.entries[0].member else []
  130.     members = set(str(m) for m in current_members)
  131.     if add:
  132.         members.add(user_dn)
  133.     else:
  134.         members.discard(user_dn)
  135.     return list(members)
  136.  
  137. def is_user_in_subscribers(conn, user_dn):
  138.     conn.search(SUBSCRIBERS_GROUP_DN, "(objectClass=groupOfNames)", attributes=["member"])
  139.     if not conn.entries:
  140.         return False
  141.     members = conn.entries[0].member if conn.entries[0].member else []
  142.     return user_dn in [str(m) for m in members]
  143.  
  144. def ldap_user_exists(conn, email):
  145.     search_filter = f"(mail={email})"
  146.     conn.search(LDAP_USERS_DN, search_filter, attributes=["mail"])
  147.     return len(conn.entries) > 0
  148.  
  149. def get_all_subscribers(conn):
  150.     conn.search(SUBSCRIBERS_GROUP_DN, "(objectClass=groupOfNames)", attributes=["member"])
  151.     if not conn.entries:
  152.         return []
  153.     return [str(m) for m in conn.entries[0].member]
  154.  
  155. # -------------------------------
  156. # Periodic Sync Task
  157. # -------------------------------
  158. @tasks.loop(minutes=5)
  159. async def sync_subscribers():
  160.     conn = ldap_connect()
  161.     associations = load_associations()
  162.     for guild in bot.guilds:
  163.         subscriber_role = discord.utils.get(guild.roles, name=SUBSCRIBER_ROLE_NAME)
  164.         if not subscriber_role:
  165.             continue
  166.         for discord_id, user_dn in associations.items():
  167.             member = guild.get_member(int(discord_id))
  168.             if not member:
  169.                 continue
  170.             if subscriber_role in member.roles:
  171.                 if not is_user_in_subscribers(conn, user_dn):
  172.                     add_user_to_subscribers(conn, user_dn)
  173.             else:
  174.                 if is_user_in_subscribers(conn, user_dn):
  175.                     remove_user_from_subscribers(conn, user_dn)
  176.     conn.unbind()
  177.  
  178. # -------------------------------
  179. # Slash Commands
  180. # -------------------------------
  181. @tree.command(name="register", description="Register an LDAP account.")
  182. async def register(interaction: discord.Interaction, email: str):
  183.     associations = load_associations()
  184.     user_id_str = str(interaction.user.id)
  185.  
  186.     if user_id_str in associations:
  187.         await interaction.response.send_message("You are already linked to an LDAP account.", ephemeral=True)
  188.         return
  189.  
  190.     conn = ldap_connect()
  191.     if ldap_user_exists(conn, email):
  192.         await interaction.response.send_message("That email is already linked to an LDAP account.", ephemeral=True)
  193.         conn.unbind()
  194.         return
  195.  
  196.     username = interaction.user.name.lower().replace(" ", "")
  197.     password = generate_random_password()
  198.     success = create_ldap_user(conn, username, email, password)
  199.    
  200.     if not success:
  201.         await interaction.response.send_message("Failed to create LDAP account.", ephemeral=True)
  202.         print(f"LDAP Creation Error: {conn.result}")
  203.         conn.unbind()
  204.         return
  205.  
  206.  
  207.     user_dn = f"uid={username},{LDAP_USERS_DN}"
  208.     add_user_to_subscribers(conn, user_dn)
  209.     associations[user_id_str] = user_dn
  210.     save_associations(associations)
  211.     conn.unbind()
  212.  
  213.     await interaction.user.send(f"Your LDAP account has been created.\nUsername: {username}\nPassword: {password}\nChange it here: {LLDAP_LOGIN_URL}")
  214.     await interaction.response.send_message("Your LDAP account has been created.", ephemeral=True)
  215.  
  216. @tree.command(name="list_subscribed", description="List all subscribed LDAP users (Admin Only)")
  217. async def list_subscribed(interaction: discord.Interaction):
  218.     if not interaction.user.guild_permissions.administrator:
  219.         await interaction.response.send_message("You don't have permission for this.", ephemeral=True)
  220.         return
  221.    
  222.     conn = ldap_connect()
  223.     subscribers = get_all_subscribers(conn)
  224.     conn.unbind()
  225.    
  226.     response = "\n".join(subscribers) if subscribers else "No subscribers found."
  227.     await interaction.response.send_message(f"**Subscribers:**\n```{response}```", ephemeral=True)
  228.  
  229. @bot.event
  230. async def on_ready():
  231.     await bot.wait_until_ready()  # Ensure bot is fully loaded
  232.     try:
  233.         synced = await tree.sync()  # Sync commands to all guilds
  234.         print(f"Synced {len(synced)} commands globally.")
  235.     except Exception as e:
  236.         print(f"Failed to sync commands: {e}")
  237.  
  238.     print(f"Bot logged in as {bot.user}")
  239.     sync_subscribers.start()
  240.  
  241.  
  242. bot.run(DISCORD_BOT_TOKEN)
  243.  
Advertisement
Add Comment
Please, Sign In to add comment