async def _update_about(self, about: str, sender: Optional['p.Puppet'] = None,
                            save: bool = False) -> bool:
        if self.about == about:
            return False

        self.about = about
        await self._try_set_state(sender, EventType.ROOM_TOPIC,
                                  RoomTopicStateEventContent(topic=self.about))
        if save:
            self.save()
        return True
Beispiel #2
0
 def set_room_topic(self, room_id: RoomID, topic: str,
                    **kwargs) -> Awaitable[EventID]:
     return self.send_state_event(room_id, EventType.ROOM_TOPIC,
                                  RoomTopicStateEventContent(topic=topic),
                                  **kwargs)
Beispiel #3
0
    async def urandom(self, evt: MessageEvent, args: Args) -> None:
        evt.disable_reply = "reply" not in args and "replay" not in args
        if "help" in args:
            await evt.reply(helps.get(args["help"], HELP_UNKNOWN))
            return
        try:
            length = int(args["len"])
        except (KeyError, ValueError):
            length = DEFAULT_LENGTH
        if length > MAX_LENGTH:
            await evt.reply("Too high length")
            return
        elif length < 0:
            await evt.reply("Invalid length")
            return

        rand = sys_rand
        if "seed" in args:
            if args["seed"] == True:
                rand = random
            else:
                try:
                    rand = random.Random(int(args["seed"]))
                except ValueError:
                    await evt.reply("Invalid seed")
                    return

        if "alphabet" in args:
            alphabet = args["alphabet"]
            if "space" in args:
                alphabet = alphabet.replace(args["space"], " ")
            if "permutation" in args or "shuffle" in args:
                data = list(alphabet)
                rand.shuffle(data)
                randomness = "".join(data)
            else:
                randomness = "".join(rand.choices(alphabet, k=length or DEFAULT_LENGTH))
        elif "urange" in args:
            ranges: List[Tuple[int, int]] = []
            weights: List[int] = []
            try:
                lim = range(0x110000)
                for urange in args["urange"].split(","):
                    start, end = parse_urange(urange.strip())
                    if start == 0 or end == 0:
                        await evt.reply(
                            'Exception in thread "main" java.lang.NullPointerException  \n'
                            '    at Urandom.handle_command(Urandom.java:216)')
                        return
                    if start not in lim:
                        raise ValueError("range start not in range(0x110000)")
                    elif end not in lim:
                        raise ValueError("range end not in range(0x110000)")
                    ranges.append((start, end + 1))
                    weights.append(end - start + 1)
            except (KeyError, ValueError):
                await evt.reply("Invalid unicode range")
                self.log.exception("Invalid unicode range")
                return
            randomness = "".join(chr(rand.randrange(start, end))
                                 for start, end
                                 in rand.choices(ranges, weights, k=length or DEFAULT_LENGTH))
        else:
            urandom = (sys_urandom if rand == sys_rand
                       else lambda n: bytes(rand.randint(0, 255) for i in range(n)))
            randomness = urandom(length or DEFAULT_LENGTH)

            base = args.get("base", DEFAULT_BASE)
            if base == "raw":
                randomness = str(randomness)
            elif base == "16" or base == "hex":
                randomness = b16encode(randomness).decode("utf-8")
            elif base == "32":
                randomness = b32encode(randomness).decode("utf-8").rstrip("=")
            elif base == "64":
                randomness = b64encode(randomness).decode("utf-8").rstrip("=")
            elif base == "85":
                randomness = b85encode(randomness).decode("utf-8")
            elif base == "65536":
                randomness = b65536encode(randomness)
            else:
                await evt.reply("Unknown base")

        if "topic" in args:
            await self.client.send_state_event(evt.room_id, EventType.ROOM_TOPIC,
                                               RoomTopicStateEventContent(topic=randomness))
        else:
            await evt.reply(TextMessageEventContent(body=randomness, msgtype=MessageType.NOTICE))
Beispiel #4
0
    async def _exec(self, evt: MessageEvent, **kwargs: Any) -> None:
        if not self._exec_ok(evt):
            self.log.debug(f"Ignoring exec {evt.event_id} from {evt.sender} in {evt.room_id}")
            return

        http = self.client.api.session
        old_name = await self.get_cached_name(evt.room_id)
        old_topic = await self.get_cached_topic(evt.room_id)
        devices = {}
        if old_name:
            devices["name"] = old_name
        if old_topic:
            devices["topic"] = old_topic
        reply_to_id = evt.content.get_reply_to()
        if reply_to_id:
            reply_to_evt = await self.client.get_event(evt.room_id, reply_to_id)
            if reply_to_evt.content.msgtype.is_media:
                url = self.client.api.get_download_url(reply_to_evt.content.url)
                max_size = 8 * 1024 * 1024
                async with self.client.api.session.head(url) as response:
                    if int(response.headers["Content-Length"]) > max_size:
                        await evt.reply("File too large")
                        return
                file = await self.client.download_media(reply_to_evt.content.url)
                if len(file) > max_size:
                    await evt.reply("File too large")
                    return
                devices["reply"] = base64.b64encode(file).decode("utf-8")
            else:
                devices["reply"] = reply_to_evt.content.body

        localpart, server = self.client.parse_user_id(evt.sender)
        resp = await http.post(self.config["server"], data=json.dumps({
            **kwargs,
            "user": evt.sender,
            "home": re.sub(r"//+", "/", f"/{server}/{localpart}"),
            "devices": devices,
        }))
        if resp.status == 502:
            await evt.respond("maush is currently down")
            return
        data = await resp.json()
        self.log.debug("Execution response for %s: %s", evt.sender, data)
        if not data["ok"]:
            self.log.error("Exec failed: %s", data["error"])
            await evt.respond(data["error"])
            return

        dur = round(data["duration"] / 1_000_000, 1)
        ret = data["return"]
        if ret != 0:
            resp = f"Exited with code {ret} in {dur} ms. "
        else:
            resp = f"Completed in {dur} ms. "
        if data["timeout"]:
            resp += "**Execution timed out**. "
        if data["stdout"]:
            stdout = data["stdout"].strip().replace("```", r"\```")
            if len(stdout) >= 8190:
                stdout = stdout[:8192] + "[…]"
            resp += f"**stdout:**\n```\n{stdout}\n```\n"
        if data["stderr"]:
            stderr = data["stderr"].strip().replace("```", r"\```")
            if len(stderr) >= 8190:
                stderr = stderr[:8192] + "[…]"
            resp += f"**stderr:**\n```\n{stderr}\n```\n"

        resp = resp.strip()
        if resp:
            await evt.respond(resp)

        new_dev = data["devices"]
        new_name = new_dev.get("name") or ""
        if new_name:
            new_name = new_name.strip()
        new_topic = new_dev.get("topic") or ""
        if new_topic:
            new_topic = new_topic.strip()
        if new_name != old_name:
            await self.client.send_state_event(evt.room_id, EventType.ROOM_NAME,
                                               RoomNameStateEventContent(name=new_name))
            self.name_cache[evt.room_id] = new_name
        if new_topic != old_topic:
            await self.client.send_state_event(evt.room_id, EventType.ROOM_TOPIC,
                                               RoomTopicStateEventContent(topic=new_topic))
            self.topic_cache[evt.room_id] = new_topic