From db688ab0d68d132a8a17c1a16b669499a83bd7bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Rudowicz?= Date: Sun, 12 Oct 2025 21:48:18 +0200 Subject: [PATCH] Initial version of the HSWro party line --- groupchatbot/bot.py | 72 ++++++++++++++++++++++++++++++++++- groupchatbot/requirements.txt | 1 + 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/groupchatbot/bot.py b/groupchatbot/bot.py index f42141a..592a112 100644 --- a/groupchatbot/bot.py +++ b/groupchatbot/bot.py @@ -1,11 +1,81 @@ from lxmfbot import LXMFBot +from redis import Redis +from time import monotonic +from hashlib import sha256 +import json +from functools import reduce bot = LXMFBot("HSWro Conference Bot") +PASS = '34a77e61000b2ba1f56201332ef64d93f9cdc60e63ab48bc255102586ef7e592' +WRONG_LOGIN_BAN_DURATION = 60 + + +def check_password(password: str) -> bool: + gotten = sha256(f"hswrosalt{password}".encode( + 'utf-8'), usedforsecurity=True).hexdigest() + return PASS == gotten + + +def ban_sender(r, userhash, until): + r.rpush("hswroconference:banned", str(json.dumps({ + "hash": userhash, + "until": str(until), + }))) + + +def check_banned(r, userhash): + for raw in r.lrange("hswroconference:banned", 0, -1): + m = json.loads(raw.decode('utf-8')) + if m['hash'] == userhash: + if monotonic() > float(m['until']): + r.lrem("hswroconference:banned", 0, raw) + print(f"Ban expired for {userhash}, unbanning") + return False + return True + + +def handle_login(msg, r, from_known_sender): + def login_usage(): + msg.reply("Usage: `/login [NICK] [PASSWORD]`") + parts = msg.content.split() + if len(parts) != 3: + login_usage() + return + assert parts[0] == "/login" + if not check_password(parts[2]): + ban_sender(r, msg.sender, monotonic() + WRONG_LOGIN_BAN_DURATION) + return + r.rpush("hswroconference:users", str(json.dumps({ + "hash": msg.sender, + "nick": parts[1], + }))) + msg.reply(f"Logged in as {parts[1]}.") @bot.received def echo_msg(msg): - msg.reply(msg.content) + r = Redis(host='localhost', port=6379, db=0) + if check_banned(r, msg.sender): + print(f"Message from banned user: {msg.sender}") + return + known_senders = list(map(lambda x: json.loads(x.decode('utf-8')), + r.lrange("hswroconference:users", 0, -1))) + sender_info = reduce(lambda x, y: y if (y["hash"] == msg.sender) else x, + known_senders, None) + from_known_sender = sender_info is not None + assert isinstance(msg.content, str) + if msg.content.startswith("/login"): + handle_login(msg, r, from_known_sender) + return + + if not from_known_sender: + msg.reply("Please identify with `/login [NICK] [PASSWORD]`") + else: + print(f"Forwarding message from {sender_info['nick']}") + for r in known_senders: + if r["hash"] == msg.sender: + continue + bot.send(r["hash"], f"<{sender_info['nick']}> {msg.content}") bot.run() diff --git a/groupchatbot/requirements.txt b/groupchatbot/requirements.txt index eceb1e3..4532e0f 100644 --- a/groupchatbot/requirements.txt +++ b/groupchatbot/requirements.txt @@ -1,3 +1,4 @@ appdirs==1.4.4 lxmf==0.8 rns==1.0 +redis==6.4.0