Esempio n. 1
0
    private async Task ExecuteProxy(Message trigger, MessageContext ctx, AutoproxySettings autoproxySettings,
                                    ProxyMatch match, bool allowEveryone, bool allowEmbeds)
    {
        // Create reply embed
        var embeds  = new List <Embed>();
        var content = "";

        if (trigger.Type == Message.MessageType.Reply && trigger.MessageReference?.ChannelId == trigger.ChannelId)
        {
            var repliedTo = trigger.ReferencedMessage.Value;
            if (repliedTo != null)
            {
                if (trigger.Mentions.Length > 0 &&
                    repliedTo.Author.Id == trigger.Mentions[0].Id &&
                    !(trigger.Content.Contains($"<@{repliedTo.Author.Id}>") ||
                      trigger.Content.Contains($"<@!{repliedTo.Author.Id}>")))
                {
                    content = $"*<@{repliedTo.Author.Id}>*\n";
                }

                var(nickname, avatar) = await FetchReferencedMessageAuthorInfo(trigger, repliedTo);

                var embed = CreateReplyEmbed(match, trigger, repliedTo, nickname, avatar);
                if (embed != null)
                {
                    embeds.Add(embed);
                }
            }

            // TODO: have a clean error for when message can't be fetched instead of just being silent
        }

        // Send the webhook
        content += match.ProxyContent;
        if (!allowEmbeds)
        {
            content = content.BreakLinkEmbeds();
        }

        var messageChannel = await _cache.GetChannel(trigger.ChannelId);

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

        var threadId = messageChannel.IsThread() ? messageChannel.Id : (ulong?)null;
        var guild    = await _cache.GetGuild(trigger.GuildId.Value);

        var proxyMessage = await _webhookExecutor.ExecuteWebhook(new ProxyRequest
        {
            GuildId       = trigger.GuildId !.Value,
            ChannelId     = rootChannel.Id,
            ThreadId      = threadId,
            Name          = await FixSameName(messageChannel.Id, ctx, match.Member),
            AvatarUrl     = AvatarUtils.TryRewriteCdnUrl(match.Member.ProxyAvatar(ctx)),
            Content       = content,
            Attachments   = trigger.Attachments,
            FileSizeLimit = guild.FileSizeLimit(),
            Embeds        = embeds.ToArray(),
            Stickers      = trigger.StickerItems,
            AllowEveryone = allowEveryone
        });
Esempio n. 2
0
    public static JObject ToJson(this AutoproxySettings settings, string?memberHid = null)
    {
        var o = new JObject();

        // tbd
        o.Add("autoproxy_mode", settings.AutoproxyMode.ToString().ToLower());
        o.Add("autoproxy_member", memberHid);

        return(o);
    }
Esempio n. 3
0
    private async Task <IActionResult> Get(AutoproxySettings settings)
    {
        string hid = null;

        if (settings.AutoproxyMember != null)
        {
            hid = (await _repo.GetMember(settings.AutoproxyMember.Value))?.Hid;
        }

        return(Ok(settings.ToJson(hid)));
    }
Esempio n. 4
0
    public static JObject ToJson(this AutoproxySettings settings, string?memberHid = null)
    {
        var o = new JObject();

        // tbd
        o.Add("autoproxy_mode", settings.AutoproxyMode.ToString().ToLower());
        o.Add("autoproxy_member", settings.AutoproxyMode == AutoproxyMode.Front ? null : memberHid);
        o.Add("last_latch_timestamp", settings.LastLatchTimestamp?.FormatExport());

        return(o);
    }
Esempio n. 5
0
    private bool IsLatchExpired(MessageContext ctx, AutoproxySettings settings)
    {
        if (ctx.LatchTimeout == 0)
        {
            return(false);
        }

        var timeout = ctx.LatchTimeout.HasValue
            ? Duration.FromSeconds(ctx.LatchTimeout.Value)
            : DefaultLatchExpiryTime;

        return(_clock.GetCurrentInstant() - settings.LastLatchTimestamp > timeout);
    }
Esempio n. 6
0
    private async Task AutoproxyFront(Context ctx, AutoproxySettings settings)
    {
        if (settings.AutoproxyMode == AutoproxyMode.Front)
        {
            await ctx.Reply($"{Emojis.Note} Autoproxy is already set to front mode in this server. If you want to disable autoproxying, use `pk;autoproxy off`.");
        }
        else
        {
            await UpdateAutoproxy(ctx, AutoproxyMode.Front, null);

            await ctx.Reply($"{Emojis.Success} Autoproxy set to front mode in this server. Messages will now be autoproxied using the *current first fronter*, if any.");
        }
    }
Esempio n. 7
0
    private async Task AutoproxyLatch(Context ctx, AutoproxySettings settings)
    {
        if (settings.AutoproxyMode == AutoproxyMode.Latch)
        {
            await ctx.Reply($"{Emojis.Note} Autoproxy is already set to latch mode in this server. If you want to disable autoproxying, use `pk;autoproxy off`.");
        }
        else
        {
            await UpdateAutoproxy(ctx, AutoproxyMode.Latch, null);

            await ctx.Reply($"{Emojis.Success} Autoproxy set to latch mode in this server. Messages will now be autoproxied using the *last-proxied member* in this server.");
        }
    }
Esempio n. 8
0
    private async Task AutoproxyOff(Context ctx, AutoproxySettings settings)
    {
        if (settings.AutoproxyMode == AutoproxyMode.Off)
        {
            await ctx.Reply($"{Emojis.Note} Autoproxy is already off in this server.");
        }
        else
        {
            await UpdateAutoproxy(ctx, AutoproxyMode.Off, null);

            await ctx.Reply($"{Emojis.Success} Autoproxy turned off in this server.");
        }
    }
Esempio n. 9
0
 public bool TryMatch(MessageContext ctx, AutoproxySettings settings, IReadOnlyCollection <ProxyMember> members, out ProxyMatch match,
                      string messageContent,
                      bool hasAttachments, bool allowAutoproxy)
 {
     if (TryMatchTags(members, messageContent, hasAttachments, out match))
     {
         return(true);
     }
     if (allowAutoproxy && TryMatchAutoproxy(ctx, settings, members, messageContent, out match))
     {
         return(true);
     }
     return(false);
 }
Esempio n. 10
0
    private bool TryMatchAutoproxy(MessageContext ctx, AutoproxySettings settings, IReadOnlyCollection <ProxyMember> members,
                                   string messageContent,
                                   out ProxyMatch match)
    {
        match = default;

        // Skip autoproxy match if we hit the escape character
        if (messageContent.StartsWith(AutoproxyEscapeCharacter))
        {
            throw new ProxyService.ProxyChecksFailedException(
                      "This message matches none of your proxy tags, and it was not autoproxied because it starts with a backslash (`\\`).");
        }

        // Find the member we should autoproxy (null if none)
        var member = settings.AutoproxyMode switch
        {
            AutoproxyMode.Member when settings.AutoproxyMember != null =>
            members.FirstOrDefault(m => m.Id == settings.AutoproxyMember),

            AutoproxyMode.Front when ctx.LastSwitchMembers.Length > 0 =>
            members.FirstOrDefault(m => m.Id == ctx.LastSwitchMembers[0]),

            AutoproxyMode.Latch when settings.AutoproxyMember != null =>
            members.FirstOrDefault(m => m.Id == settings.AutoproxyMember.Value),

            _ => null
        };

        // Throw an error if the member is null, message varies depending on autoproxy mode
        if (member == null)
        {
            if (settings.AutoproxyMode == AutoproxyMode.Front)
            {
                throw new ProxyService.ProxyChecksFailedException(
                          "You are using autoproxy front, but no members are currently registered as fronting. Please use `pk;switch <member>` to log a new switch.");
            }
            if (settings.AutoproxyMode == AutoproxyMode.Member)
            {
                throw new ProxyService.ProxyChecksFailedException(
                          "You are using member-specific autoproxy with an invalid member. Was this member deleted?");
            }
            if (settings.AutoproxyMode == AutoproxyMode.Latch)
            {
                throw new ProxyService.ProxyChecksFailedException(
                          "You are using autoproxy latch, but have not sent any messages yet in this server. Please send a message using proxy tags first.");
            }
            throw new ProxyService.ProxyChecksFailedException(
                      "This message matches none of your proxy tags and autoproxy is not enabled.");
        }

        if (settings.AutoproxyMode != AutoproxyMode.Member && !member.AllowAutoproxy)
        {
            throw new ProxyService.ProxyChecksFailedException(
                      "This member has autoproxy disabled. To enable it, use `pk;m <member> autoproxy on`.");
        }

        // Moved the IsLatchExpired() check to here, so that an expired latch and a latch without any previous messages throw different errors
        if (settings.AutoproxyMode == AutoproxyMode.Latch && IsLatchExpired(ctx, settings))
        {
            throw new ProxyService.ProxyChecksFailedException(
                      "Latch-mode autoproxy has timed out. Please send a new message using proxy tags.");
        }

        match = new ProxyMatch
        {
            Content = messageContent,
            Member  = member,

            // We're autoproxying, so not using any proxy tags here
            // we just find the first pair of tags (if any), otherwise null
            ProxyTags = member.ProxyTags.FirstOrDefault()
        };
        return(true);
    }
Esempio n. 11
0
    private async Task <IActionResult> Patch(PKSystem system, ulong?guildId, ulong?channelId, JObject data, AutoproxySettings oldData)
    {
        var updateMember = data.ContainsKey("autoproxy_member");

        PKMember?member = null;

        if (updateMember)
        {
            member = await ResolveMember(data.Value <string>("autoproxy_member"));
        }

        var patch = AutoproxyPatch.FromJson(data, member?.Id);

        patch.AssertIsValid();
        if (updateMember && member == null)
        {
            patch.Errors.Add(new("autoproxy_member", "Member not found."));
        }
        if (updateMember && ((patch.AutoproxyMode.IsPresent && patch.AutoproxyMode.Value == AutoproxyMode.Latch) || oldData.AutoproxyMode == AutoproxyMode.Latch))
        {
            patch.Errors.Add(new("autoproxy_member", "Cannot update autoproxy member if autoproxy mode is set to latch"));
        }
        if (patch.Errors.Count > 0)
        {
            throw new ModelParseError(patch.Errors);
        }

        var res = await _repo.UpdateAutoproxy(system.Id, guildId, channelId, patch);

        if (!updateMember && oldData.AutoproxyMember != null)
        {
            member = await _repo.GetMember(oldData.AutoproxyMember.Value);
        }
        return(Ok(res.ToJson(member?.Hid)));
    }
Esempio n. 12
0
    private async Task <Embed> CreateAutoproxyStatusEmbed(Context ctx, AutoproxySettings settings)
    {
        var commandList = "**pk;autoproxy latch** - Autoproxies as last-proxied member"
                          + "\n**pk;autoproxy front** - Autoproxies as current (first) fronter"
                          + "\n**pk;autoproxy <member>** - Autoproxies as a specific member";
        var eb = new EmbedBuilder()
                 .Title($"Current autoproxy status (for {ctx.Guild.Name.EscapeMarkdown()})");

        var fronters       = ctx.MessageContext.LastSwitchMembers;
        var relevantMember = settings.AutoproxyMode switch
        {
            AutoproxyMode.Front => fronters.Length > 0 ? await ctx.Repository.GetMember(fronters[0]) : null,
            AutoproxyMode.Member when settings.AutoproxyMember.HasValue => await ctx.Repository.GetMember(settings.AutoproxyMember.Value),
            _ => null
        };

        switch (settings.AutoproxyMode)
        {
        case AutoproxyMode.Off:
            eb.Description($"Autoproxy is currently **off** in this server. To enable it, use one of the following commands:\n{commandList}");
            break;

        case AutoproxyMode.Front:
        {
            if (fronters.Length == 0)
            {
                eb.Description("Autoproxy is currently set to **front mode** in this server, but there are currently no fronters registered. Use the `pk;switch` command to log a switch.");
            }
            else
            {
                if (relevantMember == null)
                {
                    throw new ArgumentException("Attempted to print member autoproxy status, but the linked member ID wasn't found in the database. Should be handled appropriately.");
                }
                eb.Description($"Autoproxy is currently set to **front mode** in this server. The current (first) fronter is **{relevantMember.NameFor(ctx).EscapeMarkdown()}** (`{relevantMember.Hid}`). To disable, type `pk;autoproxy off`.");
            }

            break;
        }

        case AutoproxyMode.Member:
        {
            if (relevantMember == null)
            {
                // just pretend autoproxy is off if the member was deleted
                // ideally we would set it to off in the database though...
                eb.Description($"Autoproxy is currently **off** in this server. To enable it, use one of the following commands:\n{commandList}");
            }
            else
            {
                eb.Description($"Autoproxy is active for member **{relevantMember.NameFor(ctx)}** (`{relevantMember.Hid}`) in this server. To disable, type `pk;autoproxy off`.");
            }

            break;
        }

        case AutoproxyMode.Latch:
            eb.Description("Autoproxy is currently set to **latch mode**, meaning the *last-proxied member* will be autoproxied. To disable, type `pk;autoproxy off`.");
            break;

        default: throw new ArgumentOutOfRangeException();
        }

        if (!ctx.MessageContext.AllowAutoproxy)
        {
            eb.Field(new Embed.Field("\u200b", $"{Emojis.Note} Autoproxy is currently **disabled** for your account (<@{ctx.Author.Id}>). To enable it, use `pk;autoproxy account enable`."));
        }

        return(eb.Build());
    }