mirror of
https://github.com/Ryujinx/ryuko-ng.git
synced 2024-12-22 20:15:30 +00:00
Delete all logs with blocked ids & Add cheat analysis (#48)
* Rename disabled_tids to disabled_ids and start adding support for bids * Add cheat information * Add analysis block for build ids Always remove blocked game logs * Add ro_section to disabled_ids * Search all potential log files for blocked games * Add commands to block ro_sections of games * Change order of macro command arguments * Add new disabled_ids key to wanted_jsons
This commit is contained in:
parent
18970723e7
commit
77fc2040a2
|
@ -56,7 +56,7 @@ wanted_jsons = [
|
||||||
"data/invites.json",
|
"data/invites.json",
|
||||||
"data/macros.json",
|
"data/macros.json",
|
||||||
"data/persistent_roles.json",
|
"data/persistent_roles.json",
|
||||||
"data/disabled_tids.json",
|
"data/disabled_ids.json",
|
||||||
]
|
]
|
||||||
|
|
||||||
for wanted_json_idx in range(len(wanted_jsons)):
|
for wanted_json_idx in range(len(wanted_jsons)):
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
from discord import Colour, Embed, Message, Attachment
|
from discord import Colour, Embed, Message, Attachment
|
||||||
|
@ -7,12 +8,20 @@ from discord.ext import commands
|
||||||
from discord.ext.commands import Cog, Context
|
from discord.ext.commands import Cog, Context
|
||||||
|
|
||||||
from robocop_ng.helpers.checks import check_if_staff
|
from robocop_ng.helpers.checks import check_if_staff
|
||||||
from robocop_ng.helpers.disabled_tids import (
|
from robocop_ng.helpers.disabled_ids import (
|
||||||
add_disabled_tid,
|
add_disabled_app_id,
|
||||||
is_tid_valid,
|
is_app_id_valid,
|
||||||
remove_disabled_tid,
|
remove_disabled_app_id,
|
||||||
get_disabled_tids,
|
get_disabled_ids,
|
||||||
is_tid_disabled,
|
is_app_id_disabled,
|
||||||
|
is_build_id_valid,
|
||||||
|
add_disabled_build_id,
|
||||||
|
remove_disabled_build_id,
|
||||||
|
is_build_id_disabled,
|
||||||
|
is_ro_section_disabled,
|
||||||
|
is_ro_section_valid,
|
||||||
|
add_disabled_ro_section,
|
||||||
|
remove_disabled_ro_section,
|
||||||
)
|
)
|
||||||
|
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
|
@ -50,6 +59,113 @@ class LogFileReader(Cog):
|
||||||
async with session.get(log_url, headers=headers) as response:
|
async with session.get(log_url, headers=headers) as response:
|
||||||
return await response.text("UTF-8")
|
return await response.text("UTF-8")
|
||||||
|
|
||||||
|
def get_main_ro_section(self, log_file: str) -> Optional[dict[str, str]]:
|
||||||
|
ro_section_regex = re.search(
|
||||||
|
r"PrintRoSectionInfo: main:[\r\n]*(.*)", log_file, re.DOTALL
|
||||||
|
)
|
||||||
|
if ro_section_regex is not None and len(ro_section_regex.groups()) > 0:
|
||||||
|
ro_section = {"module": "", "sdk_libraries": []}
|
||||||
|
for line in ro_section_regex.group(1).splitlines():
|
||||||
|
line = line.strip()
|
||||||
|
if line.startswith("Module:"):
|
||||||
|
ro_section["module"] = line[8:]
|
||||||
|
elif line.startswith("SDK Libraries:"):
|
||||||
|
ro_section["sdk_libraries"].append(line[19:])
|
||||||
|
elif line.startswith("SDK "):
|
||||||
|
ro_section["sdk_libraries"].append(line[4:])
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
return ro_section
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_app_info(
|
||||||
|
self, log_file: str
|
||||||
|
) -> Optional[tuple[str, str, list[str], dict[str, str]]]:
|
||||||
|
game_name = re.search(
|
||||||
|
r"Loader [A-Za-z]*: Application Loaded:\s([^;\n\r]*)",
|
||||||
|
log_file,
|
||||||
|
re.MULTILINE,
|
||||||
|
)
|
||||||
|
if game_name is not None and len(game_name.groups()) > 0:
|
||||||
|
game_name = game_name.group(1).rstrip()
|
||||||
|
app_id_regex = re.match(r".* \[([a-zA-Z0-9]*)\]", game_name)
|
||||||
|
if app_id_regex:
|
||||||
|
app_id = app_id_regex.group(1).strip()
|
||||||
|
else:
|
||||||
|
app_id = None
|
||||||
|
bids_regex = re.search(
|
||||||
|
r"Build ids found for title ([a-zA-Z0-9]*):[\n\r]*(.*)",
|
||||||
|
log_file,
|
||||||
|
re.DOTALL,
|
||||||
|
)
|
||||||
|
if bids_regex is not None and len(bids_regex.groups()) > 0:
|
||||||
|
app_id_from_bids = bids_regex.group(1).strip()
|
||||||
|
build_ids = [
|
||||||
|
bid.strip()
|
||||||
|
for bid in bids_regex.group(2).splitlines()
|
||||||
|
if is_build_id_valid(bid.strip())
|
||||||
|
]
|
||||||
|
|
||||||
|
# TODO: Check if self.get_main_ro_section() is None and return an error
|
||||||
|
return (
|
||||||
|
app_id,
|
||||||
|
app_id_from_bids,
|
||||||
|
build_ids,
|
||||||
|
self.get_main_ro_section(log_file),
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def is_log_valid(self, log_file: str) -> bool:
|
||||||
|
app_info = self.get_app_info(log_file)
|
||||||
|
if app_info is None:
|
||||||
|
return True
|
||||||
|
app_id, another_app_id, _, _ = app_info
|
||||||
|
return app_id == another_app_id
|
||||||
|
|
||||||
|
def is_game_blocked(self, log_file: str) -> bool:
|
||||||
|
app_info = self.get_app_info(log_file)
|
||||||
|
if app_info is None:
|
||||||
|
return False
|
||||||
|
app_id, another_app_id, build_ids, main_ro_section = app_info
|
||||||
|
if is_app_id_disabled(self.bot, app_id) or is_app_id_disabled(
|
||||||
|
self.bot, another_app_id
|
||||||
|
):
|
||||||
|
return True
|
||||||
|
for bid in build_ids:
|
||||||
|
if is_build_id_disabled(self.bot, bid):
|
||||||
|
return True
|
||||||
|
return is_ro_section_disabled(self.bot, main_ro_section)
|
||||||
|
|
||||||
|
async def blocked_game_action(self, message: Message) -> Embed:
|
||||||
|
warn_command = self.bot.get_command("warn")
|
||||||
|
if warn_command is not None:
|
||||||
|
warn_message = await message.reply(
|
||||||
|
".warn This log contains a blocked game."
|
||||||
|
)
|
||||||
|
warn_context = await self.bot.get_context(warn_message)
|
||||||
|
await warn_context.invoke(
|
||||||
|
warn_command,
|
||||||
|
target=None,
|
||||||
|
reason="This log contains a blocked game.",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
logging.error(
|
||||||
|
f"Couldn't find 'warn' command. Unable to warn {message.author}."
|
||||||
|
)
|
||||||
|
|
||||||
|
pirate_role = message.guild.get_role(self.bot.config.named_roles["pirate"])
|
||||||
|
await message.author.add_roles(pirate_role)
|
||||||
|
|
||||||
|
embed = Embed(
|
||||||
|
title="⛔ Blocked game detected ⛔",
|
||||||
|
colour=Colour(0xFF0000),
|
||||||
|
description="This log contains a blocked game and has been removed.\n"
|
||||||
|
"The user has been warned and the pirate role was applied.",
|
||||||
|
)
|
||||||
|
embed.set_footer(text=f"Log uploaded by @{message.author.name}")
|
||||||
|
await message.delete()
|
||||||
|
return embed
|
||||||
|
|
||||||
async def log_file_read(self, message):
|
async def log_file_read(self, message):
|
||||||
self.embed = {
|
self.embed = {
|
||||||
"hardware_info": {
|
"hardware_info": {
|
||||||
|
@ -67,6 +183,7 @@ class LogFileReader(Cog):
|
||||||
"game_name": "Unknown",
|
"game_name": "Unknown",
|
||||||
"errors": "No errors found in log",
|
"errors": "No errors found in log",
|
||||||
"mods": "No mods found",
|
"mods": "No mods found",
|
||||||
|
"cheats": "No cheats found",
|
||||||
"notes": [],
|
"notes": [],
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
|
@ -103,20 +220,6 @@ class LogFileReader(Cog):
|
||||||
description="This log file appears to be invalid. Please make sure to upload a Ryujinx log file.",
|
description="This log file appears to be invalid. Please make sure to upload a Ryujinx log file.",
|
||||||
)
|
)
|
||||||
|
|
||||||
def is_tid_blocked(log_file=log_file):
|
|
||||||
game_name = re.search(
|
|
||||||
r"Loader [A-Za-z]*: Application Loaded:\s([^;\n\r]*)",
|
|
||||||
log_file,
|
|
||||||
re.MULTILINE,
|
|
||||||
)
|
|
||||||
if game_name is not None and len(game_name.groups()) > 0:
|
|
||||||
game_name = game_name.group(1).rstrip()
|
|
||||||
tid = re.match(r".* \[([a-zA-Z0-9]*)\]", game_name)
|
|
||||||
if tid is not None:
|
|
||||||
tid = tid.group(1).strip()
|
|
||||||
return is_tid_disabled(self.bot, tid)
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_hardware_info(log_file=log_file):
|
def get_hardware_info(log_file=log_file):
|
||||||
for setting in self.embed["hardware_info"]:
|
for setting in self.embed["hardware_info"]:
|
||||||
try:
|
try:
|
||||||
|
@ -284,6 +387,9 @@ class LogFileReader(Cog):
|
||||||
log_embed.add_field(
|
log_embed.add_field(
|
||||||
name="Mods", value=self.embed["game_info"]["mods"], inline=False
|
name="Mods", value=self.embed["game_info"]["mods"], inline=False
|
||||||
)
|
)
|
||||||
|
log_embed.add_field(
|
||||||
|
name="Cheats", value=self.embed["game_info"]["cheats"], inline=False
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
notes_value = "\n".join(game_notes)
|
notes_value = "\n".join(game_notes)
|
||||||
|
@ -540,11 +646,20 @@ class LogFileReader(Cog):
|
||||||
mods_status = list(dict.fromkeys(mods_status))
|
mods_status = list(dict.fromkeys(mods_status))
|
||||||
return mods_status
|
return mods_status
|
||||||
|
|
||||||
|
def cheat_information(log_file=log_file):
|
||||||
|
cheat_regex = re.compile(r"Installing cheat\s\'(.+?)\'")
|
||||||
|
matches = re.findall(cheat_regex, log_file)
|
||||||
|
if matches:
|
||||||
|
cheats = [match[0] for match in matches]
|
||||||
|
return list(set(cheats))
|
||||||
|
|
||||||
game_mods = mods_information()
|
game_mods = mods_information()
|
||||||
if game_mods:
|
if game_mods:
|
||||||
self.embed["game_info"]["mods"] = "\n".join(game_mods)
|
self.embed["game_info"]["mods"] = "\n".join(game_mods)
|
||||||
else:
|
|
||||||
pass
|
game_cheats = cheat_information()
|
||||||
|
if game_cheats:
|
||||||
|
self.embed["game_info"]["cheats"] = "\n".join(game_cheats)
|
||||||
|
|
||||||
controllers_regex = re.compile(r"Hid Configure: ([^\r\n]+)")
|
controllers_regex = re.compile(r"Hid Configure: ([^\r\n]+)")
|
||||||
controllers = re.findall(controllers_regex, log_file)
|
controllers = re.findall(controllers_regex, log_file)
|
||||||
|
@ -721,35 +836,25 @@ class LogFileReader(Cog):
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if is_tid_blocked():
|
if self.is_game_blocked(log_file):
|
||||||
warn_command = self.bot.get_command("warn")
|
return await self.blocked_game_action(message)
|
||||||
if warn_command is not None:
|
|
||||||
warn_message = await message.reply(
|
|
||||||
".warn This log contains a blocked title id."
|
|
||||||
)
|
|
||||||
warn_context = await self.bot.get_context(warn_message)
|
|
||||||
await warn_context.invoke(
|
|
||||||
warn_command,
|
|
||||||
target=None,
|
|
||||||
reason="This log contains a blocked title id.",
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
logging.error(
|
|
||||||
f"Couldn't find 'warn' command. Unable to warn {message.author}."
|
|
||||||
)
|
|
||||||
|
|
||||||
pirate_role = message.guild.get_role(self.bot.config.named_roles["pirate"])
|
for role in message.author.roles:
|
||||||
await message.author.add_roles(pirate_role)
|
if role.id in self.disallowed_roles:
|
||||||
|
embed = Embed(
|
||||||
|
colour=Colour(0xFF0000),
|
||||||
|
description="I'm not allowed to analyse this log.",
|
||||||
|
)
|
||||||
|
embed.set_footer(text=f"Log uploaded by {author_name}")
|
||||||
|
return embed
|
||||||
|
|
||||||
|
if not self.is_log_valid(log_file):
|
||||||
embed = Embed(
|
embed = Embed(
|
||||||
title="⛔ Blocked game detected ⛔",
|
title="⚠️ Modified log detected ⚠️",
|
||||||
colour=Colour(0xFF0000),
|
colour=Colour(0xFCFC00),
|
||||||
description="This log contains a blocked title id and has been removed.\n"
|
description="This log contains manually modified information and won't be analysed.",
|
||||||
"The user has been warned and the pirate role was applied.",
|
|
||||||
)
|
)
|
||||||
embed.set_footer(text=f"Log uploaded by {author_name}")
|
embed.set_footer(text=f"Log uploaded by {author_name}")
|
||||||
|
|
||||||
await message.delete()
|
|
||||||
return embed
|
return embed
|
||||||
|
|
||||||
get_hardware_info()
|
get_hardware_info()
|
||||||
|
@ -760,52 +865,185 @@ class LogFileReader(Cog):
|
||||||
|
|
||||||
@commands.check(check_if_staff)
|
@commands.check(check_if_staff)
|
||||||
@commands.command(
|
@commands.command(
|
||||||
aliases=["disallow_log_tid", "forbid_log_tid", "block_tid", "blocktid"]
|
aliases=["disallow_log_id", "forbid_log_id", "block_id", "blockid"]
|
||||||
)
|
)
|
||||||
async def disable_log_tid(self, ctx: Context, tid: str, note=""):
|
async def disable_log_id(
|
||||||
if not is_tid_valid(tid):
|
self, ctx: Context, block_id_type: str, block_id: str, note=""
|
||||||
return await ctx.send("The specified TID is invalid.")
|
):
|
||||||
|
match block_id_type.lower():
|
||||||
|
case "app" | "app_id" | "appid" | "tid" | "title_id":
|
||||||
|
if not is_app_id_valid(block_id):
|
||||||
|
return await ctx.send("The specified app id is invalid.")
|
||||||
|
|
||||||
if add_disabled_tid(self.bot, tid, note):
|
if add_disabled_app_id(self.bot, block_id, note):
|
||||||
return await ctx.send(f"TID '{tid}' is now blocked!")
|
return await ctx.send(
|
||||||
else:
|
f"Application id '{block_id}' is now blocked!"
|
||||||
return await ctx.send(f"TID '{tid}' is already blocked.")
|
)
|
||||||
|
else:
|
||||||
|
return await ctx.send(
|
||||||
|
f"Application id '{block_id}' is already blocked."
|
||||||
|
)
|
||||||
|
case "build" | "build_id", "bid":
|
||||||
|
if not is_build_id_valid(block_id):
|
||||||
|
return await ctx.send("The specified build id is invalid.")
|
||||||
|
|
||||||
|
if add_disabled_build_id(self.bot, block_id, note):
|
||||||
|
return await ctx.send(f"Build id '{block_id}' is now blocked!")
|
||||||
|
else:
|
||||||
|
return await ctx.send(f"Build id '{block_id}' is already blocked.")
|
||||||
|
case _:
|
||||||
|
return await ctx.send(
|
||||||
|
"The specified id type is invalid. Valid id types are: ['app_id', 'build_id']"
|
||||||
|
)
|
||||||
|
|
||||||
@commands.check(check_if_staff)
|
@commands.check(check_if_staff)
|
||||||
@commands.command(
|
@commands.command(
|
||||||
aliases=[
|
aliases=[
|
||||||
"allow_log_tid",
|
"allow_log_id",
|
||||||
"unblock_log_tid",
|
"unblock_log_id",
|
||||||
"unblock_tid",
|
"unblock_id",
|
||||||
"allow_tid",
|
"allow_id",
|
||||||
"unblocktid",
|
"unblockid",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
async def enable_log_tid(self, ctx: Context, tid: str):
|
async def enable_log_id(self, ctx: Context, block_id_type: str, block_id: str):
|
||||||
if not is_tid_valid(tid):
|
match block_id_type.lower():
|
||||||
return await ctx.send("The specified TID is invalid.")
|
case "app" | "app_id" | "appid" | "tid" | "title_id":
|
||||||
|
if not is_app_id_valid(block_id):
|
||||||
|
return await ctx.send("The specified app id is invalid.")
|
||||||
|
|
||||||
if remove_disabled_tid(self.bot, tid):
|
if remove_disabled_app_id(self.bot, block_id):
|
||||||
return await ctx.send(f"TID '{tid}' is now unblocked!")
|
return await ctx.send(
|
||||||
else:
|
f"Application id '{block_id}' is now unblocked!"
|
||||||
return await ctx.send(f"TID '{tid}' is not blocked.")
|
)
|
||||||
|
else:
|
||||||
|
return await ctx.send(
|
||||||
|
f"Application id '{block_id}' is not blocked."
|
||||||
|
)
|
||||||
|
case "build" | "build_id", "bid":
|
||||||
|
if not is_build_id_valid(block_id):
|
||||||
|
return await ctx.send("The specified build id is invalid.")
|
||||||
|
|
||||||
|
if remove_disabled_build_id(self.bot, block_id):
|
||||||
|
return await ctx.send(f"Build id '{block_id}' is now unblocked!")
|
||||||
|
else:
|
||||||
|
return await ctx.send(f"Build id '{block_id}' is not blocked.")
|
||||||
|
case _:
|
||||||
|
return await ctx.send(
|
||||||
|
"The specified id type is invalid. Valid id types are: ['app_id', 'build_id']"
|
||||||
|
)
|
||||||
|
|
||||||
@commands.check(check_if_staff)
|
@commands.check(check_if_staff)
|
||||||
@commands.command(
|
@commands.command(
|
||||||
aliases=[
|
aliases=[
|
||||||
"blocked_tids",
|
"blocked_ids",
|
||||||
"listblockedtids",
|
"listblockedids",
|
||||||
"list_blocked_log_tids",
|
"list_blocked_log_ids",
|
||||||
"list_blocked_tids",
|
"list_blocked_ids",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
async def list_disabled_tids(self, ctx: Context):
|
async def list_disabled_ids(self, ctx: Context):
|
||||||
disabled_tids = get_disabled_tids(self.bot)
|
disabled_ids = get_disabled_ids(self.bot)
|
||||||
message = "**Blocking analysis of the following TIDs:**\n"
|
message = "**Blocking analysis of the following IDs:**\n"
|
||||||
for tid, note in disabled_tids.items():
|
for id_type, name in {
|
||||||
message += f"- [{tid.upper()}]: {note}\n" if note != "" else f"- [{tid}]\n"
|
"app_id": "Application IDs",
|
||||||
|
"build_id": "Build IDs",
|
||||||
|
}.items():
|
||||||
|
if len(disabled_ids[id_type].keys()) > 0:
|
||||||
|
message += f"- {name}:\n"
|
||||||
|
for disabled_id, note in disabled_ids[id_type].items():
|
||||||
|
message += (
|
||||||
|
f" - [{disabled_id.upper()}]: {note}\n"
|
||||||
|
if note != ""
|
||||||
|
else f" - [{disabled_id}]\n"
|
||||||
|
)
|
||||||
|
message += "\n"
|
||||||
|
if len(disabled_ids["ro_section"].keys()) > 0:
|
||||||
|
message += "- Read-only sections:\n"
|
||||||
|
for note in disabled_ids["ro_section"].keys():
|
||||||
|
f"- [{note}]"
|
||||||
return await ctx.send(message)
|
return await ctx.send(message)
|
||||||
|
|
||||||
|
@commands.check(check_if_staff)
|
||||||
|
@commands.command(
|
||||||
|
aliases=[
|
||||||
|
"disallow_ro_section",
|
||||||
|
"forbid_ro_section",
|
||||||
|
"block_ro_section",
|
||||||
|
"blockrosection",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
async def disable_ro_section(
|
||||||
|
self, ctx: Context, note: str, ro_section_snippet: str
|
||||||
|
):
|
||||||
|
ro_section_snippet = ro_section_snippet.strip("`").splitlines()
|
||||||
|
ro_section_snippet = [
|
||||||
|
line for line in ro_section_snippet if len(line.strip()) > 0
|
||||||
|
]
|
||||||
|
|
||||||
|
ro_section_info_regex = re.search(
|
||||||
|
r"PrintRoSectionInfo: main:", ro_section_snippet[0]
|
||||||
|
)
|
||||||
|
if ro_section_info_regex is None:
|
||||||
|
ro_section_snippet.insert(0, "PrintRoSectionInfo: main:")
|
||||||
|
|
||||||
|
ro_section = self.get_main_ro_section("\n".join(ro_section_snippet))
|
||||||
|
if ro_section is not None and is_ro_section_valid(ro_section):
|
||||||
|
if add_disabled_ro_section(self.bot, note, ro_section):
|
||||||
|
return await ctx.send(
|
||||||
|
f"The specified read-only section '{note}' is now blocked."
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return await ctx.send(
|
||||||
|
f"The specified read-only section '{note}' is already blocked."
|
||||||
|
)
|
||||||
|
|
||||||
|
@commands.check(check_if_staff)
|
||||||
|
@commands.command(
|
||||||
|
aliases=[
|
||||||
|
"allow_ro_section",
|
||||||
|
"unblock_ro_section",
|
||||||
|
"allow_rosection",
|
||||||
|
"unblockrosection",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
async def enable_ro_section(self, ctx: Context, note: str):
|
||||||
|
if remove_disabled_ro_section(self.bot, note):
|
||||||
|
return await ctx.send(
|
||||||
|
f"The read-only section for '{note}' is now unblocked!"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return await ctx.send(f"The read-only section for '{note}' is not blocked.")
|
||||||
|
|
||||||
|
@commands.check(check_if_staff)
|
||||||
|
@commands.command(
|
||||||
|
aliases=[
|
||||||
|
"get_blocked_ro_section",
|
||||||
|
"disabled_ro_section",
|
||||||
|
"blocked_ro_section" "list_disabled_ro_section",
|
||||||
|
"list_blocked_ro_section",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
async def get_disabled_ro_section(self, ctx: Context, note: str):
|
||||||
|
disabled_ids = get_disabled_ids(self.bot)
|
||||||
|
key_note = note.lower()
|
||||||
|
if key_note in disabled_ids["ro_section"].keys():
|
||||||
|
message = f"**Disabled read-only section for '{note}'**:\n"
|
||||||
|
message += "```\n"
|
||||||
|
for key, content in disabled_ids["ro_section"][key_note].items():
|
||||||
|
match key:
|
||||||
|
case "module":
|
||||||
|
message += f"Module: {content}\n"
|
||||||
|
case "sdk_libraries":
|
||||||
|
message += f"SDK Libraries: \n"
|
||||||
|
for entry in content:
|
||||||
|
message += f" SDK {entry}\n"
|
||||||
|
message += "\n"
|
||||||
|
message += "```"
|
||||||
|
return await ctx.send(message)
|
||||||
|
else:
|
||||||
|
return await ctx.send("The specified read-only section is not blocked.")
|
||||||
|
|
||||||
async def analyse_log_message(self, message: Message, attachment_index=0):
|
async def analyse_log_message(self, message: Message, attachment_index=0):
|
||||||
author_id = message.author.id
|
author_id = message.author.id
|
||||||
author_mention = message.author.mention
|
author_mention = message.author.mention
|
||||||
|
@ -814,12 +1052,6 @@ class LogFileReader(Cog):
|
||||||
# Any message over 2000 chars is uploaded as message.txt, so this is accounted for
|
# Any message over 2000 chars is uploaded as message.txt, so this is accounted for
|
||||||
log_file_link = message.jump_url
|
log_file_link = message.jump_url
|
||||||
|
|
||||||
for role in message.author.roles:
|
|
||||||
if role.id in self.disallowed_roles:
|
|
||||||
return await message.channel.send(
|
|
||||||
"I'm not allowed to analyse this log."
|
|
||||||
)
|
|
||||||
|
|
||||||
uploaded_logs_exist = [
|
uploaded_logs_exist = [
|
||||||
True for elem in self.uploaded_log_info if filename in elem.values()
|
True for elem in self.uploaded_log_info if filename in elem.values()
|
||||||
]
|
]
|
||||||
|
@ -911,7 +1143,22 @@ class LogFileReader(Cog):
|
||||||
for attachment in message.attachments:
|
for attachment in message.attachments:
|
||||||
is_log_file, is_ryujinx_log_file = self.is_valid_log_name(attachment)
|
is_log_file, is_ryujinx_log_file = self.is_valid_log_name(attachment)
|
||||||
|
|
||||||
if (
|
if is_log_file and not is_ryujinx_log_file:
|
||||||
|
attached_log = message.attachments[0]
|
||||||
|
log_file = await self.download_file(attached_log.url)
|
||||||
|
# Large files show a header value when not downloaded completely
|
||||||
|
# this regex makes sure that the log text to read starts from the first timestamp, ignoring headers
|
||||||
|
log_file_header_regex = re.compile(
|
||||||
|
r"\d{2}:\d{2}:\d{2}\.\d{3}.*", re.DOTALL
|
||||||
|
)
|
||||||
|
log_file_match = re.search(log_file_header_regex, log_file)
|
||||||
|
if log_file_match:
|
||||||
|
log_file = log_file_match.group(0)
|
||||||
|
if self.is_game_blocked(log_file):
|
||||||
|
return await message.channel.send(
|
||||||
|
content=None, embed=await self.blocked_game_action(message)
|
||||||
|
)
|
||||||
|
elif (
|
||||||
is_log_file
|
is_log_file
|
||||||
and is_ryujinx_log_file
|
and is_ryujinx_log_file
|
||||||
and message.channel.id in self.bot_log_allowed_channels.values()
|
and message.channel.id in self.bot_log_allowed_channels.values()
|
||||||
|
|
|
@ -23,7 +23,9 @@ class Macro(Cog):
|
||||||
|
|
||||||
@commands.cooldown(3, 30, BucketType.member)
|
@commands.cooldown(3, 30, BucketType.member)
|
||||||
@commands.command(aliases=["m"])
|
@commands.command(aliases=["m"])
|
||||||
async def macro(self, ctx: Context, target: Optional[discord.Member], key: str):
|
async def macro(
|
||||||
|
self, ctx: Context, key: str, target: Optional[discord.Member] = None
|
||||||
|
):
|
||||||
await ctx.message.delete()
|
await ctx.message.delete()
|
||||||
if len(key) > 0:
|
if len(key) > 0:
|
||||||
text = get_macro(self.bot, key)
|
text = get_macro(self.bot, key)
|
||||||
|
|
133
robocop_ng/helpers/disabled_ids.py
Normal file
133
robocop_ng/helpers/disabled_ids.py
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
|
def get_disabled_ids_path(bot) -> str:
|
||||||
|
old_filepath = os.path.join(bot.state_dir, "data/disabled_tids.json")
|
||||||
|
new_filepath = os.path.join(bot.state_dir, "data/disabled_ids.json")
|
||||||
|
if os.path.isfile(old_filepath):
|
||||||
|
os.rename(old_filepath, new_filepath)
|
||||||
|
return new_filepath
|
||||||
|
|
||||||
|
|
||||||
|
def is_app_id_valid(app_id: str) -> bool:
|
||||||
|
return len(app_id) == 16 and app_id.isalnum()
|
||||||
|
|
||||||
|
|
||||||
|
def is_build_id_valid(build_id: str) -> bool:
|
||||||
|
return 32 <= len(build_id) <= 64 and build_id.isalnum()
|
||||||
|
|
||||||
|
|
||||||
|
def is_ro_section_valid(ro_section: dict[str, str]) -> bool:
|
||||||
|
return "module" in ro_section.keys() and "sdk_libraries" in ro_section.keys()
|
||||||
|
|
||||||
|
|
||||||
|
def get_disabled_ids(bot) -> dict[str, dict[str, Union[str, dict[str, str]]]]:
|
||||||
|
if os.path.isfile(get_disabled_ids_path(bot)):
|
||||||
|
with open(get_disabled_ids_path(bot), "r") as f:
|
||||||
|
disabled_ids = json.load(f)
|
||||||
|
# Migration code
|
||||||
|
if "app_id" not in disabled_ids.keys():
|
||||||
|
disabled_ids = {"app_id": disabled_ids, "build_id": {}, "ro_section": {}}
|
||||||
|
return disabled_ids
|
||||||
|
|
||||||
|
return {"app_id": {}, "build_id": {}, "ro_section": {}}
|
||||||
|
|
||||||
|
|
||||||
|
def set_disabled_ids(bot, contents: dict[str, dict[str, Union[str, dict[str, str]]]]):
|
||||||
|
with open(get_disabled_ids_path(bot), "w") as f:
|
||||||
|
json.dump(contents, f)
|
||||||
|
|
||||||
|
|
||||||
|
def is_app_id_disabled(bot, app_id: str) -> bool:
|
||||||
|
disabled_ids = get_disabled_ids(bot)
|
||||||
|
app_id = app_id.lower()
|
||||||
|
return app_id in disabled_ids["app_id"].keys()
|
||||||
|
|
||||||
|
|
||||||
|
def is_build_id_disabled(bot, build_id: str) -> bool:
|
||||||
|
disabled_ids = get_disabled_ids(bot)
|
||||||
|
build_id = build_id.lower()
|
||||||
|
if len(build_id) < 64:
|
||||||
|
build_id += "0" * (64 - len(build_id))
|
||||||
|
return build_id in disabled_ids["build_id"].keys()
|
||||||
|
|
||||||
|
|
||||||
|
def is_ro_section_disabled(bot, ro_section: dict[str, str]) -> bool:
|
||||||
|
disabled_ids = get_disabled_ids(bot)
|
||||||
|
matches = []
|
||||||
|
for note, entry in disabled_ids["ro_section"].items():
|
||||||
|
for key, content in entry.items():
|
||||||
|
matches.append(ro_section[key].lower() == content.lower())
|
||||||
|
if all(matches):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
matches = []
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def add_disabled_app_id(bot, app_id: str, note="") -> bool:
|
||||||
|
disabled_ids = get_disabled_ids(bot)
|
||||||
|
app_id = app_id.lower()
|
||||||
|
if app_id not in disabled_ids["app_id"].keys():
|
||||||
|
disabled_ids["app_id"][app_id] = note
|
||||||
|
set_disabled_ids(bot, disabled_ids)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def remove_disabled_app_id(bot, app_id: str) -> bool:
|
||||||
|
disabled_ids = get_disabled_ids(bot)
|
||||||
|
app_id = app_id.lower()
|
||||||
|
if app_id in disabled_ids["app_id"].keys():
|
||||||
|
del disabled_ids["app_id"][app_id]
|
||||||
|
set_disabled_ids(bot, disabled_ids)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def add_disabled_build_id(bot, build_id: str, note="") -> bool:
|
||||||
|
disabled_ids = get_disabled_ids(bot)
|
||||||
|
build_id = build_id.lower()
|
||||||
|
if len(build_id) < 64:
|
||||||
|
build_id += "0" * (64 - len(build_id))
|
||||||
|
if build_id not in disabled_ids["build_id"].keys():
|
||||||
|
disabled_ids["build_id"][build_id] = note
|
||||||
|
set_disabled_ids(bot, disabled_ids)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def remove_disabled_build_id(bot, build_id: str) -> bool:
|
||||||
|
disabled_ids = get_disabled_ids(bot)
|
||||||
|
build_id = build_id.lower()
|
||||||
|
if len(build_id) < 64:
|
||||||
|
build_id += "0" * (64 - len(build_id))
|
||||||
|
if build_id in disabled_ids["build_id"].keys():
|
||||||
|
del disabled_ids["build_id"][build_id]
|
||||||
|
set_disabled_ids(bot, disabled_ids)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def add_disabled_ro_section(bot, note: str, ro_section: dict[str, str]) -> bool:
|
||||||
|
disabled_ids = get_disabled_ids(bot)
|
||||||
|
note = note.lower()
|
||||||
|
if note not in disabled_ids["ro_section"].keys():
|
||||||
|
disabled_ids["ro_section"][note] = {}
|
||||||
|
for key, content in ro_section.items():
|
||||||
|
disabled_ids["ro_section"][note][key] = content.lower()
|
||||||
|
set_disabled_ids(bot, disabled_ids)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def remove_disabled_ro_section(bot, note: str) -> bool:
|
||||||
|
disabled_ids = get_disabled_ids(bot)
|
||||||
|
note = note.lower()
|
||||||
|
if note in disabled_ids["ro_section"].keys():
|
||||||
|
del disabled_ids["ro_section"][note]
|
||||||
|
set_disabled_ids(bot, disabled_ids)
|
||||||
|
return True
|
||||||
|
return False
|
|
@ -1,48 +0,0 @@
|
||||||
import json
|
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
def get_disabled_tids_path(bot) -> str:
|
|
||||||
return os.path.join(bot.state_dir, "data/disabled_tids.json")
|
|
||||||
|
|
||||||
|
|
||||||
def is_tid_valid(tid: str) -> bool:
|
|
||||||
return len(tid) == 16 and tid.isalnum()
|
|
||||||
|
|
||||||
|
|
||||||
def get_disabled_tids(bot) -> dict[str, str]:
|
|
||||||
if os.path.isfile(get_disabled_tids_path(bot)):
|
|
||||||
with open(get_disabled_tids_path(bot), "r") as f:
|
|
||||||
return json.load(f)
|
|
||||||
return {}
|
|
||||||
|
|
||||||
|
|
||||||
def set_disabled_tids(bot, contents: dict[str, str]):
|
|
||||||
with open(get_disabled_tids_path(bot), "w") as f:
|
|
||||||
json.dump(contents, f)
|
|
||||||
|
|
||||||
|
|
||||||
def is_tid_disabled(bot, tid: str) -> bool:
|
|
||||||
disabled_tids = get_disabled_tids(bot)
|
|
||||||
tid = tid.lower()
|
|
||||||
return tid in disabled_tids.keys()
|
|
||||||
|
|
||||||
|
|
||||||
def add_disabled_tid(bot, tid: str, note="") -> bool:
|
|
||||||
disabled_tids = get_disabled_tids(bot)
|
|
||||||
tid = tid.lower()
|
|
||||||
if tid not in disabled_tids.keys():
|
|
||||||
disabled_tids[tid] = note
|
|
||||||
set_disabled_tids(bot, disabled_tids)
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def remove_disabled_tid(bot, tid: str) -> bool:
|
|
||||||
disabled_tids = get_disabled_tids(bot)
|
|
||||||
tid = tid.lower()
|
|
||||||
if tid in disabled_tids.keys():
|
|
||||||
del disabled_tids[tid]
|
|
||||||
set_disabled_tids(bot, disabled_tids)
|
|
||||||
return True
|
|
||||||
return False
|
|
Loading…
Reference in a new issue