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
Beispiel #3
0
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()