示例#1
0
    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 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}");
        }
    }