コード例 #1
0
ファイル: ProxyService.cs プロジェクト: xSke/PluralKit
    public async Task <bool> HandleIncomingMessage(MessageCreateEvent message, MessageContext ctx,
                                                   Guild guild, Channel channel, bool allowAutoproxy, PermissionSet botPermissions)
    {
        if (!ShouldProxy(channel, message, ctx))
        {
            return(false);
        }

        var autoproxySettings = await _repo.GetAutoproxySettings(ctx.SystemId.Value, guild.Id, null);

        if (autoproxySettings.AutoproxyMode == AutoproxyMode.Latch && IsUnlatch(message))
        {
            // "unlatch"
            await _repo.UpdateAutoproxy(ctx.SystemId.Value, guild.Id, null, new() {
                AutoproxyMember = null
            });

            return(false);
        }

        var rootChannel = await _cache.GetRootChannel(message.ChannelId);

        List <ProxyMember> members;

        // Fetch members and try to match to a specific member
        using (_metrics.Measure.Timer.Time(BotMetrics.ProxyMembersQueryTime))
            members = (await _repo.GetProxyMembers(message.Author.Id, message.GuildId !.Value)).ToList();

        if (!_matcher.TryMatch(ctx, autoproxySettings, members, out var match, message.Content, message.Attachments.Length > 0,
                               allowAutoproxy))
        {
            return(false);
        }

        // this is hopefully temporary, so not putting it into a separate method
        if (message.Content != null && message.Content.Length > 2000)
        {
            throw new PKError("PluralKit cannot proxy messages over 2000 characters in length.");
        }

        // Permission check after proxy match so we don't get spammed when not actually proxying
        if (!CheckBotPermissionsOrError(botPermissions, rootChannel.Id))
        {
            return(false);
        }

        // this method throws, so no need to wrap it in an if statement
        CheckProxyNameBoundsOrError(match.Member.ProxyName(ctx));

        // Check if the sender account can mention everyone/here + embed links
        // we need to "mirror" these permissions when proxying to prevent exploits
        var senderPermissions = PermissionExtensions.PermissionsFor(guild, rootChannel, message);
        var allowEveryone     = senderPermissions.HasFlag(PermissionSet.MentionEveryone);
        var allowEmbeds       = senderPermissions.HasFlag(PermissionSet.EmbedLinks);

        // Everything's in order, we can execute the proxy!
        await ExecuteProxy(message, ctx, autoproxySettings, match, allowEveryone, allowEmbeds);

        return(true);
    }
コード例 #2
0
    public static async Task <PermissionSet> PermissionsFor(this IDiscordCache cache, ulong channelId, ulong userId,
                                                            GuildMemberPartial?member, bool isWebhook = false)
    {
        if (!(await cache.TryGetChannel(channelId) is Channel channel))
        {
            // todo: handle channel not found better
            return(PermissionSet.Dm);
        }

        if (channel.GuildId == null)
        {
            return(PermissionSet.Dm);
        }

        var rootChannel = await cache.GetRootChannel(channelId);

        var guild = await cache.GetGuild(channel.GuildId.Value);

        if (isWebhook)
        {
            return(EveryonePermissions(guild));
        }

        return(PermissionsFor(guild, rootChannel, userId, member));
    }
コード例 #3
0
    public async Task Handle(int shardId, MessageCreateEvent evt)
    {
        if (evt.Author.Id == await _cache.GetOwnUser())
        {
            return;
        }
        if (evt.Type != Message.MessageType.Default && evt.Type != Message.MessageType.Reply)
        {
            return;
        }
        if (IsDuplicateMessage(evt))
        {
            return;
        }

        if (!(await _cache.PermissionsIn(evt.ChannelId)).HasFlag(PermissionSet.SendMessages))
        {
            return;
        }

        // spawn off saving the private channel into another thread
        // it is not a fatal error if this fails, and it shouldn't block message processing
        _ = _dmCache.TrySavePrivateChannel(evt);

        var guild = evt.GuildId != null ? await _cache.GetGuild(evt.GuildId.Value) : null;

        var channel = await _cache.GetChannel(evt.ChannelId);

        var rootChannel = await _cache.GetRootChannel(evt.ChannelId);

        // Log metrics and message info
        _metrics.Measure.Meter.Mark(BotMetrics.MessagesReceived);
        _lastMessageCache.AddMessage(evt);

        // Get message context from DB (tracking w/ metrics)
        MessageContext ctx;

        using (_metrics.Measure.Timer.Time(BotMetrics.MessageContextQueryTime))
            ctx = await _repo.GetMessageContext(evt.Author.Id, evt.GuildId ?? default, rootChannel.Id);

        // Try each handler until we find one that succeeds
        if (await TryHandleLogClean(evt, ctx))
        {
            return;
        }

        // Only do command/proxy handling if it's a user account
        if (evt.Author.Bot || evt.WebhookId != null || evt.Author.System == true)
        {
            return;
        }

        if (await TryHandleCommand(shardId, evt, guild, channel, ctx))
        {
            return;
        }
        await TryHandleProxy(evt, guild, channel, ctx);
    }
コード例 #4
0
        public async Task Handle(Shard shard, MessageCreateEvent evt)
        {
            if (evt.Author.Id == shard.User?.Id)
            {
                return;
            }
            if (evt.Type != Message.MessageType.Default && evt.Type != Message.MessageType.Reply)
            {
                return;
            }
            if (IsDuplicateMessage(evt))
            {
                return;
            }

            var guild = evt.GuildId != null?_cache.GetGuild(evt.GuildId.Value) : null;

            var channel     = _cache.GetChannel(evt.ChannelId);
            var rootChannel = _cache.GetRootChannel(evt.ChannelId);

            // Log metrics and message info
            _metrics.Measure.Meter.Mark(BotMetrics.MessagesReceived);
            _lastMessageCache.AddMessage(evt);

            // Get message context from DB (tracking w/ metrics)
            MessageContext ctx;

            await using (var conn = await _db.Obtain())
                using (_metrics.Measure.Timer.Time(BotMetrics.MessageContextQueryTime))
                    ctx = await _repo.GetMessageContext(conn, evt.Author.Id, evt.GuildId ?? default, rootChannel.Id);

            // Try each handler until we find one that succeeds
            if (await TryHandleLogClean(evt, ctx))
            {
                return;
            }

            // Only do command/proxy handling if it's a user account
            if (evt.Author.Bot || evt.WebhookId != null || evt.Author.System == true)
            {
                return;
            }

            if (await TryHandleCommand(shard, evt, guild, channel, ctx))
            {
                return;
            }
            await TryHandleProxy(shard, evt, guild, channel, ctx);
        }
コード例 #5
0
    public async Task <Message> EditWebhookMessage(ulong channelId, ulong messageId, string newContent)
    {
        var allowedMentions = newContent.ParseMentions() with
        {
            Roles = Array.Empty <ulong>(),
            Parse = Array.Empty <AllowedMentions.ParseType>()
        };

        ulong?threadId = null;
        var   root     = await _cache.GetRootChannel(channelId);

        if (root.Id != channelId)
        {
            threadId = channelId;
        }

        var webhook = await _webhookCache.GetWebhook(root.Id);

        return(await _rest.EditWebhookMessage(webhook.Id, webhook.Token, messageId,
                                              new WebhookMessageEditRequest { Content = newContent, AllowedMentions = allowedMentions },
                                              threadId));
    }
コード例 #6
0
        public static PermissionSet PermissionsFor(this IDiscordCache cache, ulong channelId, ulong userId, ICollection <ulong>?userRoles, bool isWebhook = false)
        {
            if (!cache.TryGetChannel(channelId, out var channel))
            {
                // todo: handle channel not found better
                return(PermissionSet.Dm);
            }

            if (channel.GuildId == null)
            {
                return(PermissionSet.Dm);
            }

            var rootChannel = cache.GetRootChannel(channelId);

            var guild = cache.GetGuild(channel.GuildId.Value);

            if (isWebhook)
            {
                return(EveryonePermissions(guild));
            }

            return(PermissionsFor(guild, rootChannel, userId, userRoles));
        }