Example #1
0
    private async ValueTask HandleQueryReaction(MessageReactionAddEvent evt, FullMessage msg)
    {
        var guild = await _cache.GetGuild(evt.GuildId !.Value);

        // Try to DM the user info about the message
        try
        {
            var dm = await _dmCache.GetOrCreateDmChannel(evt.UserId);

            var embeds = new List <Embed>();

            if (msg.Member != null)
            {
                embeds.Add(await _embeds.CreateMemberEmbed(
                               msg.System,
                               msg.Member,
                               guild,
                               LookupContext.ByNonOwner,
                               DateTimeZone.Utc
                               ));
            }

            embeds.Add(await _embeds.CreateMessageInfoEmbed(msg, true));

            await _rest.CreateMessage(dm, new MessageRequest { Embeds = embeds.ToArray() });
        }
        catch (ForbiddenException) { } // No permissions to DM, can't check for this :(

        await TryRemoveOriginalReaction(evt);
    }
Example #2
0
    private async ValueTask <bool> TryHandleCommand(int shardId, MessageCreateEvent evt, Guild?guild,
                                                    Channel channel, MessageContext ctx)
    {
        var content = evt.Content;

        if (content == null)
        {
            return(false);
        }

        var ourUserId = await _cache.GetOwnUser();

        // Check for command prefix
        if (!HasCommandPrefix(content, ourUserId, out var cmdStart) || cmdStart == content.Length)
        {
            return(false);
        }

        if (ctx.IsDeleting)
        {
            await _rest.CreateMessage(evt.ChannelId, new()
            {
                Content = $"{Emojis.Error} Your system is currently being deleted."
                          + " Due to database issues, it is not possible to use commands while a system is being deleted. Please wait a few minutes and try again.",
                MessageReference = new(guild?.Id, channel.Id, evt.Id)
            });

            return(true);
        }

        // Trim leading whitespace from command without actually modifying the string
        // This just moves the argPos pointer by however much whitespace is at the start of the post-argPos string
        var trimStartLengthDiff =
            content.Substring(cmdStart).Length - content.Substring(cmdStart).TrimStart().Length;

        cmdStart += trimStartLengthDiff;

        try
        {
            var system = ctx.SystemId != null ? await _repo.GetSystem(ctx.SystemId.Value) : null;

            var config = ctx.SystemId != null ? await _repo.GetSystemConfig(ctx.SystemId.Value) : null;

            await _tree.ExecuteCommand(new Context(_services, shardId, guild, channel, evt, cmdStart, system, config, ctx));
        }
        catch (PKError)
        {
            // Only permission errors will ever bubble this far and be caught here instead of Context.Execute
            // so we just catch and ignore these. TODO: this may need to change.
        }

        return(true);
    }
Example #3
0
    public async Task <Message> Reply(string text = null, Embed embed = null, AllowedMentions?mentions = null)
    {
        var botPerms = await BotPermissions;

        if (!botPerms.HasFlag(PermissionSet.SendMessages))
        {
            // Will be "swallowed" during the error handler anyway, this message is never shown.
            throw new PKError("PluralKit does not have permission to send messages in this channel.");
        }

        if (embed != null && !botPerms.HasFlag(PermissionSet.EmbedLinks))
        {
            throw new PKError("PluralKit does not have permission to send embeds in this channel. Please ensure I have the **Embed Links** permission enabled.");
        }

        var msg = await Rest.CreateMessage(Channel.Id, new MessageRequest
        {
            Content = text,
            Embeds  = embed != null ? new[] { embed } : null,
            // Default to an empty allowed mentions object instead of null (which means no mentions allowed)
            AllowedMentions = mentions ?? new AllowedMentions()
        });

        if (embed != null)
        {
            // Sensitive information that might want to be deleted by :x: reaction is typically in an embed format (member cards, for example)
            // This may need to be changed at some point but works well enough for now
            await _commandMessageService.RegisterMessage(msg.Id, msg.ChannelId, Author.Id);
        }

        return(msg);
    }
Example #4
0
    private async ValueTask <bool> TryHandleProxy(MessageCreateEvent evt, Guild guild, Channel channel,
                                                  MessageContext ctx)
    {
        var botPermissions = await _cache.PermissionsIn(channel.Id);

        try
        {
            return(await _proxy.HandleIncomingMessage(evt, ctx, guild, channel, ctx.AllowAutoproxy,
                                                      botPermissions));
        }

        // Catch any failed proxy checks so they get ignored in the global error handler
        catch (ProxyService.ProxyChecksFailedException) { }

        catch (PKError e)
        {
            // User-facing errors, print to the channel properly formatted
            if (botPermissions.HasFlag(PermissionSet.SendMessages))
            {
                await _rest.CreateMessage(evt.ChannelId,
                                          new MessageRequest { Content = $"{Emojis.Error} {e.Message}" });
            }
        }

        return(false);
    }
        public async ValueTask LogMessage(MessageContext ctx, ProxyMatch proxy, Message trigger, ulong hookMessage)
        {
            var logChannel = await GetAndCheckLogChannel(ctx, trigger);

            if (logChannel == null)
            {
                return;
            }

            var triggerChannel = _cache.GetChannel(trigger.ChannelId);

            // Send embed!
            await using var conn = await _db.Obtain();

            var embed = _embed.CreateLoggedMessageEmbed(await _repo.GetSystem(conn, ctx.SystemId.Value),
                                                        await _repo.GetMember(conn, proxy.Member.Id), hookMessage, trigger.Id, trigger.Author, proxy.Content,
                                                        triggerChannel);
            var url = $"https://discord.com/channels/{trigger.GuildId}/{trigger.ChannelId}/{hookMessage}";
            await _rest.CreateMessage(logChannel.Id, new() { Content = url, Embed = embed });
        }
Example #6
0
        private async ValueTask HandleQueryReaction(MessageReactionAddEvent evt, FullMessage msg)
        {
            var guild = _cache.GetGuild(evt.GuildId !.Value);

            // Try to DM the user info about the message
            try
            {
                var dm = await _cache.GetOrCreateDmChannel(_rest, evt.UserId);

                await _rest.CreateMessage(dm.Id, new MessageRequest
                {
                    Embed = await _embeds.CreateMemberEmbed(msg.System, msg.Member, guild, LookupContext.ByNonOwner)
                });

                await _rest.CreateMessage(dm.Id, new MessageRequest
                {
                    Embed = await _embeds.CreateMessageInfoEmbed(msg)
                });
            }
            catch (ForbiddenException) { } // No permissions to DM, can't check for this :(

            await TryRemoveOriginalReaction(evt);
        }
Example #7
0
        private async ValueTask <bool> TryHandleProxy(Shard shard, MessageCreateEvent evt, Guild guild, Channel channel, MessageContext ctx)
        {
            var botPermissions = _bot.PermissionsIn(channel.Id);

            try
            {
                return(await _proxy.HandleIncomingMessage(shard, evt, ctx, guild, channel, allowAutoproxy : ctx.AllowAutoproxy, botPermissions));
            }
            catch (PKError e)
            {
                // User-facing errors, print to the channel properly formatted
                if (botPermissions.HasFlag(PermissionSet.SendMessages))
                {
                    await _rest.CreateMessage(evt.ChannelId,
                                              new MessageRequest { Content = $"{Emojis.Error} {e.Message}" });
                }
            }

            return(false);
        }
Example #8
0
    public async Task SendErrorMessage(ulong channelId, string errorId)
    {
        var now = SystemClock.Instance.GetCurrentInstant();

        if (!ShouldSendErrorMessage(channelId, now))
        {
            _logger.Warning("Rate limited sending error message to {ChannelId} with error code {ErrorId}",
                            channelId, errorId);
            _metrics.Measure.Meter.Mark(BotMetrics.ErrorMessagesSent, "throttled");
            return;
        }

        var channelInfo = _botConfig.IsBetaBot
            ? "**#hi-please-break-the-beta-bot** on **[the support server *(click to join)*](https://discord.gg/THvbH59btW)**"
            : "**#bug-reports-and-errors** on **[the support server *(click to join)*](https://discord.gg/PczBt78)**";

        var embed = new EmbedBuilder()
                    .Color(0xE74C3C)
                    .Title("Internal error occurred")
                    .Description($"For support, please send the error code above in {channelInfo} with a description of what you were doing at the time.")
                    .Footer(new Embed.EmbedFooter(errorId))
                    .Timestamp(now.ToDateTimeOffset().ToString("O"));

        try
        {
            await _rest.CreateMessage(channelId,
                                      new MessageRequest { Content = $"> **Error code:** `{errorId}`", Embeds = new[] { embed.Build() } });

            _logger.Information("Sent error message to {ChannelId} with error code {ErrorId}", channelId, errorId);
            _metrics.Measure.Meter.Mark(BotMetrics.ErrorMessagesSent, "sent");
        }
        catch (Exception e)
        {
            _logger.Error(e, "Error sending error message to {ChannelId}", channelId);
            _metrics.Measure.Meter.Mark(BotMetrics.ErrorMessagesSent, "failed");
            throw;
        }
    }
Example #9
0
    public async ValueTask LogMessage(MessageContext ctx, PKMessage proxiedMessage, Message trigger,
                                      Message hookMessage, string oldContent = null)
    {
        var logChannelId = await GetAndCheckLogChannel(ctx, trigger, proxiedMessage);

        if (logChannelId == null)
        {
            return;
        }

        var triggerChannel = await _cache.GetChannel(proxiedMessage.Channel);

        var system = await _repo.GetSystem(ctx.SystemId.Value);

        var member = await _repo.GetMember(proxiedMessage.Member !.Value);

        // Send embed!
        var embed = _embed.CreateLoggedMessageEmbed(trigger, hookMessage, system.Hid, member, triggerChannel.Name,
                                                    oldContent);
        var url =
            $"https://discord.com/channels/{proxiedMessage.Guild.Value}/{proxiedMessage.Channel}/{proxiedMessage.Mid}";
        await _rest.CreateMessage(logChannelId.Value, new MessageRequest { Content = url, Embeds = new[] { embed } });
    }
Example #10
0
        public async ValueTask LogMessage(MessageContext ctx, ProxyMatch proxy, Message trigger, ulong hookMessage)
        {
            if (ctx.SystemId == null || ctx.LogChannel == null || ctx.InLogBlacklist)
            {
                return;
            }

            // Find log channel and check if valid
            var logChannel = await FindLogChannel(trigger.GuildId !.Value, ctx.LogChannel.Value);

            if (logChannel == null || logChannel.Type != Channel.ChannelType.GuildText)
            {
                return;
            }

            var triggerChannel = _cache.GetChannel(trigger.ChannelId);

            // Check bot permissions
            var perms = _bot.PermissionsIn(logChannel.Id);

            if (!perms.HasFlag(PermissionSet.SendMessages | PermissionSet.EmbedLinks))
            {
                _logger.Information(
                    "Does not have permission to proxy log, ignoring (channel: {ChannelId}, guild: {GuildId}, bot permissions: {BotPermissions})",
                    ctx.LogChannel.Value, trigger.GuildId !.Value, perms);
                return;
            }

            // Send embed!
            await using var conn = await _db.Obtain();

            var embed = _embed.CreateLoggedMessageEmbed(await _repo.GetSystem(conn, ctx.SystemId.Value),
                                                        await _repo.GetMember(conn, proxy.Member.Id), hookMessage, trigger.Id, trigger.Author, proxy.Content,
                                                        triggerChannel);
            var url = $"https://discord.com/channels/{trigger.GuildId}/{trigger.ChannelId}/{hookMessage}";
            await _rest.CreateMessage(logChannel.Id, new() { Content = url, Embed = embed });
        }