Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ASFConnector.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def get_bot_info(self, bot):
def bot_redeem(self, bot, keys):
""" Redeems cd-keys on given bot. """
LOG.debug('bot_redeem: bot {}, keys {}'.format(bot, keys))
assert type(keys) is set or type(keys) is str
assert isinstance(keys, (list, set, str))
resource = '/Bot/' + bot + '/Redeem'
if type(keys) is str:
payload_keys = [keys]
Expand Down
52 changes: 40 additions & 12 deletions bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from ASFConnector import ASFConnector


_REGEX_CDKEY = re.compile(r'\w{5}-\w{5}-\w{5}')
_REGEX_CDKEY = re.compile(r"\b[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}\b", re.IGNORECASE)
_REGEX_COMMAND_BOT_ARGS = r'^[/!]\w+\s*(?P<bot>\w+)?\s+(?P<arg>.*)'
_REGEX_COMMAND_RAW = r'^[/!](?P<input>(?P<command>\w+).*)'
_REGEX_COMMAND = r'^[/!]\w+\s*(?P<bot>\w+)?'
Expand Down Expand Up @@ -139,11 +139,12 @@ def status_command(message):
response = asf_connector.get_bot_info(bot_arg)
LOG.info("Response to status message: %s", str(response))
reply_to(message, "<code>" + str(response) + "</code>")
except requests.HTTPError as http_error:
except requests.exceptions.HTTPError as http_error:
LOG.exception(http_error)
response = http_error.response
status_code = response.status_code
except requests.ConnectionError as connection_error:
reply_to(message, "ASF HTTP error: <code>{}</code>".format(status_code))
except requests.exceptions.ConnectionError as connection_error:
LOG.exception(connection_error)
error_message = str(connection_error.args[0].reason.args[0]).split('>:')[1]
error_response = "Couldn't reach the ASF instance: <code>{}</code>".format(error_message)
Expand All @@ -153,18 +154,30 @@ def status_command(message):
LOG.exception(ex)


@bot.message_handler(commands=['redeem'])
@bot.message_handler(func=is_user_message, commands=['redeem'])
def redeem_command(message):
LOG.debug("Received redeem message: %s", str(message))
match = re.search(_REGEX_COMMAND_BOT_ARGS, message.text)
match = re.search(_REGEX_COMMAND_BOT_ARGS, message.text, re.DOTALL)
if not match:
reply_to(message, "Missing arguments. Usage:\n<code>/redeem &lt;bot&gt; &lt;keys&gt;</code>")
return
bots = match.group('bot') if match.group('bot') else 'ASF'
keys = match.group('arg')
response = asf_connector.bot_redeem(bots, keys)
LOG.info("Response to redeem message: %s", str(response))
reply_to(message, "<code>" + str(response) + "</code>")
raw_keys = match.group('arg')
keys = _normalize_keys(raw_keys)
if not keys:
reply_to(message, "No valid keys found.")
return
try:
response = asf_connector.bot_redeem(bots, keys)
LOG.info("Response to redeem message: %s", str(response))
reply_to(message, "<code>" + str(response) + "</code>")
except requests.exceptions.HTTPError as ex:
status_code = ex.response.status_code if ex.response is not None else "?"
LOG.error(ex)
reply_to(message, 'Redeem failed. ASF status code: <code>{}</code>'.format(status_code))
except Exception as ex:
LOG.exception("Redeem unexpected error")
reply_to(message, 'Redeem failed: <code>{}</code>'.format(str(ex)))


@bot.message_handler(func=is_user_message, regexp=_REGEX_COMMAND_RAW)
Expand All @@ -181,7 +194,7 @@ def command_handler(message):
try:
asf_response = asf_connector.send_command(command)
LOG.info("Command: {}. Response: {}".format(message.text, asf_response))
response = replace_html_entities(asf_response)
response = replace_html_entities(str(asf_response))
except requests.exceptions.HTTPError as ex:
status_code = ex.response.status_code
LOG.error(ex)
Expand All @@ -194,8 +207,8 @@ def check_for_cdkeys(message):
"""
Sync handler for the rest of the messages. It searchs for cdkeys and redeems them.
"""
cdkeys = set(_REGEX_CDKEY.findall(message.text))
if len(cdkeys) > 0:
cdkeys = _normalize_keys(message.text)
if cdkeys:
response = asf_connector.bot_redeem('ASF', cdkeys)
reply_to(message, "<code>" + str(response) + "</code>")
else:
Expand Down Expand Up @@ -227,3 +240,18 @@ def replace_html_entities(message: str):
except Exception as e:
LOG.exception(e)

def _normalize_keys(text_or_iterable):
"""Return a list of unique, uppercased CD-keys (5-5-5 format) from a string or iterable."""
if not text_or_iterable:
return []
if isinstance(text_or_iterable, str):
found = _REGEX_CDKEY.findall(text_or_iterable.upper())
if found:
# preserve order and drop duplicates
return list(dict.fromkeys(found))
# Fallback split on common separators
parts = re.split(r"[\s,;]+", text_or_iterable.strip())
parts = [p.upper() for p in parts if p]
return list(dict.fromkeys(parts))
# Iterable case
return list(dict.fromkeys([str(x).upper().strip() for x in text_or_iterable if str(x).strip()]))