Example #1
0
	async def ensure_client(self):
		if self.client is None:
			self.client = mc.Client(ADRESS, PASS)
			try:
				await self.client.setup()
			except:
				self.client = None
				raise RCONUnavailableException("Could not reach the Minecraft server")
Example #2
0
async def get_client(*args, **kwargs):
    client = rc.Client(*args, **kwargs)
    try:
        yield client
    except rc.ConnectionFailedError:
        print("Connection failed", file=sys.stderr)
    except rc.InvalidAuthError:
        print("Invalid password", file=sys.stderr)
    except EOFError:
        pass
    finally:
        await client.close()
Example #3
0
    async def rcon_command(self, ctx, *, cmd):
        dm_check = (lambda m: ctx.author.id == m.author.id and ctx.author.dm_channel.id == m.channel.id)
        db_guild = await self.db.fetch_guild(ctx.guild.id)

        if db_guild['mcserver'] is None:
            await self.bot.send(ctx, ctx.l.minecraft.rcon.stupid_1)
            return

        db_user_rcon = await self.db.fetch_user_rcon(ctx.author.id, db_guild['mcserver'])

        if db_user_rcon is None:
            try:
                await self.bot.send(ctx.author, ctx.l.minecraft.rcon.port)
            except Exception:
                await self.bot.send(ctx, ctx.l.minecraft.rcon.dm_error)
                return

            try:
                port_msg = await self.bot.wait_for('message', check=dm_check, timeout=60)
            except asyncio.TimeoutError:
                try:
                    await self.bot.send(ctx.author, ctx.l.minecraft.rcon.msg_timeout)
                except Exception:
                    pass
                return

            try:
                rcon_port = int(port_msg.content)

                if 0 > rcon_port > 65535:
                    rcon_port = 25575
            except Exception:
                rcon_port = 25575

            try:
                await self.bot.send(ctx.author, ctx.l.minecraft.rcon.passw)
            except Exception:
                await self.bot.send(ctx, ctx.l.minecraft.rcon.dm_error)
                return

            try:
                auth_msg = await self.bot.wait_for('message', check=dm_check, timeout=60)
            except asyncio.TimeoutError:
                try:
                    await self.bot.send(ctx.author, ctx.l.minecraft.rcon.msg_timeout)
                except Exception:
                    pass
                return

            password = auth_msg.content
        else:
            rcon_port = db_user_rcon['rcon_port']
            password = Fernet(self.k.fernet).decrypt(db_user_rcon['password'].encode('utf-8')).decode('utf-8')  # decrypt to plaintext

        await ctx.trigger_typing()

        try:
            rcon_con = self.d.rcon_cache.get((ctx.author.id, db_guild['mcserver']))

            if rcon_con is None:
                rcon_con = rcon.Client((db_guild['mcserver'].split(':')[0] + f':{rcon_port}'), password, 2.5, loop=self.bot.loop)
                self.d.rcon_cache[(ctx.author.id, db_guild['mcserver'])] = (rcon_con, arrow.utcnow())
            else:
                rcon_con = rcon_con[0]
                self.d.rcon_cache[(ctx.author.id, db_guild['mcserver'])] = (rcon_con, arrow.utcnow())

            await rcon_con.setup()
        except Exception as e:
            if isinstance(e, rcon.errors.InvalidAuthError):
                await self.bot.send(ctx, ctx.l.minecraft.rcon.stupid_2)
            else:
                await self.bot.send(ctx, ctx.l.minecraft.rcon.err_con)

            await self.db.delete_user_rcon(ctx.author.id, db_guild['mcserver'])
            await rcon_con.close()
            self.d.rcon_cache.pop((ctx.author.id, db_guild['mcserver']), None)

            return

        if db_user_rcon is None:
            encrypted_password = Fernet(self.k.fernet).encrypt(password.encode('utf-8')).decode('utf-8')
            await self.db.add_user_rcon(ctx.author.id, db_guild['mcserver'], rcon_port, encrypted_password)

        try:
            resp = await rcon_con.send_cmd(cmd[:1445])
        except Exception:
            await self.bot.send(ctx, ctx.l.minecraft.rcon.err_cmd)
            await rcon_con.close()
            self.d.rcon_cache.pop((ctx.author.id, db_guild['mcserver']), None)

            return

        resp_text = ''
        for i in range(0, len(resp[0])):
            if resp[0][i] != '§' and (i == 0 or resp[0][i-1] != '§'):
                resp_text += resp[0][i]

        await ctx.send('```\uFEFF{}```'.format(resp_text.replace('\\n', '\n')[:2000-7]))
Example #4
0
    async def rcon_command(self, ctx, *, cmd):
        author_check = (lambda m: ctx.author.id == m.author.id and ctx.author.dm_channel.id == m.channel.id)
        db_guild = await self.db.fetch_guild(ctx.guild.id)

        if db_guild['mcserver'] is None:
            await self.bot.send(ctx, 'You have to set a Minecraft server for this guild via the `/config mcserver` command first.')
            return

        key = (ctx.guild.id, ctx.author.id, db_guild['mcserver'])
        cached = self.d.rcon_connection_cache.get(key)

        if cached is None:
            try:
                await self.bot.send(ctx.author, 'Type in the remote console password (rcon.password in the server.properties file) here. This password can be stored for up to 10 minutes past the last rcon command.')
            except Exception:
                await self.bot.send(ctx, 'I need to be able to DM you, either something went wrong or I don\'t have the permissions to.')
                return

            try:
                auth_msg = await self.bot.wait_for('message', check=author_check, timeout=60)
            except asyncio.TimeoutError:
                await self.bot.send(ctx.author, 'I\'ve stopped waiting for a response.')
                return

            if db_guild['mcserver_rcon'] is None:
                try:
                    await self.bot.send(ctx.author, 'Now type in the RCON port (rcon.port in the server.properties file)')
                except Exception:
                    await self.bot.send(ctx, 'I need to be able to DM you, either something went wrong or I don\'t have the permissions to.')
                    return

                try:
                    port_msg = await self.bot.wait_for('message', check=author_check, timeout=60)
                except asyncio.TimeoutError:
                    await self.bot.send(ctx.author, 'I\'ve stopped waiting for a response.')
                    return

                port = 25575
                try:
                    port = int(port_msg.content)
                except Exception:
                    port = 25575

                if 0 > port > 65535:
                    port = 25575

                await self.db.set_guild_attr(ctx.guild.id, 'mcserver_rcon', port)  # update value in db
            else:
                port = db_guild['mcserver_rcon']

            try:
                s = db_guild['mcserver'].split(':')[0]+f':{port}'
                self.d.rcon_connection_cache[key] = (rcon.Client(s, auth_msg.content, 2.5, loop=self.bot.loop), arrow.utcnow())
                await self.d.rcon_connection_cache[key][0].setup()
            except rcon.Errors.ConnectionFailedError:
                await self.bot.send(ctx, 'Connection to the server failed, is RCON enabled?')
                await self.close_rcon_con(key, ctx.guild.id)
                return
            except rcon.Errors.InvalidAuthError:
                await self.bot.send(ctx.author, 'The provided RCON password/authentication is invalid')
                await self.close_rcon_con(key, ctx.guild.id)
                return

            rcon_con = self.d.rcon_connection_cache[key][0]
        else:
            rcon_con = cached[0]
            self.d.rcon_connection_cache[key] = (rcon_con, arrow.utcnow())  # update time

        try:
            resp = await rcon_con.send_cmd(cmd[:1446])  # shorten to avoid unecessary timeouts
        except asyncio.TimeoutError:
            await self.bot.send(ctx, 'A timeout occurred while sending that command to the server')
            await self.close_rcon_con(key, ctx.guild.id)
        except Exception:
            await self.bot.send(ctx, f'For some reason, an error ocurred while sending that command to the server')
            await self.close_rcon_con(key, ctx.guild.id)
        else:
            resp_text = ''
            for i in range(0, len(resp[0])):
                if resp[0][i] != '§' and (i == 0 or resp[0][i-1] != '§'):
                    resp_text += resp[0][i]

            await ctx.send('```{}```'.format(resp_text.replace('\\n', '\n')))
Example #5
0
    async def rcon_command(self, ctx, *, cmd):
        db_guild = await self.db.fetch_guild(ctx.guild.id)

        if db_guild["mc_server"] is None:
            await self.bot.reply_embed(ctx, ctx.l.minecraft.rcon.stupid_1.format(ctx.prefix))
            return

        db_user_rcon = await self.db.fetch_user_rcon(ctx.author.id, db_guild["mc_server"])

        if db_user_rcon is None:
            try:
                await self.bot.send_embed(ctx.author, ctx.l.minecraft.rcon.port)
            except Exception:
                await self.bot.reply_embed(ctx, ctx.l.minecraft.rcon.dm_error, True)
                return

            try:
                if 0 in self.bot.shard_ids:
                    port_msg = await self.bot.wait_for("message", check=dm_check(ctx), timeout=60)
                else:
                    port_msg = await asyncio.wait_for(
                        self.ipc.request({"type": "dm-message-request", "user_id": ctx.author.id}), 60
                    )
            except asyncio.TimeoutError:
                try:
                    await self.bot.send_embed(ctx.author, ctx.l.minecraft.rcon.msg_timeout)
                except (discord.Forbidden, discord.HTTPException):
                    pass

                return

            try:
                rcon_port = int(port_msg.content)

                if 0 > rcon_port > 65535:
                    rcon_port = 25575
            except (ValueError, TypeError):
                rcon_port = 25575

            try:
                await self.bot.send_embed(ctx.author, ctx.l.minecraft.rcon.passw)
            except Exception:
                await self.bot.reply_embed(ctx, ctx.l.minecraft.rcon.dm_error, True)
                return

            try:
                if 0 in self.bot.shard_ids:
                    auth_msg = await self.bot.wait_for("message", check=dm_check(ctx), timeout=60)
                else:
                    auth_msg = await asyncio.wait_for(
                        self.ipc.request({"type": "dm-message-request", "user_id": ctx.author.id}), 60
                    )
            except asyncio.TimeoutError:
                try:
                    await self.bot.send_embed(ctx.author, ctx.l.minecraft.rcon.msg_timeout)
                except (discord.Forbidden, discord.HTTPException):
                    pass

                return

            password = auth_msg.content
        else:
            rcon_port = db_user_rcon["rcon_port"]
            password = self.fernet.decrypt(db_user_rcon["password"].encode("utf-8")).decode("utf-8")  # decrypt to plaintext

        await ctx.trigger_typing()

        try:
            rcon_con = self.bot.rcon_cache.get((ctx.author.id, db_guild["mc_server"]))

            if rcon_con is None:
                rcon_con = rcon.Client(db_guild["mc_server"].split(":")[0], rcon_port, password)
                self.bot.rcon_cache[(ctx.author.id, db_guild["mc_server"])] = (rcon_con, arrow.utcnow())
            else:
                rcon_con = rcon_con[0]
                self.bot.rcon_cache[(ctx.author.id, db_guild["mc_server"])] = (rcon_con, arrow.utcnow())

            await rcon_con.connect(timeout=2.5)
        except Exception as e:
            if isinstance(e, rcon.IncorrectPasswordError):
                await self.bot.reply_embed(ctx, ctx.l.minecraft.rcon.stupid_2)
            else:
                await self.bot.reply_embed(ctx, ctx.l.minecraft.rcon.err_con)

            await self.db.delete_user_rcon(ctx.author.id, db_guild["mc_server"])
            await rcon_con.close()
            self.bot.rcon_cache.pop((ctx.author.id, db_guild["mc_server"]), None)

            return

        if db_user_rcon is None:
            encrypted_password = Fernet(self.k.fernet).encrypt(password.encode("utf-8")).decode("utf-8")
            await self.db.add_user_rcon(ctx.author.id, db_guild["mc_server"], rcon_port, encrypted_password)

        try:
            resp = await rcon_con.send_cmd(cmd[:1445])
        except Exception:
            await self.bot.reply_embed(ctx, ctx.l.minecraft.rcon.err_cmd)
            await rcon_con.close()
            self.bot.rcon_cache.pop((ctx.author.id, db_guild["mc_server"]), None)

            return

        resp_text = ""
        for i in range(0, len(resp[0])):
            if resp[0][i] != "§" and (i == 0 or resp[0][i - 1] != "§"):
                resp_text += resp[0][i]

        await ctx.reply("```\uFEFF{}```".format(resp_text.replace("\\n", "\n")[: 2000 - 7]), mention_author=False)