Skip to content

Commit

Permalink
fix(irc): restrict the start of usernames even more
Browse files Browse the repository at this point in the history
Turns out, they have to start with [a-zA-Z0-9].
  • Loading branch information
TrueBrain committed Jun 27, 2023
1 parent be03b1c commit 0b75d6c
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 17 deletions.
28 changes: 19 additions & 9 deletions dibridge/irc.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@
# talk to someone if they are in an active conversation with them.
LEFT_WHILE_TALKING_TIMEOUT = 60 * 10

# By RFC, only these characters are allowed in a nickname.
REGEX_NICKNAME_FILTER = r"[^a-zA-Z0-9_\-\[\]\{\}\|]"
# By RFC, a nickname cannot start with a number or a dash.
REGEX_NICKNAME_START_FILTER = r"^[0-9\-]+"
# By implementation, a username is more strict than a nickname in what
# it can start with. This filter is in addition to the nickname filters.
REGEX_USERNAME_START_FILTER = r"^[_\[\]\{\}\|]+"


class IRCRelay(irc.client_aio.AioSimpleIRCClient):
def __init__(self, host, port, nickname, channel, puppet_ip_range, puppet_postfix, ignore_list, idle_timeout):
Expand Down Expand Up @@ -129,10 +137,8 @@ async def _pinger(self):

async def _connect(self):
while True:
username = self._nickname
# An additional constraints usernames have over nicknames, that they are
# also not allowed to start with an underscore.
username = re.sub(r"^_+", "", username)
# Additional constraints usernames have over nicknames.
username = re.sub(REGEX_USERNAME_START_FILTER, "", self._nickname)

try:
await self.connection.connect(
Expand Down Expand Up @@ -168,11 +174,15 @@ async def _send_message(self, discord_id, discord_username, message, is_action=F
sanitized_discord_username = self._sanitize_discord_username(discord_username)
ipv6_address = self._puppet_ip_range[self._generate_ipv6_bits(sanitized_discord_username)]

irc_nickname = f"{sanitized_discord_username}{self._puppet_postfix}"
irc_username = re.sub(REGEX_USERNAME_START_FILTER, "", irc_nickname)

self._puppets[discord_id] = IRCPuppet(
self._host,
self._port,
ipv6_address,
f"{sanitized_discord_username}{self._puppet_postfix}",
irc_nickname,
irc_username,
self._channel,
functools.partial(self._remove_puppet, discord_id),
self._idle_timeout,
Expand Down Expand Up @@ -211,10 +221,10 @@ def _sanitize_discord_username(self, discord_username):
original_discord_username = discord_username

discord_username = discord_username.strip()
# Remove all characters not allowed in IRC usernames.
discord_username = re.sub(r"[^a-zA-Z0-9_\-\[\]\{\}\|]", "", discord_username)
# Make sure a username doesn't start with a number or "-".
discord_username = re.sub(r"^[0-9\-]", "", discord_username)
# Remove all characters not allowed in IRC nicknames.
discord_username = re.sub(REGEX_NICKNAME_FILTER, "", discord_username)
# Make sure a nicknames doesn't start with an invalid character.
discord_username = re.sub(REGEX_NICKNAME_START_FILTER, "", discord_username)

# On Discord you can create usernames that don't contain any character valid
# on IRC, leaving an empty username. In that case we have no option but to
Expand Down
11 changes: 3 additions & 8 deletions dibridge/irc_puppet.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import asyncio
import irc.client_aio
import logging
import re
import socket


class IRCPuppet(irc.client_aio.AioSimpleIRCClient):
def __init__(self, irc_host, irc_port, ipv6_address, nickname, channel, remove_puppet_func, idle_timeout):
def __init__(self, irc_host, irc_port, ipv6_address, nickname, username, channel, remove_puppet_func, idle_timeout):
irc.client.SimpleIRCClient.__init__(self)

self.loop = asyncio.get_event_loop()
Expand All @@ -17,6 +16,7 @@ def __init__(self, irc_host, irc_port, ipv6_address, nickname, channel, remove_p
self._nickname = nickname
self._nickname_original = nickname
self._nickname_iteration = 0
self._username = username
self._joined = False
self._channel = channel
self._pinger_task = None
Expand Down Expand Up @@ -140,17 +140,12 @@ async def connect(self):
local_addr = (str(self._ipv6_address), 0)

while self._reconnect:
username = self._nickname
# An additional constraints usernames have over nicknames, that they are
# also not allowed to start with an underscore.
username = re.sub(r"^_+", "", username)

try:
await self.connection.connect(
self._irc_host,
self._irc_port,
self._nickname,
username=username,
username=self._username,
# We force an IPv6 connection, as we need that for the puppet source address.
connect_factory=irc.connection.AioFactory(
family=socket.AF_INET6, local_addr=local_addr, ssl=self._irc_port == 6697
Expand Down

0 comments on commit 0b75d6c

Please sign in to comment.