feat: implement basic structure of pulling data & whitelisting

This commit is contained in:
Price Hiller 2023-02-05 04:32:26 -06:00
parent 5f99751adc
commit 91ecee4c05
11 changed files with 293 additions and 281 deletions

118
autowl/Cogs/Group.py Normal file
View File

@ -0,0 +1,118 @@
import discord
from autowl import config
from autowl.bot import Bot
from discord.ext import commands
from discord import app_commands
class Group(commands.Cog, name="group"):
def __init__(self, client: Bot):
self.client = client
@app_commands.command()
async def add(
self,
interaction: discord.Interaction,
role: discord.Role,
):
if self.client.whitelist.get(role.name):
await interaction.response.send_message(
f"**{role.name}** is already added, cannot add it again!"
)
return
dropdown = discord.ui.Select(
min_values=1,
max_values=20,
placeholder="Choose group permissions in Squad",
options=[
discord.SelectOption(
label="changemap", description="Allows users to change the map"
),
discord.SelectOption(
label="pause", description="Pause server gameplay"
),
discord.SelectOption(
label="cheat", description="Use server cheat commands"
),
discord.SelectOption(
label="private", description="Password protect server"
),
discord.SelectOption(
label="balance", description="Group Ignores server team balance"
),
discord.SelectOption(
label="chat", description="Admin chat and Server broadcast"
),
discord.SelectOption(
label="kick",
description="Allows user to kick players from the server",
),
discord.SelectOption(
label="ban",
description="Allows user to ban players from the server",
),
discord.SelectOption(
label="config", description="Change server config"
),
discord.SelectOption(
label="cameraman", description="Admin spectate mode"
),
discord.SelectOption(
label="immune", description="Cannot be kicked / banned"
),
discord.SelectOption(
label="manageserver", description="Shutdown server"
),
discord.SelectOption(
label="featuretest",
description="Any features added for testing by dev team",
),
discord.SelectOption(label="reserve", description="Reserve slot"),
discord.SelectOption(
label="demos",
description="Record Demos on the server side via admin commands",
),
discord.SelectOption(
label="clientdemos",
description="Record Demos on the client side via commands or the replay UI.",
),
discord.SelectOption(
label="debug",
description="show admin stats command and other debugging info",
),
discord.SelectOption(
label="teamchange", description="No timer limits on team change"
),
discord.SelectOption(
label="forceteamchange",
description="Can issue the ForceTeamChange command",
),
discord.SelectOption(
label="canseeadminchat",
description="This group can see the admin chat and teamkill/admin-join notifications",
),
],
)
view = discord.ui.View()
view.add_item(dropdown)
async def perms_handler(interaction: discord.Interaction):
perms = "\n - ".join(dropdown.values)
dropdown.disabled = True
await interaction.response.edit_message(view=view)
await interaction.followup.send(
f"Adding **{role.name}** to whitelist with permissions:\n - {perms}\n\n"
)
self.client.whitelist[f"{role.name}"] = config.WhitelistGroup(
permissions=dropdown.values, discord_role_id=role.id, members={}
)
print(self.client.whitelist)
dropdown.callback = perms_handler
ctx: commands.Context = await self.client.get_context(interaction)
await ctx.send(view=view)

27
autowl/Cogs/Whitelist.py Normal file
View File

@ -0,0 +1,27 @@
import discord
from autowl import config
from autowl.bot import Bot
from discord.ext import commands
from discord import app_commands
class Whitelist(commands.Cog):
def __init__(self, client: Bot):
self.client = client
@app_commands.command()
async def register(self, interaction: discord.Interaction, steam64: int):
ctx: commands.Context = await self.client.get_context(interaction)
if not ctx.guild:
ctx.reply("This command must be ran within a discord server!")
return
steam64_updated = False
for role in ctx.author.roles:
for group in self.client.whitelist:
if role.id == group.discord_role_id:
steam64_updated = True
group.members[ctx.author.id] = config.WhitelistMember(ctx.author.name, steam64)
if steam64_updated:
ctx.reply(f"Updated {ctx.author.name}'s whitelist steam64 to {steam64}!")

4
autowl/Cogs/__init__.py Normal file
View File

@ -0,0 +1,4 @@
from .Whitelist import Whitelist
from .Group import Group
__all__ = ["Whitelist", "Group"]

View File

@ -1,19 +0,0 @@
import os
from sys import stderr
import discord
# run init stuff inside this function
def init():
# make sure this prints the discord token
# set this up as a runtime environment variable, DO NOT HARDCODE THE TOKEN
distoken = os.environ.get("DISCORD_TOKEN")
if not distoken:
print("Unable to find discord token in environment!", file=stderr)
exit(1)
print(f"discord token:{distoken}")
init()

View File

@ -1,28 +1,65 @@
import logging
import sys
import autowl.bot as bot
from os import environ
from sys import stderr
from multiprocessing import Process
import autowl.fileServer as fileServer
import autowl.discordBot as discordBot
from autowl.config import DiscordClientConfig
log = logging.getLogger(__name__)
class CustomFormat(logging.Formatter):
grey = "\x1b[38;20m"
yellow = "\x1b[33;20m"
red = "\x1b[31;20m"
bold_red = "\x1b[31;1m"
reset = "\x1b[0m"
format = (
"[%(asctime)s][%(levelname)s][%(name)s.%(funcName)s:%(lineno)d] %(message)s"
)
FORMATS = {
logging.DEBUG: grey + format + reset,
logging.INFO: grey + format + reset,
logging.WARNING: yellow + format + reset,
logging.ERROR: red + format + reset,
logging.CRITICAL: bold_red + format + reset,
}
def format(self, record):
log_fmt = self.FORMATS.get(record.levelno)
formatter = logging.Formatter(log_fmt)
return formatter.format(record)
def setup_logging():
log_level = environ.get("LOG_LEVEL") or "INFO"
ch = logging.StreamHandler(stream=sys.stdout)
ch.setFormatter(CustomFormat())
log.setLevel(log_level)
discord_log = logging.getLogger("discord")
discord_log.setLevel(log_level)
discord_http_log = logging.getLogger("discord.http")
discord_http_log.setLevel(log_level)
logging.basicConfig(level=log_level, handlers=[ch])
# main runtime function
def main():
if disToken := environ.get('DISCORD_TOKEN'):
print(f"Received discord token: {disToken}")
# Call into main action here, basically launch the bot via import to a lower module
setup_logging()
if disToken := environ.get("DISCORD_TOKEN"):
bot_config = DiscordClientConfig(disToken)
try:
bot.Bot(bot_config).start_bot()
except Exception as e:
log.critical(f"Bot exited critically, error: {e}")
raise e
else:
print("Unable to access DISCORD_TOKEN in environment!", file=stderr)
log.error("Unable to access DISCORD_TOKEN in environment!")
exit(1)
fsproc = Process(target=fileServer.startServer)
disbot = Process(target=discordBot.startBot, args=(disToken,))
fsproc.start()
disbot.start()
fsproc.join()
disbot.join()
exit(0)

52
autowl/bot.py Normal file
View File

@ -0,0 +1,52 @@
import logging
import discord
from discord.ext import commands
from autowl import config
log = logging.getLogger(__name__)
class Bot(commands.Bot):
whitelist = config.Whitelist({}).whitelist
def __init__(self, config: config.DiscordClientConfig):
self.config = config
intents = discord.Intents.default()
intents.message_content = True
intents.members = True
super().__init__(
command_prefix=commands.when_mentioned_or("&"),
intents=intents,
help_command=commands.DefaultHelpCommand(dm_help=True),
)
async def on_ready(self):
log.info(f"Logged in as '{self.user}' ({self.user.id})")
log.info(
f"Have access to the following guilds: "
f"{', '.join([str(guild.name) + ' (' + str(guild.id) + ')' for guild in self.guilds])}"
)
for guild in self.guilds:
self.tree.copy_global_to(guild=guild)
await self.tree.sync(guild=guild)
log.info(f"Synced guild: {guild.name}")
await self.tree.sync()
async def setup_hook(self):
log.info("Setting up bot")
from autowl import Cogs
await self.add_cog(Cogs.Whitelist(self))
await self.add_cog(Cogs.Group(self))
def start_bot(self):
log.info("Starting discord bot")
try:
self.run(self.config.login_token, log_handler=None)
except discord.errors.LoginFailure as e:
log.debug(f"Received login failure: {e}")
log.error("Failed to login to discord, check your discord token!")
raise e

34
autowl/config.py Normal file
View File

@ -0,0 +1,34 @@
from dataclasses import dataclass
@dataclass
class DiscordClientConfig:
login_token: str
@dataclass
class WhitelistMember:
discord_username: str
steam64: int
@dataclass
class WhitelistGroup:
permissions: list[str]
discord_role_id: int
members: dict[int, WhitelistMember]
@dataclass
class Whitelist:
whitelist: dict[str, WhitelistGroup]
def __iter__(self):
for key in self.whitelist:
yield self.whitelist[key]
@dataclass
class PermGroup:
group_name: str
permissions: list[str]

View File

@ -1,105 +0,0 @@
import discord
from sys import stderr
MY_GUILD = discord.Object(id=1064037361786302475)
adminsroleids = [1067044106439761950]
generalwl = dict(name='Whitelist', discordid=1067044106439761950, permslist=['reserve'], members=[])
masterwllist = [generalwl]
def removewlmember(wllist, userid):
memberrmindex = -1
for i in range(len(wllist['members'])):
if wllist['members'][i]['userid'] == userid:
memberrmindex = i
if memberrmindex < 0:
return
wllist['members'].remove(wllist['members'][memberrmindex])
async def updatefile(wllist):
with open(f"remoteAdmins/{wllist['name']}", 'w') as file:
rawperm = ''
for perm in wllist['permslist']:
rawperm = f"{rawperm},{perm}"
file.write(f"Group={wllist['name']}:{rawperm}\n\n")
for wluser in wllist['members']:
file.write(f"Admin={wluser['steamid']}:{wllist['name']} // discord:{wluser['username']} ({wluser['userid']})\n")
class WhiteLister(discord.Client):
def __init__(self, *, intents: discord.Intents):
super().__init__(intents=intents)
self.tree = discord.app_commands.CommandTree(self)
async def on_ready(self):
print(f"Logged on as {self.user}")
async def on_member_update(self, before, after):
print(f"user '{after.name} ({after.id})' started member update")
rmrolesid = []
for befrole in before.roles:
rmrolesid.append(befrole.id)
for aftrole in after.roles:
for befrole in before.roles:
if befrole.id == aftrole.id:
rmrolesid.remove(aftrole.id)
for rmroleid in rmrolesid:
for wllist in masterwllist:
if wllist['discordid'] == rmroleid:
removewlmember(wllist, before.id)
await updatefile(wllist)
async def setup_hook(self):
self.tree.copy_global_to(guild=MY_GUILD)
await self.tree.sync(guild=MY_GUILD)
async def hellofunc(interaction: discord.Interaction, steam64id: str):
print(f"user '{interaction.user.name} ({interaction.user.id})' attempting whitelist")
hasrole = False
for userrole in interaction.user.roles:
if userrole.id == WHITELISTID:
hasrole = True
if not hasrole:
print(f"user '{interaction.user.name} ({interaction.user.id})' does not have whitelist role")
await interaction.response.send_message(f"ERROR: user does not have whitelist role!")
return
for wlentry in generalwhitelist:
if wlentry[0] == steam64id:
print(f"user '{interaction.user.name} ({interaction.user.id})' used an existing steam id")
await interaction.response.send_message(f"ERROR: steam64id already exists in whitelist!")
return
if wlentry[1] == interaction.user.id:
print(f"user '{interaction.user.name} ({interaction.user.id})' used an existing discord id")
await interaction.response.send_message(f"ERROR: discord user id already exists in whitelist!")
return
username = interaction.user.name
if not (interaction.user.nick is None):
username = interaction.user.nick
newwlentry = dict(steamid=steam64id, userid=interaction.user.id, username=username)
generalwl["members"].append(newwlentry)
print(f"user '{interaction.user.name} ({interaction.user.id})' added with steamid '{steam64id}'")
await updateFile()
await interaction.response.send_message(
f'Added {newwlentry[2]} ({newwlentry[1]}) with steamid: {newwlentry[0]}, to glbwhitelist!')
def startBot(discordtoken):
print("starting discord bot")
intents = discord.Intents.default()
intents.message_content = True
intents.members = True
client = WhiteLister(intents=intents)
@client.tree.command()
async def hello(interaction: discord.Interaction, steam64id: str):
await hellofunc(interaction, steam64id)
try:
print("discord bot started!")
client.run(discordtoken)
except:
print("Invalid discord token!", file=stderr)
exit(1)

View File

@ -1,34 +0,0 @@
import http.server
import socketserver
from urllib.parse import urlparse
from urllib.parse import parse_qs
from sys import stderr
PORT = 8000
class serveRA(http.server.SimpleHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-type", "text")
self.end_headers()
query = parse_qs(urlparse(self.path).query)
if 'serverName' in query:
servername = query['serverName'][0]
try:
file = open(f"remoteAdmins/{servername}.cfg", 'rb')
except:
print("failed to open file!", file=stderr)
return
self.copyfile(file, self.wfile)
return
def startServer():
handler = serveRA
with socketserver.TCPServer(("", PORT), handler) as httpd:
print(f"Server started at localhost:{PORT}")
httpd.serve_forever()

View File

@ -2,12 +2,11 @@
"WhiteListGroupName": {
"permissions": [],
"discord_role_id": "",
"members": [
{
"discord_id": "",
"members": {
"discord_id": {
"steam64": "",
"discord_username": ""
}
]
}
}
}

View File

@ -1,101 +0,0 @@
Group=1039155511066636329:
Group=Odin:changemap,pause,balance,chat,kick,ban,cameraman,teamchange,forceteamchange,canseeadminchat,reserve,config
Group=SrAdmin:changemap,balance,chat,kick,ban,cameraman,teamchange,forceteamchange,canseeadminchat,reserve
Group=JrAdmin:balance,chat,kick,ban,teamchange,canseeadminchat,reserve
Group=Whitelist:reserve
Group=CAS:reserve
Group=HC:reserve
Group=SLT:reserve
Group=BR1:reserve
/////////////////////////////////////////////////////////////////////////////////////////////
// The format for adding admins is:
// Admin=<Steam ID #>:<Group Name>
//
// For example:
// Admin=123456:Admin // Adam the admin
// Admin=654321:Moderator // Molly the moderator
//
// Add your own below:
/////////////////////////////////////////////////////////////////////////////////////////////
// === 1039155511066636329 ===
// === Odin ===
Admin=76561197986710399:Odin // Kinsher - Server Administrator
Admin=76561199101367413:Odin // Atrocity -
Admin=76561198001193856:Odin // Xikky -
Admin=76561199028579724:Odin // iiTherRealMcCoy -
Admin=76561198153769543:Odin // MaxRecon -
Admin=76561198067016254:Odin // SheHulk -
Admin=76561198404402665:Odin // Malinoff -
Admin=76561198073942737:Odin // Someoneulove -
Admin=76561198356666755:Odin // Teggy -
Admin=76561198855097026:Odin // SooperGloo -
// === SrAdmin ===
Admin=76561198339174737:SrAdmin // Frizz -
Admin=76561198373523022:SrAdmin // Lt_Longsword -
Admin=76561199201845769:SrAdmin // Buddy -
Admin=76561198015328506:SrAdmin // Ray -
Admin=76561198329170534:SrAdmin // Freeman -
Admin=76561199018771290:SrAdmin // Omega -
Admin=76561198046579272:SrAdmin // Coiffee -
Admin=76561198203568744:SrAdmin // Elon -
Admin=76561198799111045:SrAdmin // Kin_Seward -
Admin=76561198206734757:SrAdmin // RangerSix -
Admin=76561199094282718:SrAdmin // Epimetheus -
Admin=76561199127559778:SrAdmin // Chemji -
Admin=76561198059250541:SrAdmin // Mirage40K -
Admin=76561198081576045:SrAdmin // Rabbid_Squirrel -
Admin=76561198124658412:SrAdmin // Sweetwater -
Admin=76561198107367726:SrAdmin // wolf.rayne -
// === JrAdmin ===
Admin=76561198003130199:JrAdmin // Sexo - Primary Seeder
// === Whitelist ===
Admin=76561198090760895:Whitelist // Treay ~ Sam - For Asgard IT Started 01/09/2023
Admin=76561198106004468:Whitelist // Trippy Chivas - devbryanbar@gmail.com
Admin=76561198209119887:Whitelist // RIOTYouth1 - aclerc1220@gmail.com
Admin=76561198312514319:Whitelist // {ASG} Scarface - logangrimes11@gmail.com
Admin=76561198983371735:Whitelist // {ASG} young sloth - logangrimes11@gmail.com
Admin=76561198221715432:Whitelist // Skillet - Server Administrator
Admin=76561198026192477:Whitelist // LtJamesFox - Nevetsu@hotmail.com
Admin=76561198059124010:Whitelist // tcandan88(4skin) - ducati979@aol.com
Admin=76561199062085282:Whitelist // Dick Deflator - Granted Whitelist for 3 month's started 12/01/2022/Ends 02/28/2023
Admin=76561198059462064:Whitelist // Bagels - adroessler10@gmail.com
Admin=76561198119385943:Whitelist // Hypothermiack -
Admin=76561199123384670:Whitelist // TapatioTimmy - camdenricketts4@gmail.com
Admin=76561199285813056:Whitelist // TheGoochSlooth - justintestorelli@gmail.com
Admin=76561197963075020:Whitelist // Subterfuge - jwlind@gmail.com
Admin=76561198128034210:Whitelist // Kybar - carbarykyle@gmail.com
Admin=76561198049739312:Whitelist // Juggernaut - robledoaustin@yahoo.com
Admin=76561197979663830:Whitelist // DamiSupreme - alexdemiane93@gmail.com
Admin=76561199241025555:Whitelist // Dang Li Wang - n.hinesly0602@gmail.com
Admin=76561199241627472:Whitelist // Jenna Tools - n.hinesly0602@gmail.com
Admin=76561199302780874:Whitelist // Mr_poopy_diaper - Attached to (ASG) Kybar (carbarykyle@gmail.com)
Admin=76561198801895406:Whitelist // OneBarStatus - jacobadams135@yahoo.com
// === CAS ===
Admin=7656119844551138:CAS // Albertime - CAS
Admin=76561198094918611:CAS // JF - CAS
Admin=76561198153409985:CAS // Jashy - CAS
Admin=76561198150626482:CAS // Oscar - CAS
Admin=76561198248146940:CAS // Skay - CAS
// === HC ===
Admin=76561198043032389:HC // Sir Peabody - HC
Admin=76561197982328479:HC // Kameron - HC
Admin=76561198101099268:HC // Evans - HC
Admin=76561198249614886:HC // Brodizle - HC
Admin=76561198191984002:HC // Skeebler - HC
// === SLT ===
Admin=76561198149412908:SLT // EnderDevs - SLT
Admin=76561198448114730:SLT // JoeBrandonCheated - SLT
// === BR1 ===
Admin=76561199060693600:BR1 // Madtopher - BR1
Admin=76561198037486479:BR1 // Dr. Hammerstein - BR1
Admin=76561198315718944:BR1 // Bags - BR1