Sanitize user input in response messages

This commit is contained in:
Ske 2019-07-10 13:44:03 +02:00
parent 2b508f80e9
commit 352940abbd
7 changed files with 36 additions and 27 deletions

View File

@ -38,7 +38,7 @@ namespace PluralKit.Bot.Commands
// Warn if there's already a member by this name
var existingMember = await Members.GetByName(Context.SenderSystem, memberName);
if (existingMember != null) {
var msg = await Context.Channel.SendMessageAsync($"{Emojis.Warn} You already have a member in your system with the name \"{existingMember.Name}\" (with ID `{existingMember.Hid}`). Do you want to create another member with the same name?");
var msg = await Context.Channel.SendMessageAsync($"{Emojis.Warn} You already have a member in your system with the name \"{existingMember.Name.Sanitize()}\" (with ID `{existingMember.Hid}`). Do you want to create another member with the same name?");
if (!await Context.PromptYesNo(msg)) throw new PKError("Member creation cancelled.");
}
@ -46,7 +46,7 @@ namespace PluralKit.Bot.Commands
var member = await Members.Create(Context.SenderSystem, memberName);
// Send confirmation and space hint
await Context.Channel.SendMessageAsync($"{Emojis.Success} Member \"{memberName}\" (`{member.Hid}`) registered! Type `pk;help member` for a list of commands to edit this member.");
await Context.Channel.SendMessageAsync($"{Emojis.Success} Member \"{memberName.Sanitize()}\" (`{member.Hid}`) registered! Type `pk;help member` for a list of commands to edit this member.");
if (memberName.Contains(" ")) await Context.Channel.SendMessageAsync($"{Emojis.Note} Note that this member's name contains spaces. You will need to surround it with \"double quotes\" when using commands referring to it.");
}
@ -69,7 +69,7 @@ namespace PluralKit.Bot.Commands
// Warn if there's already a member by this name
var existingMember = await Members.GetByName(Context.SenderSystem, newName);
if (existingMember != null) {
var msg = await Context.Channel.SendMessageAsync($"{Emojis.Warn} You already have a member in your system with the name \"{existingMember.Name}\" (`{existingMember.Hid}`). Do you want to rename this member to that name too?");
var msg = await Context.Channel.SendMessageAsync($"{Emojis.Warn} You already have a member in your system with the name \"{existingMember.Name.Sanitize()}\" (`{existingMember.Hid}`). Do you want to rename this member to that name too?");
if (!await Context.PromptYesNo(msg)) throw new PKError("Member renaming cancelled.");
}
@ -170,7 +170,7 @@ namespace PluralKit.Bot.Commands
ContextEntity.Prefix = prefixAndSuffix[0].Length > 0 ? prefixAndSuffix[0] : null;
ContextEntity.Suffix = prefixAndSuffix[1].Length > 0 ? prefixAndSuffix[1] : null;
await Members.Save(ContextEntity);
await Context.Channel.SendMessageAsync($"{Emojis.Success} Member proxy tags changed to `{ContextEntity.ProxyString}`. Try proxying now!");
await Context.Channel.SendMessageAsync($"{Emojis.Success} Member proxy tags changed to `{ContextEntity.ProxyString.Sanitize()}`. Try proxying now!");
}
[Command("delete")]
@ -179,7 +179,7 @@ namespace PluralKit.Bot.Commands
[MustPassOwnMember]
public async Task MemberDelete()
{
await Context.Channel.SendMessageAsync($"{Emojis.Warn} Are you sure you want to delete \"{ContextEntity.Name}\"? If so, reply to this message with the member's ID (`{ContextEntity.Hid}`). __***This cannot be undone!***__");
await Context.Channel.SendMessageAsync($"{Emojis.Warn} Are you sure you want to delete \"{ContextEntity.Name.Sanitize()}\"? If so, reply to this message with the member's ID (`{ContextEntity.Hid}`). __***This cannot be undone!***__");
if (!await Context.ConfirmWithReply(ContextEntity.Hid)) throw Errors.MemberDeleteCancelled;
await Members.Delete(ContextEntity);
await Context.Channel.SendMessageAsync($"{Emojis.Success} Member deleted.");

View File

@ -21,7 +21,6 @@ namespace PluralKit.Bot.Commands {
sendMessages: true
);
// TODO: allow customization of invite ID
var invite = $"https://discordapp.com/oauth2/authorize?client_id={clientId}&scope=bot&permissions={permissions.RawValue}";
await Context.Channel.SendMessageAsync($"{Emojis.Success} Use this link to add PluralKit to your server:\n<{invite}>");
}

View File

@ -20,7 +20,7 @@ namespace PluralKit.Bot.Commands
await LogChannels.SetLogChannel(Context.Guild, channel);
if (channel != null)
await Context.Channel.SendMessageAsync($"{Emojis.Success} Proxy logging channel set to #{channel.Name}.");
await Context.Channel.SendMessageAsync($"{Emojis.Success} Proxy logging channel set to #{channel.Name.Sanitize()}.");
else
await Context.Channel.SendMessageAsync($"{Emojis.Success} Proxy logging channel cleared.");
}

View File

@ -52,7 +52,7 @@ namespace PluralKit.Bot.Commands
if (members.Count == 0)
await Context.Channel.SendMessageAsync($"{Emojis.Success} Switch-out registered.");
else
await Context.Channel.SendMessageAsync($"{Emojis.Success} Switch registered. Current fronter is now {string.Join(", ", members.Select(m => m.Name))}.");
await Context.Channel.SendMessageAsync($"{Emojis.Success} Switch registered. Current fronter is now {string.Join(", ", members.Select(m => m.Name)).Sanitize()}.");
}
[Command("move")]
@ -91,7 +91,7 @@ namespace PluralKit.Bot.Commands
var newSwitchDeltaStr = Formats.DurationFormat.Format(SystemClock.Instance.GetCurrentInstant() - time.ToInstant());
// yeet
var msg = await Context.Channel.SendMessageAsync($"{Emojis.Warn} This will move the latest switch ({lastSwitchMemberStr}) from {lastSwitchTimeStr} ({lastSwitchDeltaStr} ago) to {newSwitchTimeStr} ({newSwitchDeltaStr} ago). Is this OK?");
var msg = await Context.Channel.SendMessageAsync($"{Emojis.Warn} This will move the latest switch ({lastSwitchMemberStr.Sanitize()}) from {lastSwitchTimeStr} ({lastSwitchDeltaStr} ago) to {newSwitchTimeStr} ({newSwitchDeltaStr} ago). Is this OK?");
if (!await Context.PromptYesNo(msg)) throw Errors.SwitchMoveCancelled;
// aaaand *now* we do the move
@ -116,7 +116,7 @@ namespace PluralKit.Bot.Commands
if (lastTwoSwitches.Length == 1)
{
msg = await Context.Channel.SendMessageAsync(
$"{Emojis.Warn} This will delete the latest switch ({lastSwitchMemberStr}, {lastSwitchDeltaStr} ago). You have no other switches logged. Is this okay?");
$"{Emojis.Warn} This will delete the latest switch ({lastSwitchMemberStr.Sanitize()}, {lastSwitchDeltaStr} ago). You have no other switches logged. Is this okay?");
}
else
{
@ -124,7 +124,7 @@ namespace PluralKit.Bot.Commands
var secondSwitchMemberStr = string.Join(", ", secondSwitchMembers.Select(m => m.Name));
var secondSwitchDeltaStr = Formats.DurationFormat.Format(SystemClock.Instance.GetCurrentInstant() - lastTwoSwitches[1].Timestamp);
msg = await Context.Channel.SendMessageAsync(
$"{Emojis.Warn} This will delete the latest switch ({lastSwitchMemberStr}, {lastSwitchDeltaStr} ago). The next latest switch is {secondSwitchMemberStr} ({secondSwitchDeltaStr} ago). Is this okay?");
$"{Emojis.Warn} This will delete the latest switch ({lastSwitchMemberStr.Sanitize()}, {lastSwitchDeltaStr} ago). The next latest switch is {secondSwitchMemberStr.Sanitize()} ({secondSwitchDeltaStr} ago). Is this okay?");
}
if (!await Context.PromptYesNo(msg)) throw Errors.SwitchDeleteCancelled;

View File

@ -74,15 +74,21 @@ namespace PluralKit.Bot.Commands
[Remarks("system tag <tag>")]
[MustHaveSystem]
public async Task Tag([Remainder] string newTag = null) {
if (newTag.Length > Limits.MaxSystemTagLength) throw Errors.SystemNameTooLongError(newTag.Length);
Context.SenderSystem.Tag = newTag;
// Check unproxyable messages *after* changing the tag (so it's seen in the method) but *before* we save to DB (so we can cancel)
var unproxyableMembers = await Members.GetUnproxyableMembers(Context.SenderSystem);
if (unproxyableMembers.Count > 0) {
var msg = await Context.Channel.SendMessageAsync($"{Emojis.Warn} Changing your system tag to '{newTag}' will result in the following members being unproxyable, since the tag would bring their name over 32 characters:\n**{string.Join(", ", unproxyableMembers.Select((m) => m.Name))}**\nDo you want to continue anyway?");
if (!await Context.PromptYesNo(msg)) throw new PKError("Tag change cancelled.");
if (newTag != null)
{
if (newTag.Length > Limits.MaxSystemTagLength) throw Errors.SystemNameTooLongError(newTag.Length);
// Check unproxyable messages *after* changing the tag (so it's seen in the method) but *before* we save to DB (so we can cancel)
var unproxyableMembers = await Members.GetUnproxyableMembers(Context.SenderSystem);
if (unproxyableMembers.Count > 0)
{
var msg = await Context.Channel.SendMessageAsync(
$"{Emojis.Warn} Changing your system tag to '{newTag}' will result in the following members being unproxyable, since the tag would bring their name over 32 characters:\n**{string.Join(", ", unproxyableMembers.Select((m) => m.Name))}**\nDo you want to continue anyway?");
if (!await Context.PromptYesNo(msg)) throw new PKError("Tag change cancelled.");
}
}
await Systems.Save(Context.SenderSystem);

View File

@ -22,15 +22,15 @@ namespace PluralKit.Bot {
public static PKError MemberNameTooLongError(int length) => new PKError($"Member name too long ({length}/{Limits.MaxMemberNameLength} characters).");
public static PKError MemberPronounsTooLongError(int length) => new PKError($"Member pronouns too long ({length}/{Limits.MaxMemberNameLength} characters).");
public static PKError InvalidColorError(string color) => new PKError($"\"{color}\" is not a valid color. Color must be in 6-digit RGB hex format (eg. #ff0000).");
public static PKError BirthdayParseError(string birthday) => new PKError($"\"{birthday}\" could not be parsed as a valid date. Try a format like \"2016-12-24\" or \"May 3 1996\".");
public static PKError InvalidColorError(string color) => new PKError($"\"{color.Sanitize()}\" is not a valid color. Color must be in 6-digit RGB hex format (eg. #ff0000).");
public static PKError BirthdayParseError(string birthday) => new PKError($"\"{birthday.Sanitize()}\" could not be parsed as a valid date. Try a format like \"2016-12-24\" or \"May 3 1996\".");
public static PKError ProxyMustHaveText => new PKSyntaxError("Example proxy message must contain the string 'text'.");
public static PKError ProxyMultipleText => new PKSyntaxError("Example proxy message must contain the string 'text' exactly once.");
public static PKError MemberDeleteCancelled => new PKError($"Member deletion cancelled. Stay safe! {Emojis.ThumbsUp}");
public static PKError AvatarServerError(HttpStatusCode statusCode) => new PKError($"Server responded with status code {(int) statusCode}, are you sure your link is working?");
public static PKError AvatarFileSizeLimit(long size) => new PKError($"File size too large ({size.Bytes().ToString("#.#")} > {Limits.AvatarFileSizeLimit.Bytes().ToString("#.#")}), try shrinking or compressing the image.");
public static PKError AvatarNotAnImage(string mimeType) => new PKError($"The given link does not point to an image{(mimeType != null ? $" ({mimeType})" : "")}. Make sure you're using a direct link (ending in .jpg, .png, .gif).");
public static PKError AvatarNotAnImage(string mimeType) => new PKError($"The given link does not point to an image{(mimeType != null ? $" ({mimeType.Sanitize()})" : "")}. Make sure you're using a direct link (ending in .jpg, .png, .gif).");
public static PKError AvatarDimensionsTooLarge(int width, int height) => new PKError($"Image too large ({width}x{height} > {Limits.AvatarDimensionLimit}x{Limits.AvatarDimensionLimit}), try resizing the image.");
public static PKError InvalidUrl(string url) => new PKError($"The given URL is invalid.");
@ -44,30 +44,30 @@ namespace PluralKit.Bot {
public static PKError SameSwitch(ICollection<PKMember> members)
{
if (members.Count == 0) return new PKError("There's already no one in front.");
if (members.Count == 1) return new PKError($"Member {members.First().Name} is already fronting.");
return new PKError($"Members {string.Join(", ", members.Select(m => m.Name))} are already fronting.");
if (members.Count == 1) return new PKError($"Member {members.First().Name.Sanitize()} is already fronting.");
return new PKError($"Members {string.Join(", ", members.Select(m => m.Name.Sanitize()))} are already fronting.");
}
public static PKError DuplicateSwitchMembers => new PKError("Duplicate members in member list.");
public static PKError SwitchMemberNotInSystem => new PKError("One or more switch members aren't in your own system.");
public static PKError InvalidDateTime(string str) => new PKError($"Could not parse '{str}' as a valid date/time. Try using a syntax such as \"May 21, 12:30 PM\" or \"3d12h\" (ie. 3 days, 12 hours ago).");
public static PKError InvalidDateTime(string str) => new PKError($"Could not parse '{str.Sanitize()}' as a valid date/time. Try using a syntax such as \"May 21, 12:30 PM\" or \"3d12h\" (ie. 3 days, 12 hours ago).");
public static PKError SwitchTimeInFuture => new PKError("Can't move switch to a time in the future.");
public static PKError NoRegisteredSwitches => new PKError("There are no registered switches for this system.");
public static PKError SwitchMoveBeforeSecondLast(ZonedDateTime time) => new PKError($"Can't move switch to before last switch time ({Formats.ZonedDateTimeFormat.Format(time)}), as it would cause conflicts.");
public static PKError SwitchMoveCancelled => new PKError("Switch move cancelled.");
public static PKError SwitchDeleteCancelled => new PKError("Switch deletion cancelled.");
public static PKError TimezoneParseError(string timezone) => new PKError($"Could not parse timezone offset {timezone}. Offset must be a value like 'UTC+5' or 'GMT-4:30'.");
public static PKError TimezoneParseError(string timezone) => new PKError($"Could not parse timezone offset {timezone.Sanitize()}. Offset must be a value like 'UTC+5' or 'GMT-4:30'.");
public static PKError InvalidTimeZone(string zoneStr) => new PKError($"Invalid time zone ID '{zoneStr}'. To find your time zone ID, use the following website: <https://xske.github.io/tz>");
public static PKError InvalidTimeZone(string zoneStr) => new PKError($"Invalid time zone ID '{zoneStr.Sanitize()}'. To find your time zone ID, use the following website: <https://xske.github.io/tz>");
public static PKError TimezoneChangeCancelled => new PKError("Time zone change cancelled.");
public static PKError AmbiguousTimeZone(string zoneStr, int count) => new PKError($"The time zone query '{zoneStr}' resulted in **{count}** different time zone regions. Try being more specific - e.g. pass an exact time zone specifier from the following website: <https://xske.github.io/tz>");
public static PKError AmbiguousTimeZone(string zoneStr, int count) => new PKError($"The time zone query '{zoneStr.Sanitize()}' resulted in **{count}** different time zone regions. Try being more specific - e.g. pass an exact time zone specifier from the following website: <https://xske.github.io/tz>");
public static PKError NoImportFilePassed => new PKError("You must either pass an URL to a file as a command parameter, or as an attachment to the message containing the command.");
public static PKError InvalidImportFile => new PKError("Imported data file invalid. Make sure this is a .json file directly exported from PluralKit or Tupperbox.");
public static PKError ImportCancelled => new PKError("Import cancelled.");
public static PKError MessageNotFound(ulong id) => new PKError($"Message with ID '{id}' not found. Are you sure it's a message proxied by PluralKit?");
public static PKError DurationParseError(string durationStr) => new PKError($"Could not parse '{durationStr}' as a valid duration. Try a format such as `30d`, `1d3h` or `20m30s`.");
public static PKError DurationParseError(string durationStr) => new PKError($"Could not parse '{durationStr.Sanitize()}' as a valid duration. Try a format such as `30d`, `1d3h` or `20m30s`.");
}
}

View File

@ -4,6 +4,7 @@ using System.Data;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Dapper;
using Discord;
@ -82,6 +83,9 @@ namespace PluralKit.Bot
argPos = num + 2;
return true;
}
public static string Sanitize(this string input) =>
Regex.Replace(Regex.Replace(input, "<@[!&]?(\\d{17,19})>", "<\\@$1>"), "@(everyone|here)", "@\u200B$1");
}
class PKSystemTypeReader : TypeReader