Example #1
0
    private async Task <Channel?> FindLogChannel(ulong guildId, ulong channelId)
    {
        // TODO: fetch it directly on cache miss?
        if (await _cache.TryGetChannel(channelId) is Channel channel)
        {
            return(channel);
        }

        if (await _rest.GetChannelOrNull(channelId) is Channel restChannel)
        {
            return(restChannel);
        }

        // Channel doesn't exist or we don't have permission to access it, let's remove it from the database too
        _logger.Warning(
            "Attempted to fetch missing log channel {LogChannel} for guild {Guild}, removing from database",
            channelId, guildId
            );
        await using var conn = await _db.Obtain();

        await conn.ExecuteAsync("update servers set log_channel = null where id = @Guild",
                                new { Guild = guildId });

        return(null);
    }
Example #2
0
    public async Task MessageProxyCheck(Context ctx)
    {
        if (!ctx.HasNext() && ctx.Message.MessageReference == null)
        {
            throw new PKSyntaxError("You need to specify a message.");
        }

        var failedToGetMessage =
            "Could not find a valid message to check, was not able to fetch the message, or the message was not sent by you.";

        var(messageId, channelId) = ctx.MatchMessage(false);
        if (messageId == null || channelId == null)
        {
            throw new PKError(failedToGetMessage);
        }

        var proxiedMsg = await ctx.Database.Execute(conn => ctx.Repository.GetMessage(conn, messageId.Value));

        if (proxiedMsg != null)
        {
            await ctx.Reply($"{Emojis.Success} This message was proxied successfully.");

            return;
        }

        // get the message info
        var msg = await _rest.GetMessageOrNull(channelId.Value, messageId.Value);

        if (msg == null)
        {
            throw new PKError(failedToGetMessage);
        }

        // if user is fetching a message in a different channel sent by someone else, throw a generic error message
        if (msg == null || msg.Author.Id != ctx.Author.Id && msg.ChannelId != ctx.Channel.Id)
        {
            throw new PKError(failedToGetMessage);
        }

        if ((_botConfig.Prefixes ?? BotConfig.DefaultPrefixes).Any(p => msg.Content.StartsWith(p)))
        {
            await ctx.Reply("This message starts with the bot's prefix, and was parsed as a command.");

            return;
        }
        if (msg.Author.Bot)
        {
            throw new PKError("You cannot check messages sent by a bot.");
        }
        if (msg.WebhookId != null)
        {
            throw new PKError("You cannot check messages sent by a webhook.");
        }
        if (msg.Author.Id != ctx.Author.Id && !ctx.CheckBotAdmin())
        {
            throw new PKError("You can only check your own messages.");
        }

        // get the channel info
        var channel = await _rest.GetChannelOrNull(channelId.Value);

        if (channel == null)
        {
            throw new PKError("Unable to get the channel associated with this message.");
        }

        // using channel.GuildId here since _rest.GetMessage() doesn't return the GuildId
        var context = await ctx.Repository.GetMessageContext(msg.Author.Id, channel.GuildId.Value, msg.ChannelId);

        var members = (await ctx.Repository.GetProxyMembers(msg.Author.Id, channel.GuildId.Value)).ToList();

        // for now this is just server
        var autoproxySettings = await ctx.Repository.GetAutoproxySettings(ctx.System.Id, channel.GuildId.Value, null);

        // todo: match unlatch

        // Run everything through the checks, catch the ProxyCheckFailedException, and reply with the error message.
        try
        {
            _proxy.ShouldProxy(channel, msg, context);
            _matcher.TryMatch(context, autoproxySettings, members, out var match, msg.Content, msg.Attachments.Length > 0,
                              context.AllowAutoproxy);

            await ctx.Reply("I'm not sure why this message was not proxied, sorry.");
        }
        catch (ProxyService.ProxyChecksFailedException e)
        {
            await ctx.Reply($"{e.Message}");
        }
    }
Example #3
0
    private async Task <FullMessage> GetMessageToEdit(Context ctx, Duration timeout, bool isReproxy)
    {
        var editType       = isReproxy ? "reproxy" : "edit";
        var editTypeAction = isReproxy ? "reproxied" : "edited";

        // todo: is it correct to get a connection here?
        await using var conn = await ctx.Database.Obtain();

        FullMessage?msg = null;

        var(referencedMessage, _) = ctx.MatchMessage(false);
        if (referencedMessage != null)
        {
            msg = await ctx.Repository.GetMessage(conn, referencedMessage.Value);

            if (msg == null)
            {
                throw new PKError("This is not a message proxied by PluralKit.");
            }
        }

        if (msg == null)
        {
            if (ctx.Guild == null)
            {
                throw new PKSyntaxError($"You must use a message link to {editType} messages in DMs.");
            }

            var recent = await FindRecentMessage(ctx, timeout);

            if (recent == null)
            {
                throw new PKSyntaxError($"Could not find a recent message to {editType}.");
            }

            msg = await ctx.Repository.GetMessage(conn, recent.Mid);

            if (msg == null)
            {
                throw new PKSyntaxError($"Could not find a recent message to {editType}.");
            }
        }

        if (msg.Message.Channel != ctx.Channel.Id)
        {
            var error =
                "The channel where the message was sent does not exist anymore, or you are missing permissions to access it.";

            var channel = await _rest.GetChannelOrNull(msg.Message.Channel);

            if (channel == null)
            {
                throw new PKError(error);
            }

            if (!await ctx.CheckPermissionsInGuildChannel(channel,
                                                          PermissionSet.ViewChannel | PermissionSet.SendMessages
                                                          ))
            {
                throw new PKError(error);
            }
        }

        var msgTimestamp = DiscordUtils.SnowflakeToInstant(msg.Message.Mid);

        if (isReproxy && SystemClock.Instance.GetCurrentInstant() - msgTimestamp > timeout)
        {
            throw new PKError($"The message is too old to be {editTypeAction}.");
        }

        return(msg);
    }
Example #4
0
    private async Task <FullMessage> GetMessageToEdit(Context ctx)
    {
        // todo: is it correct to get a connection here?
        await using var conn = await ctx.Database.Obtain();

        FullMessage?msg = null;

        var(referencedMessage, _) = ctx.MatchMessage(false);
        if (referencedMessage != null)
        {
            msg = await ctx.Repository.GetMessage(conn, referencedMessage.Value);

            if (msg == null)
            {
                throw new PKError("This is not a message proxied by PluralKit.");
            }
        }

        if (msg == null)
        {
            if (ctx.Guild == null)
            {
                throw new PKSyntaxError("You must use a message link to edit messages in DMs.");
            }

            var recent = await FindRecentMessage(ctx);

            if (recent == null)
            {
                throw new PKSyntaxError("Could not find a recent message to edit.");
            }

            msg = await ctx.Repository.GetMessage(conn, recent.Mid);

            if (msg == null)
            {
                throw new PKSyntaxError("Could not find a recent message to edit.");
            }
        }

        if (msg.Message.Channel != ctx.Channel.Id)
        {
            var error =
                "The channel where the message was sent does not exist anymore, or you are missing permissions to access it.";

            var channel = await _rest.GetChannelOrNull(msg.Message.Channel);

            if (channel == null)
            {
                throw new PKError(error);
            }

            if (!await ctx.CheckPermissionsInGuildChannel(channel,
                                                          PermissionSet.ViewChannel | PermissionSet.SendMessages
                                                          ))
            {
                throw new PKError(error);
            }
        }

        return(msg);
    }