Add server-side text safety features - user input will now be checked… (#224)

* Add server-side text safety features - user input will now be checked against a known list of profanities (such as toyo). Filter mode can be adjusted in global config file between four levels according to desired level of punishment;

0 - None
1 - Asterisks
2 - Random Characters
3 - Furry

Fixes #34

* Remove unnecessary censors

* Add international list

* Handle spaces correctly (``w o r d`` would have been censored as ```********`` rather than ```* * * *``)

Remove whitespace at ends of words in censor list

* Remove letters from CensorHelper._randomCharacters

* Fix naming in CensorHelper

* Use AsSpan instead of Substr

* Restitching

* Extract FilterMode to new class

* Revert "Remove unnecessary censors"

This reverts commit e1c3b35acc.

Co-authored-by: jvyden <jvyden@jvyden.xyz>
This commit is contained in:
Logan Lowe 2022-03-09 14:50:07 -07:00 committed by GitHub
parent 79fd133093
commit 1d72481a5e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 1096 additions and 42 deletions

View file

@ -11,5 +11,10 @@
<option name="enabled" value="true" />
</CommitMessageValidationOverride>
</option>
<option name="commitMessageValidationEnabledOverride">
<BoolValueOverride>
<option name="enabled" value="true" />
</BoolValueOverride>
</option>
</component>
</project>

View file

@ -78,11 +78,15 @@ public class MessageController : ControllerBase
public async Task<IActionResult> Filter()
{
User? user = await this.database.UserFromGameRequest(this.Request);
if (user == null) return this.StatusCode(403, "");
string loggedText = await new StreamReader(this.Request.Body).ReadToEndAsync();
string response = await new StreamReader(this.Request.Body).ReadToEndAsync();
string scannedText = CensorHelper.ScanMessage(response);
Logger.Log($"{user.Username}: {loggedText}", LoggerLevelFilter.Instance);
return this.Ok(loggedText);
Logger.Log($"{user.Username}: {response} / {scannedText}", LoggerLevelFilter.Instance);
return this.Ok(scannedText);
}
}

View file

@ -0,0 +1,97 @@
using System;
using System.Text;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Settings;
namespace LBPUnion.ProjectLighthouse.Helpers;
public static class CensorHelper
{
private static readonly char[] randomCharacters =
{
'!', '@', '#', '$', '&', '%', '-', '_',
};
private static readonly string[] randomFurry =
{
"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").Split("\n");
public static string ScanMessage(string message)
{
if (ServerSettings.Instance.UserInputFilterMode == FilterMode.None) return message;
int profaneIndex = -1;
foreach (string profanity in censorList)
do
{
profaneIndex = message.ToLower().IndexOf(profanity, StringComparison.Ordinal);
if (profaneIndex != -1) message = Censor(profaneIndex, profanity.Length, message);
}
while (profaneIndex != -1);
return message;
}
private static string Censor(int profanityIndex, int profanityLength, string message)
{
StringBuilder sb = new();
char prevRandomChar = '\0';
sb.Append(message.AsSpan(0, profanityIndex));
switch (ServerSettings.Instance.UserInputFilterMode)
{
case FilterMode.Random:
for(int i = 0; i < profanityLength; i++)
lock(RandomHelper.random)
{
if (message[i] == ' ')
{
sb.Append(' ');
}
else
{
char randomChar = randomCharacters[RandomHelper.random.Next(0, randomCharacters.Length - 1)];
if (randomChar == prevRandomChar) randomChar = randomCharacters[RandomHelper.random.Next(0, randomCharacters.Length - 1)];
prevRandomChar = randomChar;
sb.Append(randomChar);
}
}
break;
case FilterMode.Asterisks:
for(int i = 0; i < profanityLength; i++)
{
if (message[i] == ' ')
{
sb.Append(' ');
}
else
{
sb.Append('*');
}
}
break;
case FilterMode.Furry:
lock(RandomHelper.random)
{
string randomWord = randomFurry[RandomHelper.random.Next(0, randomFurry.Length - 1)];
sb.Append(randomWord);
}
break;
}
sb.Append(message.AsSpan(profanityIndex + profanityLength));
return sb.ToString();
}
}

View file

@ -14,7 +14,6 @@ public static class HashHelper
{
// private static readonly SHA1 sha1 = SHA1.Create();
private static readonly SHA256 sha256 = SHA256.Create();
private static readonly Random random = new();
/// <summary>
/// Generates a specified amount of random bytes in an array.
@ -24,8 +23,12 @@ public static class HashHelper
public static IEnumerable<byte> GenerateRandomBytes(int count)
{
byte[] b = new byte[count];
random.NextBytes(b);
lock (RandomHelper.random)
{
RandomHelper.random.NextBytes(b);
}
return b;
}

View file

@ -0,0 +1,8 @@
using System;
namespace LBPUnion.ProjectLighthouse.Helpers;
public static class RandomHelper
{
public static readonly Random random = new();
}

View file

@ -0,0 +1,20 @@
using System;
using System.IO;
using System.Linq;
using Kettu;
using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Types.Settings;
namespace LBPUnion.ProjectLighthouse.Helpers;
public static class ResourceHelper
{
public static string readManifestFile(string fileName)
{
using Stream stream =
typeof(Program).Assembly.GetManifestResourceStream($"{typeof(Program).Namespace}.{fileName}");
using StreamReader reader = new(stream ?? throw new Exception("The assembly or manifest resource is null."));
return reader.ReadToEnd().Trim();
}
}

View file

@ -13,10 +13,10 @@ public static class VersionHelper
{
try
{
CommitHash = readManifestFile("gitVersion.txt");
Branch = readManifestFile("gitBranch.txt");
CommitHash = ResourceHelper.readManifestFile("gitVersion.txt");
Branch = ResourceHelper.readManifestFile("gitBranch.txt");
string remotesFile = readManifestFile("gitRemotes.txt");
string remotesFile = ResourceHelper.readManifestFile("gitRemotes.txt");
string[] lines = remotesFile.Split('\n');
@ -26,7 +26,7 @@ public static class VersionHelper
// linq is a serious and painful catastrophe but its useful so i'm gonna keep using it
Remotes = lines.Select(line => line.Split("\t")[1]).ToArray();
CommitsOutOfDate = readManifestFile("gitUnpushed.txt").Split('\n').Length;
CommitsOutOfDate = ResourceHelper.readManifestFile("gitUnpushed.txt").Split('\n').Length;
CanCheckForUpdates = true;
}
@ -55,14 +55,6 @@ public static class VersionHelper
}
}
private static string readManifestFile(string fileName)
{
using Stream stream = typeof(Program).Assembly.GetManifestResourceStream($"{typeof(Program).Namespace}.{fileName}");
using StreamReader reader = new(stream ?? throw new Exception("The assembly or manifest resource is null."));
return reader.ReadToEnd().Trim();
}
public static string CommitHash { get; set; }
public static string Branch { get; set; }
public static string FullVersion => $"{ServerStatics.ServerName} {Branch}@{CommitHash} {Build}";

View file

@ -12,53 +12,57 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3"/>
<PackageReference Include="DDSReader" Version="1.0.8-pre"/>
<PackageReference Include="Discord.Net.Webhook" Version="3.4.0"/>
<PackageReference Include="InfluxDB.Client" Version="3.3.0"/>
<PackageReference Include="JetBrains.Annotations" Version="2021.3.0"/>
<PackageReference Include="Kettu" Version="1.2.2"/>
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="6.0.2"/>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.2"/>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.2"/>
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
<PackageReference Include="DDSReader" Version="1.0.8-pre" />
<PackageReference Include="Discord.Net.Webhook" Version="3.4.0" />
<PackageReference Include="InfluxDB.Client" Version="3.3.0" />
<PackageReference Include="JetBrains.Annotations" Version="2021.3.0" />
<PackageReference Include="Kettu" Version="1.2.2" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="6.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.1"/>
<PackageReference Include="SharpZipLib" Version="1.3.3"/>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3"/>
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.1" />
<PackageReference Include="SharpZipLib" Version="1.3.3" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
</ItemGroup>
<ItemGroup>
<None Remove="gitVersion.txt"/>
<None Remove="gitVersion.txt" />
<EmbeddedResource Include="gitVersion.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
<None Remove="gitBranch.txt"/>
<None Remove="gitBranch.txt" />
<EmbeddedResource Include="gitBranch.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
<None Remove="gitRemotes.txt"/>
<None Remove="gitRemotes.txt" />
<EmbeddedResource Include="gitRemotes.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
<None Remove="gitUnpushed.txt"/>
<None Remove="gitUnpushed.txt" />
<EmbeddedResource Include="gitUnpushed.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
<None Remove="recent-activity.xml"/>
<None Remove="r.tar.gz"/>
<None Remove="chatCensoredList.txt" />
<EmbeddedResource Include="chatCensoredList.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
<None Remove="recent-activity.xml" />
<None Remove="r.tar.gz" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Migrations\20220301204930_AddEmailVerificationTokens.Designer.cs"/>
<Compile Remove="Migrations\20220301204930_AddEmailVerificationTokens.Designer.cs" />
</ItemGroup>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
<Exec Command="git describe --long --always --dirty --exclude=\* --abbrev=8 &gt; &quot;$(ProjectDir)/gitVersion.txt&quot;"/>
<Exec Command="git branch --show-current &gt; &quot;$(ProjectDir)/gitBranch.txt&quot;"/>
<Exec Command="git remote -v &gt; &quot;$(ProjectDir)/gitRemotes.txt&quot;"/>
<Exec Command="git log --branches --not --remotes --oneline &gt; &quot;$(ProjectDir)/gitUnpushed.txt&quot;"/>
<Exec Command="git describe --long --always --dirty --exclude=\* --abbrev=8 &gt; &quot;$(ProjectDir)/gitVersion.txt&quot;" />
<Exec Command="git branch --show-current &gt; &quot;$(ProjectDir)/gitBranch.txt&quot;" />
<Exec Command="git remote -v &gt; &quot;$(ProjectDir)/gitRemotes.txt&quot;" />
<Exec Command="git log --branches --not --remotes --oneline &gt; &quot;$(ProjectDir)/gitUnpushed.txt&quot;" />
</Target>
</Project>

View file

@ -0,0 +1,9 @@
namespace LBPUnion.ProjectLighthouse.Types;
public enum FilterMode
{
None,
Asterisks,
Random,
Furry,
}

View file

@ -5,6 +5,7 @@ using System.Text.Json;
using System.Text.Json.Serialization;
using JetBrains.Annotations;
using Kettu;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Logging;
namespace LBPUnion.ProjectLighthouse.Types.Settings;
@ -12,7 +13,7 @@ namespace LBPUnion.ProjectLighthouse.Types.Settings;
[Serializable]
public class ServerSettings
{
public const int CurrentConfigVersion = 24; // MUST BE INCREMENTED FOR EVERY CONFIG CHANGE!
public const int CurrentConfigVersion = 25; // MUST BE INCREMENTED FOR EVERY CONFIG CHANGE!
private static FileSystemWatcher fileWatcher;
static ServerSettings()
{
@ -144,6 +145,8 @@ public class ServerSettings
public bool BooingEnabled { get; set; } = true;
public FilterMode UserInputFilterMode { get; set; } = FilterMode.None;
public bool DiscordWebhookEnabled { get; set; }
public string DiscordWebhookUrl { get; set; } = "";

View file

@ -0,0 +1,909 @@
4r5e
5h1t
5hit
a55
anal
anus
ar5e
arrse
arse
ass
ass-fucker
asses
assfucker
assfukka
asshole
assholes
asswhole
a_s_s
b!tch
b00bs
b17ch
b1tch
ballbag
balls
ballsack
bastard
beastial
beastiality
bellend
bestial
bestiality
bi+ch
biatch
bitch
bitcher
bitchers
bitches
bitchin
bitching
bloody
blow job
blowjob
blowjobs
boiolas
bollock
bollok
boner
boob
boobs
booobs
boooobs
booooobs
booooooobs
breasts
buceta
bugger
bum
bunny fucker
butt
butthole
buttmunch
buttplug
c0ck
c0cksucker
carpet muncher
cawk
chink
cipa
cl1t
clit
clitoris
clits
cnut
cock
cock-sucker
cockface
cockhead
cockmunch
cockmuncher
cocks
cocksuck
cocksucked
cocksucker
cocksucking
cocksucks
cocksuka
cocksukka
cok
cokmuncher
coksucka
coon
cox
crap
cum
cummer
cumming
cums
cumshot
cunilingus
cunillingus
cunnilingus
cunt
cuntlick
cuntlicker
cuntlicking
cunts
cyalis
cyberfuc
cyberfuck
cyberfucked
cyberfucker
cyberfuckers
cyberfucking
d1ck
damn
dick
dickhead
dildo
dildos
dink
dinks
dirsa
dlck
dog-fucker
doggin
dogging
donkeyribber
doosh
duche
dyke
ejaculate
ejaculated
ejaculates
ejaculating
ejaculatings
ejaculation
ejakulate
f u c k
f u c k e r
f4nny
fridinator
fag
fagging
faggitt
faggot
faggs
fagot
fagots
fags
fanny
fannyflaps
fannyfucker
fanyy
fatass
fcuk
fcuker
fcuking
feck
fecker
felching
fellate
fellatio
fingerfuck
fingerfucked
fingerfucker
fingerfuckers
fingerfucking
fingerfucks
fistfuck
fistfucked
fistfucker
fistfuckers
fistfucking
fistfuckings
fistfucks
flange
fook
fooker
fuck
fucka
fucked
fucker
fuckers
fuckhead
fuckheads
fuckin
fucking
fuckings
fuckingshitmotherfucker
fuckme
fucks
fuckwhit
fuckwit
fudge packer
fudgepacker
fuk
fuker
fukker
fukkin
fuks
fukwhit
fukwit
fux
fux0r
f_u_c_k
gangbang
gangbanged
gangbangs
gaylord
gaysex
goatse
god-dam
god-damned
goddamn
goddamned
hardcoresex
hell
heshe
hoar
hoare
hoer
homo
hore
horniest
horny
hotsex
jack-off
jackoff
jap
jerk-off
jism
jiz
jizm
jizz
kawk
knob
knobead
knobed
knobend
knobhead
knobjocky
knobjokey
kock
kondum
kondums
kum
kummer
kumming
kums
kunilingus
kiunt
l3i+ch
l3itch
labia
lmfao
lust
lusting
m0f0
m0fo
m45terbate
ma5terb8
ma5terbate
masochist
master-bate
masterb8
masterbat*
masterbat3
masterbate
masterbation
masterbations
masturbate
mo-fo
mof0
mofo
mothafuck
mothafucka
mothafuckas
mothafuckaz
mothafucked
mothafucker
mothafuckers
mothafuckin
mothafucking
mothafuckings
mothafucks
mother fucker
motherfuck
motherfucked
motherfucker
motherfuckers
motherfuckin
motherfucking
motherfuckings
motherfuckka
motherfucks
muff
mutha
muthafecker
muthafuckker
muther
mutherfucker
n1gga
n1gger
nazi
nigg3r
nigg4h
nigga
niggah
niggas
niggaz
nigger
niggers
nob
nob jokey
nobhead
nobjocky
nobjokey
numbnuts
nutsack
orgasim
orgasims
orgasm
orgasms
p0rn
pawn
pecker
penis
penisfucker
phonesex
phuck
phuk
phuked
phuking
phukked
phukking
phuks
phuq
pigfucker
pimpis
piss
pissed
pisser
pissers
pisses
pissflaps
pissin
pissing
pissoff
poop
porn
porno
pornography
pornos
prick
pricks
pron
pube
pusse
pussi
pussies
pussy
pussys
rectum
restitched
retard
rimjaw
rimming
s hit
s.o.b.
sadist
schlong
screwing
scroat
scrote
scrotum
semen
sex
sh!+
sh!t
sh1t
shag
shagger
shaggin
shagging
shemale
shi+
shit
shitdick
shite
shited
shitey
shitfuck
shitfull
shithead
shiting
shitings
shits
shitted
shitter
shitters
shitting
shittings
shitty
skank
slut
shiftos
sluts
smegma
smut
snatch
son-of-a-bitch
spac
spunk
s_h_i_t
t1tt1e5
t1tties
teets
teez
testical
testicle
tit
titfuck
tits
titt
tittie5
tittiefucker
titties
tittyfuck
tittywank
titwank
toyo
tosser
turd
tw4t
twat
twathead
twatty
twunt
twunter
v14gra
v1gra
vagina
viagra
vulva
w00se
wang
wank
wanker
wanky
whoar
whore
willies
willy
xrated
xxx
asesinato
asno
bastardo
bollera
cabrón
caca
chupada
chupapollas
chupetón
concha
concha de tu madre
coño
coprofagía
culo
drogas
esperma
fiesta de salchichas
follador
follar
gilipichis
gilipollas
hacer una paja
haciendo el amor
heroína
hija de puta
hijaputa
hijo de puta
hijoputa
idiota
imbécil
infierno
jilipollas
kapullo
lameculos
maciza
macizorra
maldito
mamada
marica
maricón
mariconazo
martillo
mierda
orina
pedo
pendejo
pervertido
pezón
pinche
pis
prostituta
puta
racista
ramera
sádico
semen
sexo
sexo oral
soplagaitas
soplapollas
tetas grandes
tía buena
travesti
trio
verga
vete a la mierda
vulva
baiser
bander
bigornette
bite
bitte
bloblos
bordel
bourré
bourrée
brackmard
branlage
branler
branlette
branleur
branleuse
brouter le cresson
caca
chatte
chiasse
chier
chiottes
clito
clitoris
con
connard
connasse
conne
couilles
cramouille
cul
déconne
déconner
emmerdant
emmerder
emmerdeur
emmerdeuse
enculé
enculée
enculeur
enculeurs
enfoiré
enfoirée
étron
fille de pute
fils de pute
folle
foutre
gerbe
gerber
gouine
grande folle
grogniasse
gueule
jouir
la putain de ta mère
malpt
ménage à trois
merde
merdeuse
merdeux
meuf
nègre
nique ta mère
nique ta race
palucher
pédale
pédé
péter
pipi
pisser
pouffiasse
pousse-crotte
putain
pute
ramoner
sac à foutre
sac à merde
salaud
salope
suce
tapette
tanche
teuch
tringler
trique
troncher
trou du cul
turlute
zigounette
zizi
analritter
arsch
arschficker
arschlecker
arschloch
bimbo
bratze
bumsen
bonze
dödel
fick
ficken
flittchen
fotze
fratze
hackfresse
hure
hurensohn
ische
kackbratze
kacke
kacken
kackwurst
kampflesbe
kanake
kimme
lümmel
milf
möpse
morgenlatte
möse
mufti
muschi
nackt
neger
nippel
nutte
onanieren
orgasmus
penis
pimmel
pimpern
pinkeln
pissen
pisser
popel
poppen
porno
reudig
rosette
schabracke
schlampe
scheiße
scheisser
schiesser
schnackeln
schwanzlutscher
schwuchtel
tittchen
titten
vögeln
vollpfosten
wichse
wichsen
wichser
arsle
brutta
discofitta
dra åt helvete
fan
fitta
fittig
för helvete
helvete
hård
jävlar
knulla
kuk
kuksås
kötthuvud
köttnacke
moona
moonade
moonar
moonat
mutta
neger
olla
pippa
pitt
prutt
pök
runka
röv
rövhål
rövknulla
satan
skita
skit ner dig
skäggbiff
snedfitta
snefitta
stake
subba
sås
sätta på
tusan
asshole
dritt
drittsekk
faen
faen i helvete
fan
fanken
fitte
forbanna
forbannet
forjævlig
fuck
fy faen
føkk
føkka
føkkings
jævla
jævlig
helvete
helvetet
kuk
kukene
kuker
morraknuller
morrapuler
pakkis
pikk
pokker
ræva
ræven
satan
shit
sinnsykt
skitt
sotrør
ståpikk
ståpikkene
ståpikker
svartheiteste
bychara
byk
chernozhopyi
dolboy'eb
ebalnik
ebalo
ebalom sch'elkat
gol
mudack
opizdenet
osto'eblo
ostokhuitel'no
ot'ebis
otmudohat
otpizdit
otsosi
padlo
pedik
perdet
petuh
pidar gnoinyj
pizda
pizdato
pizdatyi
piz'det
pizdetc
pizdoi nakryt'sja
pizd'uk
piz`dyulina
podi ku'evo
poeben
po'imat' na konchik
po'iti posrat
po khuy
poluchit pizdy
pososi moyu konfetku
prissat
proebat
promudobl'adsksya pizdopro'ebina
propezdoloch
prosrat
raspeezdeyi
raspizdatyi
raz'yebuy
raz'yoba
s'ebat'sya
shalava
styervo
sukin syn
svodit posrat
svoloch
trakhat'sya
trimandoblydskiy pizdoproyob
ubl'yudok
uboy
u'ebitsche
vafl'a
vafli lovit
v pizdu
vyperdysh
vzdrochennyi
yeb vas
za'ebat
zaebis
zalupa
zalupat
zasranetc
zassat
zlo'ebuchy
бздёнок
блядки
блядовать
блядство
блядь
бугор
во пизду
встать раком
выёбываться
гандон
говно
говнюк
голый
дать пизды
дерьмо
дрочить
другой дразнится
ёбарь
ебать
ебать-копать
ебло
ебнуть
ёб твою мать
жопа
жополиз
играть на кожаной флейте
измудохать
каждый дрочит как он хочет
какая разница
как два пальца обоссать
курите мою трубку
лысого в кулаке гонять
малофья
манда
мандавошка
мент
муда
мудило
мудозвон
наебать
наебениться
наебнуться
на фиг
на хуй
на хую вертеть
на хуя
нахуячиться
невебенный
не ебет
ни за хуй собачу
ни хуя
обнаженный
обоссаться можно
один ебётся
опесдол
офигеть
охуеть
охуительно
половое сношение
секс
сиськи
спиздить
срать
ссать
траxать
ты мне ваньку не валяй
фига
хапать
хер с ней
хер с ним
хохол
хрен
хуёво
хуёвый
хуем груши околачивать
хуеплет
хуило
хуиней страдать
хуиня
хуй
хуйнуть
хуй пинать