mirror of
https://github.com/WWhiteDreamProject/wwdpublic.git
synced 2026-04-16 21:17:39 +03:00
## Mirror of PR #25908: [SS14-17313 Chatfactor: Chat Censorship Systems](https://github.com/space-wizards/space-station-14/pull/25908) from <img src="https://avatars.githubusercontent.com/u/10567778?v=4" alt="space-wizards" width="22"/> [space-wizards](https://github.com/space-wizards)/[space-station-14](https://github.com/space-wizards/space-station-14) ###### `bf98a6a8bb2a57fb149459d6b053eaaf6abc8cd7` PR opened by <img src="https://avatars.githubusercontent.com/u/732532?v=4" width="16"/><a href="https://github.com/FairlySadPanda"> FairlySadPanda</a> at 2024-03-07 12:13:16 UTC - merged at 2024-03-25 23:50:20 UTC --- PR changed 4 files with 576 additions and 0 deletions. The PR had the following labels: - Status: Needs Review --- <details open="true"><summary><h1>Original Body</h1></summary> > <!-- Please read these guidelines before opening your PR: https://docs.spacestation14.io/en/getting-started/pr-guideline --> > <!-- The text between the arrows are comments - they will not be visible on your PR. --> > > ## About the PR > Adds some systems to manage chat censorship: > > 1. No-op: does nothing > 2. SimpleCensor: a regex-free censor with a variety of rules to use > 3. RegexCensor: a censor that uses regex. > > This exposes a singleton backed by a builder pattern (ChatCensor) that is set up, probably during the code init phase, and then globally available for your censorship needs. > > ## Why / Balance > Partial fulfilment of #17313 > > ## Technical details > CE wants regex, CE gets regex > > Otherwise SimpleCensor is designed to be usable by people who don't want to faff with regex. > > This would be setup during server or client init, so would be driven by Cvars. > > ## Media > <!-- > PRs which make ingame changes (adding clothing, items, new features, etc) are required to have media attached that showcase the changes. > Small fixes/refactors are exempt. > Any media may be used in SS14 progress reports, with clear credit given. > > If you're unsure whether your PR will require media, ask a maintainer. > > Check the box below to confirm that you have in fact seen this (put an X in the brackets, like [X]): > --> > > - [x] I have added screenshots/videos to this PR showcasing its changes ingame, **or** this PR does not require an ingame showcase > > ## Breaking changes > nope > **Changelog** > nope </details> Co-authored-by: SimpleStation14 <Unknown>
163 lines
5.0 KiB
C#
163 lines
5.0 KiB
C#
using System.Text.Unicode;
|
|
using Content.Shared.Chat.V2.Moderation;
|
|
using NUnit.Framework;
|
|
|
|
namespace Content.Tests.Shared.Chat.V2.Moderation;
|
|
|
|
public sealed class SimpleCensorTests
|
|
{
|
|
[Test]
|
|
public void CanCensorASingleWord()
|
|
{
|
|
var sut = new SimpleCensor().WithCustomDictionary(["amogus"]);
|
|
var output = sut.Censor("hello amogus");
|
|
|
|
Assert.That(output, Is.EqualTo("hello ******"));
|
|
}
|
|
|
|
// Basics - use custom dictionary
|
|
|
|
[Test]
|
|
public void CanCensorMultipleWordInstances()
|
|
{
|
|
var sut= new SimpleCensor().WithCustomDictionary(["amogus"]);
|
|
var output = sut.Censor("amogus hello amogus");
|
|
|
|
Assert.That(output, Is.EqualTo("****** hello ******"));
|
|
}
|
|
|
|
[Test]
|
|
public void CanCensorMultipleWords()
|
|
{
|
|
var sut= new SimpleCensor().WithCustomDictionary(["amogus", "sus"]);
|
|
var output = sut.Censor("amogus hello sus");
|
|
|
|
Assert.That(output, Is.EqualTo("****** hello ***"));
|
|
}
|
|
|
|
[Test]
|
|
public void CanUseDifferentCensorSymbols()
|
|
{
|
|
var sut= new SimpleCensor().WithCustomDictionary(["amogus", "sus"]);
|
|
var output = sut.Censor("amogus hello sus", '#');
|
|
|
|
Assert.That(output, Is.EqualTo("###### hello ###"));
|
|
}
|
|
|
|
[Test]
|
|
public void CanCatchCapitalizedWords()
|
|
{
|
|
var sut= new SimpleCensor().WithCustomDictionary(["amogus", "sus"]);
|
|
var output = sut.Censor("AMOGUS hello SUS");
|
|
|
|
Assert.That(output, Is.EqualTo("****** hello ***"));
|
|
}
|
|
|
|
[Test]
|
|
public void CanCatchWordsWithSomeCaptialsInThem()
|
|
{
|
|
var sut= new SimpleCensor().WithCustomDictionary(["amogus", "sus"]);
|
|
var output = sut.Censor("AmoGuS hello SuS");
|
|
|
|
Assert.That(output, Is.EqualTo("****** hello ***"));
|
|
}
|
|
|
|
[Test]
|
|
public void CanCatchWordsHiddenInsideOtherWords()
|
|
{
|
|
var sut= new SimpleCensor().WithCustomDictionary(["amogus", "sus"]);
|
|
var output = sut.Censor("helamoguslo suspicious");
|
|
|
|
Assert.That(output, Is.EqualTo("hel******lo ***picious"));
|
|
}
|
|
|
|
// Sanitizing Leetspeak
|
|
|
|
[Test]
|
|
public void CanSanitizeLeetspeak()
|
|
{
|
|
var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithSanitizeLeetSpeak();
|
|
var output = sut.Censor("am0gu5 hello 5u5");
|
|
|
|
Assert.That(output, Is.EqualTo("****** hello ***"));
|
|
}
|
|
|
|
[Test]
|
|
public void SanitizingLeetspeakOnlyOccursWhenTheWordIsBlocked()
|
|
{
|
|
var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithSanitizeLeetSpeak();
|
|
var output = sut.Censor("he110");
|
|
|
|
Assert.That(output, Is.EqualTo("he110"));
|
|
}
|
|
|
|
[Test]
|
|
public void CanCatchLeetspeakReplacementsWithMoreThanOneLetter()
|
|
{
|
|
var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithSanitizeLeetSpeak();
|
|
var output = sut.Censor("am()gu5 hello 5u5");
|
|
|
|
Assert.That(output, Is.EqualTo("******* hello ***"));
|
|
}
|
|
|
|
// Sanitizing special characters
|
|
|
|
[Test]
|
|
public void DoesNotSanitizeOutUncensoredSpecialCharacters()
|
|
{
|
|
var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithSanitizeSpecialCharacters();
|
|
var output = sut.Censor("amogus!hello!sus");
|
|
|
|
Assert.That(output, Is.EqualTo("******!hello!***"));
|
|
}
|
|
|
|
[Test]
|
|
public void DoesSanitizeOutCensoredSpecialCharacters()
|
|
{
|
|
var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithSanitizeSpecialCharacters();
|
|
var output = sut.Censor("amo!gus hello s?us");
|
|
|
|
Assert.That(output, Is.EqualTo("***!*** hello *?**"));
|
|
}
|
|
|
|
// Unicode ranges
|
|
|
|
[Test]
|
|
public void SanitizesOutNonLatinCharaters()
|
|
{
|
|
var sut = new SimpleCensor().WithRanges([UnicodeRanges.BasicLatin, UnicodeRanges.Latin1Supplement]);
|
|
var output = sut.Censor("amogus Україна sus 日本");
|
|
|
|
Assert.That(output, Is.EqualTo("amogus sus "));
|
|
}
|
|
|
|
[Test]
|
|
public void SanitizesOutNonLatinOrCyrillicCharaters()
|
|
{
|
|
var sut = new SimpleCensor().WithRanges([UnicodeRanges.BasicLatin, UnicodeRanges.Latin1Supplement, UnicodeRanges.Cyrillic]);
|
|
var output = sut.Censor("amogus Україна sus 日本");
|
|
|
|
Assert.That(output, Is.EqualTo("amogus Україна sus "));
|
|
}
|
|
|
|
// False positives
|
|
[Test]
|
|
public void CanHandleFalsePositives()
|
|
{
|
|
var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithFalsePositives(["amogusus"]);
|
|
var output = sut.Censor("amogusus hello amogus hello sus");
|
|
|
|
Assert.That(output, Is.EqualTo("amogusus hello ****** hello ***"));
|
|
}
|
|
|
|
// False negatives
|
|
[Test]
|
|
public void CanHandleFalseNegatives()
|
|
{
|
|
var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithFalsePositives(["amogusus"]).WithFalseNegatives(["susamogusus"]);
|
|
var output = sut.Censor("susamogusus hello amogus hello sus amogusus");
|
|
|
|
Assert.That(output, Is.EqualTo("*********** hello ****** hello *** ********"));
|
|
}
|
|
}
|