From 326b9e5529d52e36857327420f234fd951121ea8 Mon Sep 17 00:00:00 2001 From: HomicidalChicken <86430321+Cryptofowl@users.noreply.github.com> Date: Thu, 19 Jan 2023 22:24:45 -0500 Subject: [PATCH] Move filter to separate config and add more scanning (#603) * Create .gitattributes Added a .gitattributes file that excludes the local customWordFilter.txt file from merged updates, allowing server operators to maintain their own word filter list and not have it overwritten. * Update .gitignore Added chatCensoredList to gitignore * Update .gitignore * Dynamic censor list file changes Removed .gitattributes file, attempted to make chatCensoredList.txt into a dynamic file loaded at runtime instead. * Added additional censorship coverage Censorship now covers: Level titles Level descriptions Reviews Comments * Delete chatCensoredList.txt * Update .gitignore Co-authored-by: Josh * Update filter verbiage * Update ProjectLighthouse.Servers.GameServer/Controllers/CommentController.cs Co-authored-by: Josh * Update ProjectLighthouse/Helpers/CensorHelper.cs Co-authored-by: Josh * Add CensorConfiguration and add more filters Co-authored-by: Josh --- .../Controllers/CommentController.cs | 4 +- .../Controllers/MessageController.cs | 6 +-- .../Controllers/Slots/PublishController.cs | 4 ++ .../Controllers/Slots/ReviewController.cs | 2 + .../Controllers/SlotPageController.cs | 2 + .../Controllers/UserPageController.cs | 2 + .../Pages/Debug/FilterTestPage.cshtml.cs | 2 +- .../Pages/SlotSettingsPage.cshtml.cs | 2 + .../Pages/UserSettingsPage.cshtml.cs | 1 + .../Configuration/CensorConfiguration.cs | 37 +++++++++++++++++++ .../Configuration/ServerConfiguration.cs | 5 +-- ProjectLighthouse/Helpers/CensorHelper.cs | 35 ++++++------------ ProjectLighthouse/ProjectLighthouse.csproj | 4 -- ProjectLighthouse/chatCensoredList.txt | 17 --------- 14 files changed, 70 insertions(+), 53 deletions(-) create mode 100644 ProjectLighthouse/Configuration/CensorConfiguration.cs delete mode 100644 ProjectLighthouse/chatCensoredList.txt diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/CommentController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/CommentController.cs index 9318758d..ba9ac979 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/CommentController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/CommentController.cs @@ -119,7 +119,9 @@ public class CommentController : ControllerBase targetId = await this.database.UserIdFromUsername(username!); } - bool success = await this.database.PostComment(token.UserId, targetId, type, comment.Message); + string filteredText = CensorHelper.FilterMessage(comment.Message); + + bool success = await this.database.PostComment(token.UserId, targetId, type, filteredText); if (success) return this.Ok(); return this.BadRequest(); diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/MessageController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/MessageController.cs index 0ffb914e..afff8391 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/MessageController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/MessageController.cs @@ -116,13 +116,13 @@ along with this program. If not, see ."; return this.Ok(); } - string scannedText = CensorHelper.ScanMessage(message); + string filteredText = CensorHelper.FilterMessage(message); string username = await this.database.UsernameFromGameToken(token); if (ServerConfiguration.Instance.LogChatFiltering) - Logger.Info($"{username}: {message} / {scannedText}", LogArea.Filter); + Logger.Info($"{username}: {message} / {filteredText}", LogArea.Filter); - return this.Ok(scannedText); + return this.Ok(filteredText); } } \ No newline at end of file diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/PublishController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/PublishController.cs index 9b409218..8dec6fee 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/PublishController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/PublishController.cs @@ -107,12 +107,16 @@ public class PublishController : ControllerBase return this.BadRequest(); } + slot.Description = CensorHelper.FilterMessage(slot.Description); + if (slot.Description.Length > 512) { Logger.Warn($"Rejecting level upload, description too long ({slot.Description.Length} characters)", LogArea.Publish); return this.BadRequest(); } + slot.Name = CensorHelper.FilterMessage(slot.Name); + if (slot.Name.Length > 64) { Logger.Warn($"Rejecting level upload, title too long ({slot.Name.Length} characters)", LogArea.Publish); diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ReviewController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ReviewController.cs index d96faa78..2bd91bc8 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ReviewController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ReviewController.cs @@ -94,6 +94,8 @@ public class ReviewController : ControllerBase Review? newReview = await this.DeserializeBody(); if (newReview == null) return this.BadRequest(); + newReview.Text = CensorHelper.FilterMessage(newReview.Text); + if (newReview.Text.Length > 512) return this.BadRequest(); Review? review = await this.database.Reviews.FirstOrDefaultAsync(r => r.SlotId == slotId && r.ReviewerId == token.UserId); diff --git a/ProjectLighthouse.Servers.Website/Controllers/SlotPageController.cs b/ProjectLighthouse.Servers.Website/Controllers/SlotPageController.cs index a57b5d35..be7acb64 100644 --- a/ProjectLighthouse.Servers.Website/Controllers/SlotPageController.cs +++ b/ProjectLighthouse.Servers.Website/Controllers/SlotPageController.cs @@ -69,7 +69,9 @@ public class SlotPageController : ControllerBase return this.Redirect("~/slot/" + id); } + // Prevent potential xml injection and censor content msg = SanitizationHelper.SanitizeString(msg); + msg = CensorHelper.FilterMessage(msg); await this.database.PostComment(token.UserId, id, CommentType.Level, msg); Logger.Success($"Posted comment from {token.UserId}: \"{msg}\" on user {id}", LogArea.Comments); diff --git a/ProjectLighthouse.Servers.Website/Controllers/UserPageController.cs b/ProjectLighthouse.Servers.Website/Controllers/UserPageController.cs index fe30cfad..b05bc07b 100644 --- a/ProjectLighthouse.Servers.Website/Controllers/UserPageController.cs +++ b/ProjectLighthouse.Servers.Website/Controllers/UserPageController.cs @@ -43,7 +43,9 @@ public class UserPageController : ControllerBase return this.Redirect("~/user/" + id); } + // Prevent potential xml injection and censor content msg = SanitizationHelper.SanitizeString(msg); + msg = CensorHelper.FilterMessage(msg); await this.database.PostComment(token.UserId, id, CommentType.Profile, msg); Logger.Success($"Posted comment from {token.UserId}: \"{msg}\" on user {id}", LogArea.Comments); diff --git a/ProjectLighthouse.Servers.Website/Pages/Debug/FilterTestPage.cshtml.cs b/ProjectLighthouse.Servers.Website/Pages/Debug/FilterTestPage.cshtml.cs index 82d19226..40a68c5e 100644 --- a/ProjectLighthouse.Servers.Website/Pages/Debug/FilterTestPage.cshtml.cs +++ b/ProjectLighthouse.Servers.Website/Pages/Debug/FilterTestPage.cshtml.cs @@ -15,7 +15,7 @@ public class FilterTestPage : BaseLayout #if DEBUG public IActionResult OnGet(string? text = null) { - if (text != null) this.FilteredText = CensorHelper.ScanMessage(text); + if (text != null) this.FilteredText = CensorHelper.FilterMessage(text); this.Text = text; return this.Page(); diff --git a/ProjectLighthouse.Servers.Website/Pages/SlotSettingsPage.cshtml.cs b/ProjectLighthouse.Servers.Website/Pages/SlotSettingsPage.cshtml.cs index f4557ccc..1823b384 100644 --- a/ProjectLighthouse.Servers.Website/Pages/SlotSettingsPage.cshtml.cs +++ b/ProjectLighthouse.Servers.Website/Pages/SlotSettingsPage.cshtml.cs @@ -29,9 +29,11 @@ public class SlotSettingsPage : BaseLayout if (avatarHash != null) this.Slot.IconHash = avatarHash; name = SanitizationHelper.SanitizeString(name); + name = CensorHelper.FilterMessage(name); if (this.Slot.Name != name && name.Length <= 64) this.Slot.Name = name; description = SanitizationHelper.SanitizeString(description); + description = CensorHelper.FilterMessage(description); if (this.Slot.Description != description && description.Length <= 512) this.Slot.Description = description; labels = LabelHelper.RemoveInvalidLabels(SanitizationHelper.SanitizeString(labels)); diff --git a/ProjectLighthouse.Servers.Website/Pages/UserSettingsPage.cshtml.cs b/ProjectLighthouse.Servers.Website/Pages/UserSettingsPage.cshtml.cs index 882c12a0..75516bba 100644 --- a/ProjectLighthouse.Servers.Website/Pages/UserSettingsPage.cshtml.cs +++ b/ProjectLighthouse.Servers.Website/Pages/UserSettingsPage.cshtml.cs @@ -33,6 +33,7 @@ public class UserSettingsPage : BaseLayout if (avatarHash != null) this.ProfileUser.IconHash = avatarHash; biography = SanitizationHelper.SanitizeString(biography); + biography = CensorHelper.FilterMessage(biography); if (this.ProfileUser.Biography != biography && biography.Length <= 512) this.ProfileUser.Biography = biography; diff --git a/ProjectLighthouse/Configuration/CensorConfiguration.cs b/ProjectLighthouse/Configuration/CensorConfiguration.cs new file mode 100644 index 00000000..3b9e81ea --- /dev/null +++ b/ProjectLighthouse/Configuration/CensorConfiguration.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using LBPUnion.ProjectLighthouse.Types; +using YamlDotNet.Serialization; + +namespace LBPUnion.ProjectLighthouse.Configuration; + +public class CensorConfiguration : ConfigurationBase +{ + public override int ConfigVersion { get; set; } = 1; + public override string ConfigName { get; set; } = "censor.yml"; + public override bool NeedsConfiguration { get; set; } = false; + + public FilterMode UserInputFilterMode { get; set; } = FilterMode.None; + + public List FilteredWordList { get; set; } = new() + { + "cunt", + "fag", + "faggot", + "horny", + "kook", + "kys", + "loli", + "nigga", + "nigger", + "penis", + "pussy", + "retard", + "retarded", + "vagina", + "vore", + "restitched", + "h4h", + }; + + public override ConfigurationBase Deserialize(IDeserializer deserializer, string text) => deserializer.Deserialize(text); +} \ No newline at end of file diff --git a/ProjectLighthouse/Configuration/ServerConfiguration.cs b/ProjectLighthouse/Configuration/ServerConfiguration.cs index bc9bdec1..3c078d1f 100644 --- a/ProjectLighthouse/Configuration/ServerConfiguration.cs +++ b/ProjectLighthouse/Configuration/ServerConfiguration.cs @@ -1,5 +1,4 @@ using LBPUnion.ProjectLighthouse.Configuration.ConfigurationCategories; -using LBPUnion.ProjectLighthouse.Types; using YamlDotNet.Serialization; namespace LBPUnion.ProjectLighthouse.Configuration; @@ -12,7 +11,7 @@ public class ServerConfiguration : ConfigurationBase // This is so Lighthouse can properly identify outdated configurations and update them with newer settings accordingly. // If you are modifying anything here, this value MUST be incremented. // Thanks for listening~ - public override int ConfigVersion { get; set; } = 16; + public override int ConfigVersion { get; set; } = 17; public override string ConfigName { get; set; } = "lighthouse.yml"; public string WebsiteListenUrl { get; set; } = "http://localhost:10060"; @@ -32,8 +31,6 @@ public class ServerConfiguration : ConfigurationBase public bool CheckForUnsafeFiles { get; set; } = true; public bool LogChatFiltering { get; set; } = false; - public FilterMode UserInputFilterMode { get; set; } = FilterMode.None; - public AuthenticationConfiguration Authentication { get; set; } = new(); public CaptchaConfiguration Captcha { get; set; } = new(); public DigestKeyConfiguration DigestKey { get; set; } = new(); diff --git a/ProjectLighthouse/Helpers/CensorHelper.cs b/ProjectLighthouse/Helpers/CensorHelper.cs index ae5bc821..bcf364b7 100644 --- a/ProjectLighthouse/Helpers/CensorHelper.cs +++ b/ProjectLighthouse/Helpers/CensorHelper.cs @@ -18,15 +18,13 @@ public static class CensorHelper "UwU", "OwO", "uwu", "owo", "o3o", ">.>", "*pounces on you*", "*boops*", "*baps*", ":P", "x3", "O_O", "xD", ":3", ";3", "^w^", }; - private static readonly string[] censorList = ResourceHelper.ReadManifestFile("chatCensoredList.txt").Replace("\r", "").Split("\n"); - - public static string ScanMessage(string message) + public static string FilterMessage(string message) { - if (ServerConfiguration.Instance.UserInputFilterMode == FilterMode.None) return message; + if (CensorConfiguration.Instance.UserInputFilterMode == FilterMode.None) return message; - int profaneIndex = -1; + int profaneIndex; - foreach (string profanity in censorList) + foreach (string profanity in CensorConfiguration.Instance.FilteredWordList) do { profaneIndex = message.ToLower().IndexOf(profanity, StringComparison.Ordinal); @@ -45,7 +43,7 @@ public static class CensorHelper sb.Append(message.AsSpan(0, profanityIndex)); - switch (ServerConfiguration.Instance.UserInputFilterMode) + switch (CensorConfiguration.Instance.UserInputFilterMode) { case FilterMode.Random: for(int i = 0; i < profanityLength; i++) @@ -70,14 +68,7 @@ public static class CensorHelper case FilterMode.Asterisks: for(int i = 0; i < profanityLength; i++) { - if (message[i] == ' ') - { - sb.Append(' '); - } - else - { - sb.Append('*'); - } + sb.Append(message[i] == ' ' ? ' ' : '*'); } break; @@ -89,6 +80,8 @@ public static class CensorHelper } break; + case FilterMode.None: break; + default: throw new ArgumentOutOfRangeException(nameof(message)); } sb.Append(message.AsSpan(profanityIndex + profanityLength)); @@ -103,14 +96,10 @@ public static class CensorHelper string[] emailArr = email.Split('@'); string domainExt = Path.GetExtension(email); - string maskedEmail = string.Format("{0}****{1}@{2}****{3}{4}", - emailArr[0][0], - emailArr[0].Substring(emailArr[0].Length - 1), - emailArr[1][0], - emailArr[1] - .Substring(emailArr[1].Length - domainExt.Length - 1, - 1), - domainExt); + // Hides everything except the first and last character of the username and domain, preserves the domain extension (.net, .com) + string maskedEmail = $"{emailArr[0][0]}****{emailArr[0][^1..]}@{emailArr[1][0]}****{emailArr[1] + .Substring(emailArr[1].Length - domainExt.Length - 1, + 1)}{domainExt}"; return maskedEmail; } diff --git a/ProjectLighthouse/ProjectLighthouse.csproj b/ProjectLighthouse/ProjectLighthouse.csproj index 67407409..d8aa1260 100644 --- a/ProjectLighthouse/ProjectLighthouse.csproj +++ b/ProjectLighthouse/ProjectLighthouse.csproj @@ -46,10 +46,6 @@ Always - - - Always - diff --git a/ProjectLighthouse/chatCensoredList.txt b/ProjectLighthouse/chatCensoredList.txt deleted file mode 100644 index ebe0eb06..00000000 --- a/ProjectLighthouse/chatCensoredList.txt +++ /dev/null @@ -1,17 +0,0 @@ -cunt -fag -faggot -horny -kook -kys -loli -nigga -nigger -penis -pussy -retard -retarded -vagina -vore -restitched -h4h