Exemple #1
0
    def lottery_buy(self, event):
        amount = event["spec"][0] or 1

        user_coins = self._get_user_coins(event["user"])
        coin_amount = decimal.Decimal(LOTTERY_BUYIN) * amount
        new_user_coins = user_coins - coin_amount
        redeem_amount = self._redeem_amount(event["server"])

        if coin_amount > user_coins:
            raise utils.EventError("%s: You don't have enough coins" %
                                   event["user"].nickname)
        elif new_user_coins < redeem_amount:
            raise utils.EventError(
                "%s: you can't play the lottery if it puts your total coins "
                "below %s" %
                (event["user"].nickname, self._coin_str(redeem_amount)))

        self._take(event["server"], event["user"], coin_amount)

        lottery = event["server"].get_setting("lottery", {})
        nickname = event["user"].nickname_lower
        if not nickname in lottery:
            lottery[nickname] = 0
        lottery[nickname] += amount
        event["server"].set_setting("lottery", lottery)

        event["stdout"].write(
            "%s: You bought %d lottery ticket%s for %s" %
            (event["user"].nickname, amount, "" if amount == 1 else "s",
             self._coin_str(coin_amount)))
Exemple #2
0
    def _mute(self, event):
        add = event.name == "received.command.mute"

        target_name = event["args_split"][0]
        if not event["server"].has_user(target_name):
            raise utils.EventError("No such user")

        target_user = event["server"].get_user(target_name)
        if not event["target"].has_user(target_user):
            raise utils.EventError("No such user")

        mode, mask = self._mute_method(event["server"], target_user)
        if mode == None:
            raise utils.EventError("This network doesn't support mutes")

        if add and len(event["args_split"]) > 1:
            duration = utils.from_pretty_time(event["args_split"][1])
            if duration == None:
                raise utils.EventError("Invalid duration")

            self.timers.add_persistent("unmute",
                                       duration,
                                       server_id=event["server"].id,
                                       channel_name=event["target"].name,
                                       mode=mode,
                                       mask=mask)

        mode_modifier = "+" if add else "-"
        event["target"].send_mode("%s%s" % (mode_modifier, mode), [mask])
Exemple #3
0
    def flip(self, event):
        side_name = event["spec"][0]
        coin_bet = event["spec"][1]
        if coin_bet == "all":
            coin_bet = self._get_user_coins(event["user"])
            if coin_bet <= DECIMAL_ZERO:
                raise utils.EventError("%s: You have no coins to bet" %
                                       event["user"].nickname)

        user_coins = self._get_user_coins(event["user"])
        if coin_bet > user_coins:
            raise utils.EventError("%s: You don't have enough coins to bet" %
                                   event["user"].nickname)

        chosen_side = random.SystemRandom().choice(list(SIDES.keys()))
        win = side_name == chosen_side

        coin_bet_str = self._coin_str_human(coin_bet)
        if win:
            new_total = self._give(event["server"], event["user"], coin_bet)
            event["stdout"].write(
                "%s flips %s and wins %s coin%s! (new total: %s)" %
                (event["user"].nickname, side_name, coin_bet_str, ""
                 if coin_bet == 1 else "s", self._coin_str_human(new_total)))
        else:
            self._take(event["server"], event["user"], coin_bet)
            event["stdout"].write(
                "%s flips %s and loses %s coin%s! (new total: %s)" %
                (event["user"].nickname, side_name, coin_bet_str,
                 "" if coin_bet == 1 else "s",
                 self._coin_str_human(user_coins - coin_bet)))
Exemple #4
0
    def roll_dice(self, event):
        dice_count, side_count = 1, 6
        roll = "1d6"
        modifiers = []

        if event["spec"][0]:
            dice_count = int(event["spec"][0].group(1) or "1")
            side_count = int(event["spec"][0].group(2))
            roll = event["spec"][0].group(0)
            modifiers = RE_MODIFIERS.findall(event["spec"][0].group(3))

        if dice_count > 6:
            raise utils.EventError("Max number of dice is %s" % MAX_DICE)
        if side_count > MAX_SIDES:
            raise utils.EventError("Max number of sides is %s"
                % MAX_SIDES)

        results = random.choices(range(1, side_count+1), k=dice_count)

        total_n = sum(results)
        for modifier in modifiers:
            if modifier[0] == "+":
                total_n += int(modifier[1:])
            else:
                total_n -= int(modifier[1:])

        total = ""
        if len(results) > 1 or modifiers:
            total = " (total: %d)" % total_n

        results_str = ", ".join(str(r) for r in results)
        event["stdout"].write("Rolled %s and got %s%s" % (
            roll, results_str, total))
Exemple #5
0
    def vote(self, event):
        """
        :help: Vote in the channel's current vote
        :usage: <id> [choice]
        """
        vote_id = event["args_split"][0]
        vote = self._get_vote(event["target"], vote_id)
        if vote == None:
            raise utils.EventError(STR_NOVOTE % vote_id)

        if not len(event["args_split"]) > 1:
            closed = "" if vote["open"] else " (closed)"
            event["stdout"].write("Vote %s%s: %s" %
                                  (vote_id, closed, self._format_vote(vote)))
        else:
            if not vote["open"]:
                raise utils.EventError("%s: vote %s is closed" %
                                       (event["user"].nickname, vote_id))

            choice = event["args_split"][1].lower()
            if not choice in vote["options"]:
                raise utils.EventError("Vote options: %s" %
                                       self._format_options(vote))

            cast_result = self._cast_vote(event["target"], vote_id,
                                          event["user"], choice)

            cast_desc = "has been cast"
            if cast_result == VoteCastResult.Changed:
                cast_desc = "has been changed"
            elif cast_result == VoteCastResult.Unchanged:
                cast_desc = "is unchanged"

            event["stdout"].write("%s: your vote %s." %
                                  (event["user"].nickname, cast_desc))
Exemple #6
0
    def in_list(self, event):
        """
        :help: List reminders
        :usage: [index]
        """
        timers = self.timers.find_all("in")
        found = []
        for timer in timers:
            nickname_match = (event["server"].irc_lower(
                timer.kwargs["nickname"]) == event["user"].nickname_lower)
            target_match = timer.kwargs["target"] == event["target"].name

            if nickname_match and target_match:
                found.append(timer)

        if len(event["args_split"]) > 0:
            index = event["args_split"][0]
            if not index.isdigit() or index == "0":
                raise utils.EventError("Please provide a valid reminder index")

            index = int(index)
            actual_index = index - 1
            if actual_index > len(found):
                raise utils.EventError("You do not have that many reminders")

            timer = found[actual_index]
            event["stdout"].write("Reminder %d: %s" %
                                  (index, timer.kwargs["message"]))
        else:
            event["stdout"].write("%s: you have %d reminders" %
                                  (event["user"].nickname, len(found)))
Exemple #7
0
    def tfollow(self, event):
        """
        :help: Stream tweets from a given account to the current channel
        :usage: add|remove @<username>
        :permission: twitter-follow
        """
        username = event["args_split"][1]
        if username.startswith("@"):
            username = username[1:]

        subcommand = event["args_split"][0].lower()
        follows = event["target"].get_setting("twitter-follow", [])
        action = None

        if subcommand == "add":
            action = "followed"
            if username in follows:
                raise utils.EventError("Already following %s" % username)
            follows.append(username)
        elif subcommand == "remove":
            action = "unfollowed"
            if not username in follows:
                raise utils.EventError("Not following %s" % username)
            follows.remove(username)
        else:
            raise utils.EventError("Unknown subcommand")

        event["target"].set_setting("twitter-follow", follows)
        self._start_stream()
        event["stdout"].write("%s @%s" % (action.title(), username))
Exemple #8
0
    def _perform(self, target, args_split):
        subcommand = args_split[0].lower()
        current_perform = target.get_setting("perform", [])
        if subcommand == "list":
            return "Configured commands: %s" % ", ".join(current_perform)

        message = None
        if subcommand == "add":
            if not len(args_split) > 1:
                raise utils.EventError("Please provide a raw command to add")
            current_perform.append(" ".join(args_split[1:]))
            message = "Added command"
        elif subcommand == "remove":
            if not len(args_split) > 1:
                raise utils.EventError("Please provide an index to remove")
            if not args_split[1].isdigit():
                raise utils.EventError("Please provide a number")
            index = int(args_split[1])
            if not index < len(current_perform):
                raise utils.EventError("Index out of bounds")
            current_perform.pop(index)
            message = "Removed command"
        else:
            raise utils.EventError("Unknown subcommand '%s'" % subcommand)

        target.set_setting("perform", current_perform)
        return message
Exemple #9
0
    def title(self, event):
        """
        :help: Get the title of a URL
        :usage: [URL]
        """
        url = None
        if len(event["args"]) > 0:
            url = event["args_split"][0]
        else:
            url = event["target"].buffer.find(REGEX_URL)
            if url:
                url = re.search(REGEX_URL, url.message).group(0)
        if not url:
            raise utils.EventError("No URL provided/found.")

        try:
            page = utils.http.request(url, soup=True)
        except Exception as e:
            self.log.error("failed to get URL title", exc_info=True)
            page = None
            pass

        if not page:
            raise utils.EventError("Failed to get URL.")

        title = page.data.title
        if title:
            title = title.text.replace("\n",
                                       " ").replace("\r",
                                                    "").replace("  ",
                                                                " ").strip()
            event["stdout"].write(title)
        else:
            event["stderr"].write("No title found.")
Exemple #10
0
    def relay_group(self, event):
        subcommand = event["args_split"][0].lower()

        group_settings = self.bot.find_settings(prefix="relay-group-")
        groups = {}
        for setting, value in group_settings:
            name = setting.replace("relay-group-", "", 1)
            groups[name] = value

        if subcommand == "list":
            event["stdout"].write("Relay groups: %s" % ", ".join(groups.keys()))
            return

        if not len(event["args_split"]) > 1:
            raise utils.EventError("Please provide a group name")

        name = event["args_split"][1].lower()

        event["check_assert"](utils.Check("is-channel"))
        current_channel = [event["server"].id, event["target"].name]
        channel_groups = event["target"].get_setting("relay-groups", [])

        message = None
        remove = False

        if subcommand == "join":
            if not name in groups:
                groups[name] = []

            if current_channel in groups[name] or name in channel_groups:
                raise utils.EventError("Already joined group '%s'" % name)

            groups[name].append(current_channel)
            channel_groups.append(name)
            message = "Joined"

        elif subcommand == "leave":
            if (not name in groups or
                    not current_channel in groups[name] or
                    not name in channel_groups):
                raise utils.EventError("Not in group '%s'" % name)

            groups[name].remove(current_channel)
            channel_groups.remove(name)
            message = "Left"
        else:
            raise utils.EventError("Unknown subcommand '%s'" % subcommand)

        if not message == None:
            if not groups[name]:
                self.bot.del_setting("relay-group-%s" % name)
            else:
                self.bot.set_setting("relay-group-%s" % name, groups[name])

            if channel_groups:
                event["target"].set_setting("relay-groups", channel_groups)
            else:
                event["target"].del_setting("relay-groups")

            event["stdout"].write("%s group '%s'" % (message, name))
Exemple #11
0
    def edit_server(self, event):
        alias = event["spec"][0]
        server_id = self._id_from_alias(alias)
        if server_id == None:
            raise utils.EventError("Unknown server '%s'" % alias)

        option = event["spec"][1].lower()
        value = event["spec"][2]
        value_parsed = None

        if option == "hostname":
            value_parsed = value
        elif option == "port":
            if not value.isdigit():
                raise utils.EventError("Invalid port")
            value_parsed = int(value.lstrip("0"))
        elif option == "tls":
            value_lower = value.lower()
            if not value_lower in ["yes", "no"]:
                raise utils.EventError("TLS should be either 'yes' or 'no'")
            value_parsed = value_lower == "yes"
        elif option == "password":
            value_parsed = value
        elif option == "bindhost":
            value_parsed = value
        elif option in ["nickname", "username", "realname"]:
            value_parsed = value
        else:
            raise utils.EventError("Unknown option '%s'" % option)

        self.bot.database.servers.edit(server_id, option, value_parsed)
        event["stdout"].write("Set %s for %s" % (option, alias))
Exemple #12
0
    def send(self, event):
        target_user = event["spec"][0]

        if event["user"].get_id() == target_user.get_id():
            raise utils.EventError("%s: You can't send coins to yourself" %
                                   event["user"].nickname)

        send_amount = event["spec"][1]

        user_coins = self._get_user_coins(event["user"])
        redeem_amount = self._redeem_amount(event["server"])
        new_total_coins = self._get_user_coins(event["user"]) - send_amount

        if user_coins == DECIMAL_ZERO:
            raise utils.EventError("%s: You have no coins" %
                                   event["user"].nickname)
        elif new_total_coins < redeem_amount:
            raise utils.EventError(
                "%s: You cannot send an amount of money that puts"
                " you below %s coins" %
                (event["user"].nickname, self._coin_str(redeem_amount)))

        target_user_coins = self._get_user_coins(target_user)
        if target_user_coins == None:
            raise utils.EventError("%s: You can only send coins to users that "
                                   "have had coins before" %
                                   event["user"].nickname)

        self._move(event["user"], target_user, send_amount)

        event["stdout"].write(
            "%s sent %s coins to %s" %
            (event["user"].nickname, self._coin_str(send_amount),
             target_user.nickname))
Exemple #13
0
    def _mute(self, event):
        add = event["command"] == "mute"
        time, args = utils.parse.timed_args(event["args_split"], 1)

        target_name = args[0]
        if not event["server"].has_user(target_name):
            raise utils.EventError("No such user")

        target_user = event["server"].get_user(target_name)
        if not event["target"].has_user(target_user):
            raise utils.EventError("No such user")

        mode, mask = self._mute_method(event["server"], event["target"],
                                       target_user)
        if mode == None:
            raise utils.EventError("This network doesn't support mutes")

        if add and time:
            self.timers.add_persistent("unmute",
                                       time,
                                       server_id=event["server"].id,
                                       channel_name=event["target"].name,
                                       mode=mode,
                                       mask=mask)

        mode_modifier = "+" if add else "-"
        event["target"].send_mode("%s%s" % (mode_modifier, mode), [mask])
Exemple #14
0
    def fedi(self, event):
        account = None
        url = None

        strict_cw = True
        args_split = event["args_split"][:]
        for i, arg in enumerate(args_split):
            if arg == "!":
                strict_cw = False
                args_split.pop(i)
                break

        if not args_split:
            account = event["user"].get_setting("fediverse", None)
        elif utils.http.REGEX_URL.match(args_split[0]):
            url = args_split[0]
        elif not "@" in args_split[0]:
            target = args_split[0]
            if event["server"].has_user_id(target):
                target_user = event["server"].get_user(target)
                account = target_user.get_setting("fediverse", None)
        else:
            account = args_split[0]

        note = None
        type = "Create"
        if not url == None:
            note_page = ap_utils.activity_request(url)
            if not note_page.content_type == ap_utils.ACTIVITY_TYPE:
                raise utils.EventError("That's not a fediverse URL")

            note = note_page.data
            actor = ap_actor.Actor(note["attributedTo"])
            actor.load()
        else:
            username = None
            instance = None
            if account:
                username, instance = ap_utils.split_username(account)

            if not username or not instance:
                raise utils.EventError("Please provide @<user>@<instance>")
            actor, note = self._get_from_outbox(username, instance)
            type = note["type"]
            note = note["object"]

        cw, out, url = ap_utils.format_note(actor, note, type)
        shorturl = self.exports.get_one("shorturl")(event["server"],
                                                    url,
                                                    context=event["target"])

        if cw:
            if strict_cw:
                out = "CW: %s - %s" % (cw, shorturl)
            else:
                out = "(CW %s) %s - %s" % (cw, out, shorturl)
        else:
            out = "%s - %s" % (out, shorturl)
        event["stdout"].write(out)
Exemple #15
0
    def apikey(self, event):
        subcommand = event["args_split"][0].lower()
        alias = None
        alias_lower = None
        found = None
        if len(event["args_split"]) > 1:
            alias = event["args_split"][1]
            alias_lower = alias.lower()

        api_keys = {}
        for key, value in self.bot.find_settings(prefix="api-key-"):
            api_keys[key] = value
            if alias and value["comment"].lower() == alias_lower:
                alias = value["comment"]
                found = key

        if subcommand == "list":
            aliases = [v["comment"] for v in api_keys.values()]
            aliases.sort()
            event["stdout"].write("API keys: %s" % ", ".join(aliases))
        elif subcommand == "add":
            if not len(event["args_split"]) > 1:
                raise utils.EventError(
                    "Please provide an alias for the API key")

            if found == None:
                comment = event["args_split"][1]
                new_key = binascii.hexlify(os.urandom(16)).decode("ascii")
                self.bot.set_setting("api-key-%s" % new_key, {
                    "comment": comment,
                    "permissions": event["args_split"][2:]
                })
                event["stdout"].write("New API key '%s': %s" %
                                      (comment, new_key))
            else:
                event["stderr"].write("API key alias '%s' already exists" %
                                      alias)
        elif subcommand == "remove":
            if not len(event["args_split"]) > 1:
                raise utils.EventError("Please provide a key alias to remove")

            if not found == None:
                self.bot.del_setting(found)
                key = found.replace("api-key-", "", 1)
                event["stdout"].write("Deleted API key %s ('%s')" %
                                      (key, alias))
            else:
                event["stderr"].write("Count not find API key '%s'" % alias)
        elif subcommand == "info":
            if not len(event["args_split"]) > 1:
                raise utils.EventError("Please provide a key alias to remove")

            if not found == None:
                key = found.replace("api-key-", "", 1)
                event["stdout"].write(
                    "API key %s ('%s') can access: %s" %
                    (key, alias, " ".join(api_keys[found]["permissions"])))
            else:
                event["stderr"].write("Count not find API key '%s'" % alias)
Exemple #16
0
    def dns(self, event):
        """
        :help: Get all addresses for a given hostname (IPv4/IPv6)
        :usage: <hostname> [type [type ...]]
        :prefix: DNS
        """
        args = event["args_split"][:]
        nameserver = None
        if self.bot.get_setting("configurable-nameservers", True):
            nameserver = event["target"].get_setting(
                "dns-nameserver",
                event["server"].get_setting("dns-nameserver", None))
            for i, arg in enumerate(args):
                if arg[0] == "@":
                    nameserver = args.pop(i)[1:]
                    break

        hostname = args[0]

        record_types = args[1:]
        if not record_types:
            record_types = ["A?", "AAAA?"]

        if not nameserver == None:
            resolver = dns.resolver.Resolver(configure=False)
            resolver.nameservers = [nameserver]
        else:
            resolver = dns.resolver

        results = []

        for record_type in record_types:
            record_type_strip = record_type.rstrip("?").upper()
            try:
                query_result = resolver.query(hostname,
                                              record_type_strip,
                                              lifetime=4)
                query_results = [q.to_text() for q in query_result]
                results.append(
                    [record_type_strip, query_result.rrset.ttl, query_results])
            except dns.resolver.NXDOMAIN:
                raise utils.EventError("Domain not found")
            except dns.resolver.NoAnswer:
                if not record_type.endswith("?"):
                    raise utils.EventError(
                        "Domain does not have a '%s' record" %
                        record_type_strip)
            except dns.rdatatype.UnknownRdatatype:
                raise utils.EventError("Unknown record type '%s'" %
                                       record_type_strip)
            except dns.exception.DNSException:
                message = "Failed to get DNS records"
                self.log.warn(message, exc_info=True)
                raise utils.EventError(message)

        results_str = [
            "%s (TTL %s): %s" % (t, ttl, ", ".join(r)) for t, ttl, r in results
        ]
        event["stdout"].write("(%s) %s" % (hostname, " | ".join(results_str)))
Exemple #17
0
    def badge(self, event):
        now = self._round_up_day(utils.datetime.utcnow())

        if event["spec"][0] == "list":
            target = event["spec"][1] or event["user"]
            badges = self._get_badges(target)
            if not badges:
                raise utils.EventError("%s has no badges" % target.nickname)

            outs = []
            for name in sorted(badges.keys()):
                dt = utils.datetime.parse.iso8601(badges[name])
                days_since = self._days_since(now, dt)
                human = utils.datetime.format.date_human(dt)
                outs.append("%s on day %d (%s)" % (name, days_since, human))
            event["stdout"].write("badges for %s: %s" %
                                  (target.nickname, ", ".join(outs)))
        else:
            badges = self._get_badges(event["user"])
            mut_badges = badges.copy()
            name = event["spec"][1]

            if event["spec"][0] == "add":
                if event["spec"][2] in ["now", "today"]:
                    dt = utils.datetime.utcnow()
                else:
                    dt = event["spec"][2]

                exists = name in badges
                action = "updated" if exists else "added"

                mut_badges[name] = utils.datetime.format.iso8601(dt)
                human = utils.datetime.format.date_human(dt)
                event["stdout"].write(
                    "%s: %s badge %s (%s)" %
                    (event["user"].nickname, action, name, human))

            else:
                if not name in badges:
                    raise utils.EventError("%s: you don't have a '%s' badge" %
                                           (event["user"].nickname, name))

                dt = utils.datetime.parse.iso8601(badges[name])
                human = utils.datetime.format.date_human(dt)
                if event["spec"][0] == "remove":
                    del mut_badges[name]
                    event["stdout"].write(
                        "%s: removed badge '%s' (%s)" %
                        (event["user"].nickname, name, human))
                elif event["spec"][0] == "show":
                    days_since = self._days_since(now, dt)
                    event["stdout"].write(
                        "%s: your %s badge is on day %d (%s)" %
                        (event["user"].nickname, name, days_since, human))

            if not mut_badges == badges:
                self._set_badges(event["user"], mut_badges)
Exemple #18
0
 def _parse_time(self, args, min_args):
     if args[0][0] == "+":
         if len(args[1:]) < min_args:
             raise utils.EventError("Not enough arguments")
         time = utils.from_pretty_time(args[0][1:])
         if time == None:
             raise utils.EventError("Invalid timeframe")
         return time, args[1:]
     return None, args
Exemple #19
0
    def todo(self, event):
        user_todo = event["user"].get_setting("todo", [])
        if event["spec"][0] == "list":
            if not user_todo:
                raise utils.EventError("%s: you have no todo items" %
                                       event["user"].nickname)

            if not event["spec"][1] == None:
                index = event["spec"][1] - 1
                if not index in dict(enumerate(user_todo)):
                    raise utils.EventError(
                        "%s: unknown todo index %d" %
                        (event["user"].nickname, event["spec"][1]))
                event["stdout"].write(
                    "%s: (%d) %s" % (event["user"].nickname, event["spec"][1],
                                     user_todo[index]))
            else:
                outs = [
                    "(%d) %s" % (i + 1, s) for i, s in enumerate(user_todo)
                ]
                event["stdout"].write(
                    "%s: %s" % (event["user"].nickname, ", ".join(outs)))

        elif event["spec"][0] == "add":
            user_todo.append(event["spec"][1])
            event["user"].set_setting("todo", user_todo)
            event["stdout"].write("%s: todo item %d added" %
                                  (event["user"].nickname, len(user_todo)))

        elif event["spec"][0] == "remove":
            index = event["spec"][1] - 1
            if not index in dict(enumerate(user_todo)):
                raise utils.EventError("%s: unknown todo index %d" %
                                       event["user"].nickname)
            description = user_todo.pop(index)
            event["user"].set_setting("todo", user_todo)
            event["stdout"].write(
                "%s: todo item %d removed: %s" %
                (event["user"].nickname, event["spec"][1], description))

        elif event["spec"][0] == "move":
            todo_dict = dict(enumerate(user_todo))
            start_index, end_index = event["spec"][1] - 1, event["spec"][2] - 1
            for i, name in [[start_index, "start"], [end_index, "end"]]:
                if not i in todo_dict:
                    raise utils.EventError(
                        "%s: unknown todo %s index %d" %
                        (event["user"].nickname, name, i + 1))
            description = user_todo.pop(start_index)
            user_todo.insert(end_index, description)
            event["user"].set_setting("todo", user_todo)
            event["stdout"].write(
                "%s: todo item moved to %d: %s" %
                (event["user"].nickname, event["spec"][2], description))
Exemple #20
0
 def _catch(self, name, func):
     try:
         func()
     except ModuleManager.ModuleNotFoundException:
         raise utils.EventError("Module '%s' isn't loaded" % name)
     except ModuleManager.ModuleWarning as warning:
         raise utils.EventError("Module '%s' not loaded: %s" %
                                (name, str(warning)))
     except Exception as e:
         raise utils.EventError("Failed to reload module '%s': %s" %
                                (name, str(e)))
Exemple #21
0
    def _parse_ref(self, channel, ref):
        repo, _, number = ref.rpartition("#")
        if not repo:
            repo = channel.get_setting("github-default-repo", None)

        username, _, repository = repo.partition("/")

        if not username or not repository or not number:
            raise utils.EventError("Please provide username/repo#number")
        if not number.isdigit():
            raise utils.EventError("Issue number must be a number")
        return username, repository, number
Exemple #22
0
    def weather(self, event):
        """
        :help: Get current weather for you or someone else
        :usage: [nickname]
        :require_setting: location
        :require_setting_unless: 1
        """
        api_key = self.bot.config["openweathermap-api-key"]

        location = None
        if event["args"]:
            if len(event["args_split"]) == 1 and event["server"].has_user_id(
                    event["args_split"][0]):
                target_user = event["server"].get_user(event["args_split"][0])
                location = self._user_location(target_user)
                if location == None:
                    raise utils.EventError("%s doesn't have a location set" %
                                           target_user.nickname)
        else:
            location = self._user_location(event["user"])
            if location == None:
                raise utils.EventError("You don't have a location set")

        args = {"units": "metric", "APPID": api_key}

        if location:
            lat, lon = location
            args["lat"] = lat
            args["lon"] = lon
        else:
            args["q"] = event["args"]

        page = utils.http.request(URL_WEATHER, get_params=args, json=True)
        if page:
            if "weather" in page.data:
                location = "%s, %s" % (page.data["name"],
                                       page.data["sys"]["country"])
                celsius = "%dC" % page.data["main"]["temp"]
                fahrenheit = "%dF" % ((page.data["main"]["temp"] *
                                       (9 / 5)) + 32)
                description = page.data["weather"][0]["description"].title()
                humidity = "%s%%" % page.data["main"]["humidity"]
                wind_speed = "%sKM/h" % page.data["wind"]["speed"]

                event["stdout"].write(
                    "(%s) %s/%s | %s | Humidity: %s | Wind: %s" %
                    (location, celsius, fahrenheit, description, humidity,
                     wind_speed))
            else:
                event["stderr"].write(
                    "No weather information for this location")
        else:
            raise utils.EventsResultsError()
Exemple #23
0
    def dns(self, event):
        """
        :help: Get all addresses for a given hostname (IPv4/IPv6)
        :usage: <hostname> [type [type ...]]
        :prefix: DNS
        """
        hostname = event["args_split"][0]

        nameserver = event["server"].get_setting("dns-nameserver", None)

        record_types = []
        if len(event["args_split"]) > 1:
            for arg in event["args_split"][1:]:
                if arg.startswith("@"):
                    nameserver = arg[1:]
                else:
                    record_types.append(arg.upper())

        if not record_types:
            record_types = ["A?", "AAAA?"]

        if not nameserver == None:
            resolver = dns.resolver.Resolver(configure=False)
            resolver.nameservers = [nameserver]
        else:
            resolver = dns.resolver

        results = []

        for record_type in record_types:
            try:
                record_type_strip = record_type.rstrip("?")
                query_result = resolver.query(hostname, record_type_strip)
                query_results = [q.to_text() for q in query_result]
                results.append([record_type_strip, query_results])
            except dns.resolver.NXDOMAIN:
                raise utils.EventError("Domain not found")
            except dns.resolver.NoAnswer:
                if not record_type.endswith("?"):
                    raise utils.EventError(
                        "Domain does not have a '%s' record" %
                        record_type_strip)
            except dns.rdatatype.UnknownRdatatype:
                raise utils.EventError("Unknown record type '%s'" %
                                       record_type_strip)
            except dns.exception.DNSException:
                message = "Failed to get DNS records"
                self.log.warn(message, exc_info=True)
                raise utils.EventError(message)

        results_str = ["%s: %s" % (t, ", ".join(r)) for t, r in results]
        event["stdout"].write("(%s) %s" % (hostname, " | ".join(results_str)))
Exemple #24
0
    def access(self, event):
        """
        :help: Show/modify channel access for a user
        :usage: list <nickname>
        :usage: add <nickname> <permission1 permission2 ...>
        :usage: remove <nickname> <permission1 permission2 ...>
        :usage: set <nickname> <permission1 permission2 ...>
        :require_mode: high
        """
        subcommand = event["args_split"][0].lower()
        target = event["server"].get_user(event["args_split"][1])
        access = event["target"].get_user_setting(target.get_id(), "access",
                                                  [])

        if subcommand == "list":
            event["stdout"].write("Access for %s: %s" %
                                  (target.nickname, " ".join(access)))
        elif subcommand == "set":
            if not len(event["args_split"]) > 2:
                raise utils.EventError("Please provide a list of permissions")
            event["target"].set_user_setting(target.get_id(), "access",
                                             event["args_split"][2:])
        elif subcommand == "add":
            if not len(event["args_split"]) > 2:
                raise utils.EventError("Please provide a list of permissions")
            for acc in event["args_split"][2:]:
                if acc in access:
                    raise utils.EventError("%s already has '%s' permission" %
                                           (target.nickname, acc))
                access.append(acc)
            event["target"].set_user_setting(target.get_id(), "access", access)
            event["stdout"].write(
                "Added permission to %s: %s" %
                (target.nickname, " ".join(event["args_split"][2:])))
        elif subcommand == "remove":
            if not len(event["args_split"]) > 2:
                raise utils.EventError("Please provide a list of permissions")
            for acc in event["args_split"][2:]:
                if not acc in access:
                    raise utils.EventError("%s does not have '%s' permission" %
                                           (target.nickname, acc))
                access.remove(acc)
            if access:
                event["target"].set_user_setting(target.get_id(), "access",
                                                 access)
            else:
                event["target"].del_user_setting(target.get_id(), "access")
            event["stdout"].write(
                "Removed permission from %s: %s" %
                (target.nickname, " ".join(event["args_split"][2:])))
        else:
            event["stderr"].write("Unknown command '%s'" % subcommand)
Exemple #25
0
def _format_relay_summary_message(relays, search):
    if len(relays) > 1:
        raise utils.EventError(
            f"There were {len(relays)} relays found for "
            f"this query. {URL_RELAY_SEARCH_SEARCH}{search}")
    if not relays:
        raise utils.EventError("There were no relays found for this query.")
    details = relays[0]
    nickname = details["nickname"]
    consensus_weight = details["consensus_weight"]
    flags = " ".join(details["flags"])
    url = URL_RELAY_SEARCH_DETAILS + details["fingerprint"]
    return f"{nickname} - CW: {consensus_weight} [{flags}] {url}"
Exemple #26
0
    def send(self, event):
        """
        :help: Send coins to another user
        :usage: <nickname> <amount> [wallet_in:wallet_out]
        """
        target_user = event["server"].get_user(event["args_split"][0])

        wallet_in, _ = self._default_wallets(event["user"])
        _, wallet_out = self._default_wallets(target_user)
        if len(event["args_split"]) > 2:
            wallet_in, _ = self._parse_wallets(event["user"],
                                               event["args_split"][2])
            _, wallet_out = self._parse_wallets(target_user,
                                                event["args_split"][2])

        if event["user"].get_id() == target_user.get_id():
            raise utils.EventError("%s: You can't send coins to yourself" %
                                   event["user"].nickname)

        send_amount = event["args_split"][1]
        try:
            send_amount = self._parse_coins(send_amount, DECIMAL_ZERO)
        except CoinParseException as e:
            raise utils.EventError("%s: %s" % (event["user"].nickname, str(e)))

        user_coins = self._get_user_coins(event["user"], wallet_in)
        redeem_amount = self._redeem_amount(event["server"])
        new_total_coins = self._get_all_user_coins(event["user"]) - send_amount

        if user_coins == DECIMAL_ZERO:
            raise utils.EventError("%s: You have no coins" %
                                   event["user"].nickname)
        elif new_total_coins < redeem_amount:
            raise utils.EventError(
                "%s: You cannot send an amount of money that puts"
                " you below %s coins" %
                (event["user"].nickname, self._coin_str(redeem_amount)))

        target_user_coins = self._get_user_coins(target_user, wallet_out)
        if target_user_coins == None:
            raise utils.EventError("%s: You can only send coins to users that "
                                   "have had coins before" %
                                   event["user"].nickname)

        self._move(event["user"], target_user, send_amount, wallet_in,
                   wallet_out)

        event["stdout"].write(
            "%s sent %s coins to %s" %
            (event["user"].nickname, self._coin_str(send_amount),
             target_user.nickname))
Exemple #27
0
    def flip(self, event):
        """
        :help: Bet on a coin flip
        :usage: heads|tails <coin amount> [wallet_in:wallet_out]
        """
        wallet_in, wallet_out = self._default_wallets(event["user"])
        if len(event["args_split"]) > 2:
            wallet_in, wallet_out = self._parse_wallets(
                event["user"], event["args_split"][2])

        side_name = event["args_split"][0].lower()
        coin_bet = event["args_split"][1].lower()
        if coin_bet == "all":
            coin_bet = self._get_user_coins(event["user"], wallet_in)
            if coin_bet <= DECIMAL_ZERO:
                raise utils.EventError("%s: You have no coins to bet" %
                                       event["user"].nickname)
        else:
            try:
                coin_bet = self._parse_coins(coin_bet, DECIMAL_BET_MINIMUM)
            except CoinParseException as e:
                raise utils.EventError("%s: %s" %
                                       (event["user"].nickname, str(e)))

        if not side_name in SIDES:
            raise utils.EventError("%s: Please provide 'heads' or 'tails'" %
                                   event["user"].nickname)

        user_coins = self._get_user_coins(event["user"], wallet_in)
        if coin_bet > user_coins:
            raise utils.EventError("%s: You don't have enough coins to bet" %
                                   event["user"].nickname)

        chosen_side = random.SystemRandom().choice(list(SIDES.keys()))
        win = side_name == chosen_side

        coin_bet_str = self._coin_str(coin_bet)
        if win:
            new_total = self._give(event["server"], event["user"], coin_bet,
                                   wallet_out)
            event["stdout"].write(
                "%s flips %s and wins %s coin%s! (new total: %s)" %
                (event["user"].nickname, side_name, coin_bet_str,
                 "" if coin_bet == 1 else "s", self._coin_str(new_total)))
        else:
            self._take(event["server"], event["user"], coin_bet, wallet_in)
            event["stdout"].write(
                "%s flips %s and loses %s coin%s! (new total: %s)" %
                (event["user"].nickname, side_name, coin_bet_str,
                 "" if coin_bet == 1 else "s",
                 self._coin_str(user_coins - coin_bet)))
Exemple #28
0
    def mumble(self, event):
        server = None
        if not event["args"]:
            server = event["target"].get_setting(
                "mumble-server",
                event["server"].get_setting("mumble-server", None))
        elif event["args"]:
            server = event["args_split"][0]
        if not server:
            raise utils.EventError("Please provide a server")

        server, _, port = server.partition(":")
        if port:
            if not port.isdigit():
                raise utils.EventError("Port must be numeric")
            port = int(port)
        else:
            port = DEFAULT_PORT

        timestamp = datetime.datetime.utcnow()
        ping_packet = struct.pack(">iQ", 0, 123)
        s = socket.socket(type=socket.SOCK_DGRAM)
        s.settimeout(5)

        with utils.deadline():
            try:
                s.sendto(ping_packet, (server, port))
            except socket.gaierror as e:
                raise utils.EventError(str(e))

            try:
                pong_packet = s.recv(24)
            except socket.timeout:
                raise utils.EventError(
                    "Timed out waiting for response from %s:%d" %
                    (server, port))

        pong = struct.unpack(">bbbbQiii", pong_packet)

        version = ".".join(str(v) for v in pong[1:4])
        ping = (datetime.datetime.utcnow() - timestamp).total_seconds() * 1000
        users = pong[5]
        max_users = pong[6]
        bandwidth = pong[7] / 1000  # kbit/s

        event["stdout"].write(
            "%s:%d (v%s): %d/%d users, %.1fms ping, %dkbit/s bandwidth" %
            (server, port, version, users, max_users, ping, bandwidth))
Exemple #29
0
    def add_server(self, event):
        alias = event["spec"][0]
        hostname, sep, port = event["spec"][1].partition(":")
        tls = port.startswith("+")
        port = port.lstrip("+")

        if not hostname or not port or not port.isdigit():
            raise utils.EventError("Please provide <hostname>:[+]<port>")
        port = int(port)

        hostmask = IRCLine.parse_hostmask(event["spec"][2])
        nickname = hostmask.nickname
        username = hostmask.username or nickname
        realname = nickname
        bindhost = hostmask.hostname or None

        try:
            server_id = self.bot.database.servers.add(alias, hostname, port,
                                                      "", tls, bindhost,
                                                      nickname, username,
                                                      realname)
        except Exception as e:
            event["stderr"].write("Failed to add server")
            self.log.error("failed to add server \"%s\"", [alias],
                           exc_info=True)
            return
        event["stdout"].write("Added server '%s'" % alias)
Exemple #30
0
    def add_server(self, event):
        """
        :help: Add a new server
        :usage: <alias> <hostname>:[+]<port> <nickname>!<username>[@<bindhost>]
        :permission: addserver
        """
        alias = event["args_split"][0]
        hostname, sep, port = event["args_split"][1].partition(":")
        tls = port.startswith("+")
        port = port.lstrip("+")

        if not hostname or not port or not port.isdigit():
            raise utils.EventError("Please provide <hostname>:[+]<port>")
        port = int(port)

        hostmask = utils.irc.seperate_hostmask(event["args_split"][2])
        nickname = hostmask.nickname
        username = hostmask.username or nickname
        realname = nickname
        bindhost = hostmask.hostname or None

        try:
            server_id = self.bot.database.servers.add(alias, hostname, port,
                                                      "", tls, bindhost,
                                                      nickname, username,
                                                      realname)
        except Exception as e:
            event["stderr"].write("Failed to add server")
            self.log.error("failed to add server \"%s\"", [alias],
                           exc_info=True)
            return
        event["stdout"].write("Added server '%s'" % alias)