Skip to content

Commit 03db626

Browse files
Turn bad paste sites into mystbin pastes (#41)
* Add badbin searching * run lints * run lints again * use mystbin client to create pastes * Files require attachment urls for mystbin.py now * lints again -_- --------- Co-authored-by: Alex Nørgaard <[email protected]>
1 parent f408bfe commit 03db626

File tree

3 files changed

+61
-0
lines changed

3 files changed

+61
-0
lines changed

config.template.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ pythonista = '' # optional key
1010
[DATABASE]
1111
dsn = 'postgres://pythonistabot:pythonistabot@database:5432/pythonistabot' # assumed default
1212

13+
[BADBIN]
14+
domains = ["pastebin.com", "hastebin.com"]
15+
1316
# 50 = CRITICAL
1417
# 40 = ERROR
1518
# 30 = WARNING

modules/moderation.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,13 @@
2626
import base64
2727
import binascii
2828
import datetime
29+
import logging
2930
import re
3031
from textwrap import shorten
3132
from typing import TYPE_CHECKING, Any, Self, TypeAlias
3233

3334
import discord
35+
import mystbin
3436
import yarl
3537
from discord.ext import commands
3638

@@ -45,6 +47,9 @@
4547

4648
ModLogType: TypeAlias = PythonistaAPIWebsocketPayload[ModLogPayload]
4749

50+
logger = logging.getLogger(__name__)
51+
52+
BASE_BADBIN_RE = r"https://(?P<site>{domains})/(?P<slug>[a-zA-Z0-9]+)[.]?(?P<ext>[a-z]{{1,8}})?"
4853
TOKEN_RE = re.compile(r"[a-zA-Z0-9_-]{23,28}\.[a-zA-Z0-9_-]{6,7}\.[a-zA-Z0-9_-]{27}")
4954
PROSE_LOOKUP = {
5055
1: "banned",
@@ -105,6 +110,12 @@ def __init__(self, bot: core.Bot, /) -> None:
105110
self.dpy_mod_cache: dict[int, discord.User | discord.Member] = {}
106111
self._req_lock = asyncio.Lock()
107112

113+
domains = core.CONFIG["BADBIN"]["domains"]
114+
formatted = BASE_BADBIN_RE.format(domains="|".join(domains))
115+
116+
self.BADBIN_RE = re.compile(formatted)
117+
logger.info("Badbin initialized with following domains: %s", ", ".join(domains))
118+
108119
async def github_request(
109120
self,
110121
method: str,
@@ -195,6 +206,48 @@ async def find_discord_tokens(self, message: discord.Message) -> None:
195206
)
196207
await message.reply(msg)
197208

209+
async def pull_badbin_content(self, site: str, slug: str, *, fail_hard: bool = True) -> str:
210+
async with self.bot.session.get(f"https://{site}/raw/{slug}") as f:
211+
if 200 > f.status > 299:
212+
if fail_hard:
213+
f.raise_for_status()
214+
else:
215+
err = f"Could not read {slug} from {site}. Details: {f.status}\n\n{await f.read()}"
216+
logger.error(err)
217+
return err # if we don't fail hard, we'll return the error message in the new paste.
218+
219+
return (await f.read()).decode()
220+
221+
async def post_mystbin_content(self, contents: list[tuple[str, str]]) -> tuple[str, str | None]:
222+
response = await self.bot.mb_client.create_paste(
223+
files=[mystbin.File(filename=a, content=b, attachment_url=None) for a, b in contents]
224+
)
225+
return response.id, response.notice or None
226+
227+
@commands.Cog.listener("on_message")
228+
async def find_badbins(self, message: discord.Message) -> None:
229+
matches = self.BADBIN_RE.findall(message.content)
230+
231+
if matches:
232+
contents: list[tuple[str, str]] = []
233+
234+
for match in matches:
235+
site, slug, ext = match
236+
237+
if site is None or slug is None:
238+
continue
239+
240+
contents.append((await self.pull_badbin_content(site, slug), f"migrated.{ext or 'txt'}"))
241+
242+
if contents:
243+
key, notice = await self.post_mystbin_content(contents)
244+
msg = f"I've detected a badbin and have uploaded your pastes here: https://mystb.in/{key}"
245+
246+
if notice:
247+
msg += "\nnotice: " + notice
248+
249+
await message.reply(msg, mention_author=False)
250+
198251
@commands.Cog.listener()
199252
async def on_papi_dpy_modlog(self, payload: ModLogType, /) -> None:
200253
moderation_payload = payload["payload"]

types_/config.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,15 @@ class Snekbox(TypedDict):
2727
url: str
2828

2929

30+
class BadBin(TypedDict):
31+
domains: list[str]
32+
33+
3034
class Config(TypedDict):
3135
prefix: str
3236
owner_ids: NotRequired[list[int]]
3337
TOKENS: Tokens
3438
DATABASE: Database
3539
LOGGING: Logging
3640
SNEKBOX: NotRequired[Snekbox]
41+
BADBIN: BadBin

0 commit comments

Comments
 (0)