def get_jsonpath(self): am = AccessManager() # noinspection PyTypeChecker am.init(DummyBot()) # Get variables like jsonpath path = am.jsonpath del am return path
class TestAccessmanager(): am = None jsonpath = None def get_jsonpath(self): am = AccessManager() # noinspection PyTypeChecker am.init(DummyBot()) # Get variables like jsonpath path = am.jsonpath del am return path # noinspection PyPep8Naming def delete_JSON_if_exists(self): if os.path.exists(self.jsonpath): os.remove(self.jsonpath) def setup(self): self.jsonpath = self.get_jsonpath() self.delete_JSON_if_exists() self.am = AccessManager() self.am.jsonfile = self.am.jsonpath # noinspection PyTypeChecker self.am.init(DummyBot()) def teardown(self): if os.path.exists(self.am.jsonpath): os.remove(self.am.jsonpath) if os.path.exists(self.am.jsonpath + ".bak"): os.remove(self.am.jsonpath + ".bak") def test_accessmanager_init(self): assert self.am.jsonpath is not None #TODO: something else to test? def test_accessmanager_json(self): acls = {"a": "b", "c": {"d": [1, 2 ,"3"]}} groups = {"A": "B", "C": {"D": [10, 20 ,"30"]}} self.am.acls = acls self.am.groups = groups self.am.write_JSON() self.am.acls = None self.am.groups = None self.am.read_JSON() assert self.am.acls == acls assert self.am.groups == groups def test_accessmanager_addgroup(self): self.am.groups = {} self.am.add_group("grp1") assert self.am.groups == {'grp1': {'members': []}} self.am.add_group("grp2", "member") assert self.am.groups == {'grp2': {'members': ['member']}, 'grp1': {'members': []}} self.am.add_group("grp3", ["member1", "member2"]) assert self.am.groups == {'grp3': {'members': ['member1', 'member2']}, 'grp2': {'members': ['member']}, 'grp1': {'members': []}} def test_accessmanager_removegroup(self): self.am.groups = {} self.am.remove_group("grp1") assert self.am.groups == {} self.am.groups = {'grp2': {'members': ['member']}, 'grp1': {'members': []}} self.am.remove_group("grp2") assert self.am.groups == {'grp1': {'members': []}} def test_accessmanager_existsgroup(self): self.am.groups = {} self.am.add_group("grp1") assert self.am.exists_group("grp1") assert not self.am.exists_group("grp2") def test_accessmanager_getgroup(self): self.am.add_group("getgroup") grp = self.am.get_group("getgroup") assert grp.name == "getgroup" def test_accessmanager_addtogroup(self): self.am.add_group("test") self.am.add_to_group("test", "user") assert self.am.get_group("test").get_members() == ["user"] def test_accessmanager_removefromgroup(self): self.am.add_group("g1", ["a", "b"]) self.am.add_group("g2", ["a", "b"]) self.am.remove_from_group("g1", "a") self.am.remove_from_group("g2", "b") assert self.am.get_group("g1").get_members() == ["b"] assert self.am.get_group("g2").get_members() == ["a"] def test_accessmanager_createacl(self): self.am.create_acl("a.b.c.*") assert self.am.acls["a.b.c.*"] == {"groups": [], "members": []} assert not "a.b.c.d" in self.am.acls.keys() def test_accessmanager_removeacl(self): self.am.create_acl("a") self.am.create_acl("b") self.am.remove_acl("a") self.am.remove_acl("c") assert list(self.am.acls.keys()) == ["b"] def test_accessmanager_existsacl(self): self.am.create_acl("a") assert "a" in self.am.acls.keys() assert "b" not in self.am.acls.keys() def test_accessmanager_registeracl(self): self.am.register_acl("acl1") self.am.register_acl("acl1") self.am.register_acl("acl1") assert len(self.am.acls) == 1 assert ["%moderators"] == self.am.acls["acl1"]["groups"] assert len(self.am.acls["acl1"]["members"]) == 0 self.am.add_group("a") # Make sure groups to test with exist self.am.add_group("c") self.am.register_acl("acl2", "a", "b") self.am.register_acl("acl3", ["c"], ["d"]) assert self.am.acls["acl2"]["groups"] == ["a"] assert self.am.acls["acl2"]["members"] == ["b"] assert self.am.acls["acl3"]["groups"] == ["c"] assert self.am.acls["acl3"]["members"] == ["d"] def test_accessmanager_addgrouptoacl(self): self.am.add_group("a") # Make sure groups to test with exist self.am.add_group("b") self.am.register_acl("acl", ["a"], []) self.am.add_group_to_acl("acl", "b") assert self.am.acls["acl"]["groups"] == ["a", "b"] def test_accessmanager_removegroupfromacl(self): self.am.add_group("a") # Make sure groups to test with exist self.am.add_group("b") self.am.register_acl("acl", ["a", "b"], []) self.am.remove_group_from_acl("acl", "a") assert self.am.acls["acl"]["groups"] == ["b"] def test_accessmanager_addusertoacl(self): self.am.register_acl("acl", [], ["a"]) self.am.add_user_to_acl("acl", "b") assert self.am.acls["acl"]["members"] == ["a", "b"] def test_accessmanager_removeuserfromacl(self): self.am.register_acl("acl1", [], ["a", "b", "c"]) self.am.remove_user_from_acl("acl1", "b") assert self.am.acls["acl1"]["members"] == ["a", "c"] def test_accessmanager_expandgroups(self): assert self.am.expand_groups("%moderators").sort() == ["%moderators", "%operators", "%owner"].sort() assert self.am.expand_groups("%operators").sort() == ["%operators", "%owner"].sort() assert self.am.expand_groups("%owner") == ["%owner"] assert self.am.expand_groups(["test", "%operators"]).sort() == ["test", "%operators", "%owner"].sort() def test_accessmanager_isinacl(self): pass #TODO: Write access tests
class Bot: """ Mainclass for the application, everything goes through here """ def __init__(self): logutils.setup_logging("mustikkabot") self.log = logging.getLogger("mustikkabot") self.basepath = tools.find_basepath() self.confdir = os.path.join(self.basepath, "config") self.datadir = os.path.join(self.basepath, "data") self.srcdir = os.path.join(self.basepath, "src") setup.setup(self) setup.do_migrations(self) self.ircsock = None self.lastReceived = None self.user = None self.channel = None self.eventmanager = EventManager() """ :type: EventManager""" self.modulemanager = ModuleManager() """ :type: ModuleManager""" self.accessmanager = AccessManager() """ :type: AccessManager""" self.timemanager = TimeManager() """ :type: TimeManager""" self.run = True def parse_config(self): """ :return: list of strings describing parameters :rtype: list(string, string, string, string) Parse the config file, and read the different defined parameters. Return them as a list """ try: settings_f = open(os.path.join(self.confdir, "config.txt")) except IOError: self.log.error("Config not found, please make a copy of" " \"config/config.txt.template\" as \"config/config.txt\"") sys.exit() host = None username = None password = None channel = None try: for line in settings_f: line = line.strip("\n\r") if line.find('host') != -1: host = line.split(":")[1] if line.find('user') != -1: username = line.split(":")[1] if line.find('pass') != -1: password = '******'.join(line.split(":")[1:]) if line.find('chnl') != -1: channel = line.split(":")[1] except IndexError: self.log.error("Malformed config file, please fix") sys.exit() settings_f.close() passwd_hidden = "" for c in password: # Hide auth token/password from log messages passwd_hidden += '*' self.log.info("PARAMETERS: Host: %s, username: %s, password: %s, channel: %s" % (host, username, passwd_hidden, channel)) return host, username, password, channel def connect(self, params): """ :param params: A list of the params to be used to connect :type params: list(string, string, string, string) Try to connect to the IRC server using the provided parameters """ try: self.ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.ircsock.settimeout(30) self.ircsock.connect((params[0], 6667)) self.ircsock.setblocking(0) self.send_data("PASS %s" % (params[2]), dontLog=True) self.send_data("NICK %s" % (params[1])) self.send_data("USER %s mustikkaBot 127.0.0.1 :mustikkaBot" % (params[1])) self.send_data("JOIN %s" % (params[3])) except Exception as e: traceback.print_exc() self.log.error("\n\nError connecting: %s" % e) sys.exit() def get_data(self): """ :return: Data received from the socket :rtype: str Return any data that has been received """ try: data = self.ircsock.recv(1024) data = data.decode("utf-8", "replace").strip('\r\n') if not len(data) == 0: self.log.debug("RECV: <>" + data + "<>") return data except socket.error as e: err = e.args[0] if err == errno.EAGAIN or err == errno.EWOULDBLOCK: return "" # no data def send_data(self, data, dontLog=False): """ :param data: String to be sent :type data: str :param dontLog: Will the string be logged? :type dontLog: bool Send data appended with a newline """ if not (data is "" or data is None): if not dontLog: self.log.debug("SEND: " + data) self.ircsock.send(bytes(data + "\n", "UTF-8")) def send_message(self, msg): """ :param msg: Message to be sent :type msg: str Send a message to the channel """ self.send_data("PRIVMSG " + self.channel + " :" + msg) def sigint(self, signal, frame): """ :param signal: Signal received :param frame: ... A signal handler to trap ^C """ self.log.info("^C received, stopping") self.run = False def main(self): """ The startpoint of the bot """ settings = self.parse_config() self.user = settings[1] self.channel = settings[3] self.accessmanager.init(self) self.modulemanager.init(self) try: self.connect(settings) self.lastReceived = datetime.datetime.now() except: self.log.error("Error connecting to IRC") sleep(3) signal.signal(signal.SIGINT, self.sigint) sleep(1) while self.run: # Get new data ircmsg = self.get_data() # Process CLI if platform.system() != "Windows": cli = select.select([sys.stdin], [], [], 0)[0] else: cli = False # No cli on windows because you can't select stdin if cli: data = sys.stdin.readline().strip() if len(data) > 0: self.eventmanager.handle_message(":cli!cli@localhost PRIVMSG " + self.channel + " :" + data) # Handle data if received if not (ircmsg is None or len(ircmsg) == 0): for line in ircmsg.split('\n'): self.lastReceived = datetime.datetime.now() if line.find(' PRIVMSG ') != -1: self.eventmanager.handle_message(line) else: self.eventmanager.handle_special(line) # Provied timed events to timemanager self.timemanager.handle_events() # Check "watchdog" if self.lastReceived and datetime.datetime.now() - self.lastReceived > datetime.timedelta(minutes=15): self.log.warning("No messages received within 15 minutesr, trying to reconnect") try: self.connect(settings) # Reconnect self.lastReceived = datetime.datetime.now() except: self.log.error("Error connecting to IRC") sleep(3) sleep(0.01) # Shut down self.modulemanager.dispose() self.accessmanager.dispose()