Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dev #23

Merged
merged 6 commits into from
Mar 29, 2024
Merged

dev #23

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions http-client.env.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"dev": {
"development": {
"HostAddress": "http://localhost:8080"
},
"remote": {
"production": {
"HostAddress": "https://webchat.iugmali.com"
}
}
22 changes: 20 additions & 2 deletions http-client.http
Original file line number Diff line number Diff line change
@@ -1,26 +1,44 @@
# Guarantee that every request redirects to '/'
# Testes de endpoints - rodar em IDE
# Rodar com env development e production

# Deve retornar 200 e html
GET {{HostAddress}}

###

# Deve retornar 200 e html
POST {{HostAddress}}

###

# Deve retornar 302 Found - Redirecting to /
PATCH {{HostAddress}}

###

# Deve retornar 200 e html
DELETE {{HostAddress}}

###

# Deve retornar 200 e html
POST {{HostAddress}}/somegibberishinformation/anothergibberishinformation

###

POST {{HostAddress}}/checkuserexists
# Deve retornar 400 - não é nome válido
POST {{HostAddress}}/usercheck
Content-Type: application/json

{
"username": "shit"
}

###

# Deve retornar 204 caso não exista um usuário com o nome logado
# Deve retornar 403 caso exista um usuário com o nome logado
POST {{HostAddress}}/usercheck
Content-Type: application/json

{
Expand Down
15 changes: 9 additions & 6 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { createServer } from 'node:http';
import { Server } from "socket.io";

import { engine } from "express-handlebars";
import {censorWord} from "./lib/util.js";
import {censorWord, isProfane} from "./lib/util.js";

const __dirname = dirname(fileURLToPath(import.meta.url));

Expand All @@ -16,6 +16,7 @@ const io = new Server(server);
type Message = {
author: string;
message: string;
color?: string;
}

type User = {
Expand All @@ -38,8 +39,8 @@ app.use(express.static(join(__dirname, 'public')));
io.on('connection', (socket) => {
socket.on('join', (username: string) => {
message = {author: 'iugmali-webchat-server', message: `${username} entrou na sala` };
io.emit('message', message);
io.emit('join', username);
socket.broadcast.emit('message', message);
socket.broadcast.emit('join', username);
users.add({id: socket.id, username: username});
const usersQty = io.engine.clientsCount
io.emit('usersQty', usersQty);
Expand Down Expand Up @@ -72,16 +73,18 @@ app.get('/', (req, res) => {
res.render('index', { title: 'Chat' });
});

app.post('/checkuserexists', (req, res) => {
app.post('/usercheck', (req, res) => {
const { username } = req.body;
const userExists = Array.from(users).find(user => {
const regex = new RegExp(`^${username}$`, 'i');
return regex.test(user.username);
});
if (userExists) {
if (!userExists && !isProfane(username)) {
res.status(204).send();
} else if (isProfane(username)) {
res.status(400).send();
} else {
res.status(200).send();
res.status(403).send();
}
});

Expand Down
18 changes: 6 additions & 12 deletions src/lib/data/bad-words.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,6 @@ export default [
'semen',
'sex',
'sexy',
'Sh!t',
'sh1t',
'sh1ter',
'sh1ts',
Expand Down Expand Up @@ -278,14 +277,12 @@ export default [
'hore',
'jism',
'kawk',
'l3itch',
'l3i+ch',
'lesbian',
'masturbate',
'masterbat',
'masterbat3',
'motherfucker',
's.o.b.',
'sob.',
'mofo',
'nazi',
'nigga',
Expand All @@ -296,10 +293,7 @@ export default [
'pusse',
'pussy',
'scrotum',
'sh!t',
'shemale',
'shi+',
'sh!+',
'slut',
'smut',
'teets',
Expand Down Expand Up @@ -423,7 +417,6 @@ export default [
'schlampe',
'schmuck',
'screw',
'sh!t',
'sharmuta',
'sharmute',
'shipal',
Expand Down Expand Up @@ -505,7 +498,7 @@ export default [
'Cocaina',
'Coco',
'Cocô',
'Corna',
'Corniugmalia',
'Corno',
'Cornuda',
'Cornudo',
Expand Down Expand Up @@ -570,7 +563,7 @@ export default [
'Furnica',
'Furnicar',
'Furo',
'Furona',
'Furoiugmalina',
'Gaiata',
'Gaiato',
'Gay',
Expand Down Expand Up @@ -696,7 +689,7 @@ export default [
'Sapatão',
'Sifilis',
'Siririca',
'Shota',
'Shotiugmalia',
'Tarada',
'Tarado',
'Testuda',
Expand All @@ -716,7 +709,7 @@ export default [
'Veadao',
'Veado',
'Viada',
'V14d0',
'V14diugmali0',
'Viado',
'Viad0',
'V1ad0',
Expand All @@ -732,5 +725,6 @@ export default [
'Xoxota',
'Xana',
'Xaninha',
'iugmali-webchat-server',
'xxx',
]
5 changes: 5 additions & 0 deletions src/lib/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ export type FilteredWord = {
censored: boolean;
}

export const isProfane = (word: string): boolean => {
const profanity = new Profanity();
return profanity.isProfane(word);
}

export const censorWord = (word: string): FilteredWord => {
const profanity = new Profanity();
if (profanity.isProfane(word)) {
Expand Down
31 changes: 15 additions & 16 deletions src/public/js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ const socket = io();
const chatbox = document.getElementById('chatbox');
const users = document.getElementById('users');
const sendButton = document.getElementById('send');

let user;

Swal.fire({
title: 'Digite seu username',
title: 'Seu nome',
input: 'text',
inputValidator: (value) => {
return !value && 'Você precisa digitar um nome de usuário do github';
return !value && 'Você precisa digitar um nome';
},
inputAttributes: {
autocapitalize: 'off'
Expand All @@ -25,19 +26,17 @@ Swal.fire({
showLoaderOnConfirm: true,
preConfirm: async (login) => {
try {
const githubUrl = `
https://api.github.com/users/${login}
`;
const response = await fetch(githubUrl);
if (!response.ok) {
Swal.showValidationMessage(`Usuário não existe no github`);
} else {
const checkuserexists = await fetch('/checkuserexists', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({username: login})});
if (!checkuserexists.ok) {
Swal.showValidationMessage(`${login} já está conectado na sala`);
} else {
socket.emit('join', login);
}
const response = await fetch('/usercheck', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({username: login})
});
if (response.status === 204) {
socket.emit('join', login);
} else if (response.status === 400) {
Swal.showValidationMessage(`${login} não é um nome válido`);
} else if (response.status === 403) {
Swal.showValidationMessage(`${login} já está conectado na sala`);
}
} catch (error) {
Swal.showValidationMessage(error.message);
Expand Down Expand Up @@ -99,7 +98,7 @@ Swal.fire({
const messagesList = document.getElementById('messages');
const msgElem = document.createElement('div');
msgElem.className = 'message';
msgElem.innerHTML = message.author === 'iugmali-webchat-server' ? `<span class="system">${message.message}</span>` : `<a href="https://github.com/${message.author}"><strong>${message.author}:</strong></a> ${message.message}`;
msgElem.innerHTML = message.author === 'iugmali-webchat-server' ? `<span class="system">${message.message}</span>` : `<strong>${message.author}:</strong> ${message.message}`;
messagesList.appendChild(msgElem);
messagesList.scrollTop = messagesList.scrollHeight;
});
Expand Down
4 changes: 2 additions & 2 deletions src/services/profanity.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ describe("Profanity", () => {
const badWord = badWords[Math.floor(Math.random() * badWords.length)];
const censored = profanity.isProfane(badWord);
expect(censored).toBe(true);
const expectedCensored = '*'.repeat(badWord.length);
const expectedCensored = badWord[0] + '*'.repeat(badWord.length - 1);
expect(profanity.censor(badWord)).toBe(expectedCensored);
});
it("should maintain not profane words in a sentence", () => {
const badWord = badWords[Math.floor(Math.random() * badWords.length)];
const phrase = `This is a phrase with a ${badWord} in it`;
const expectedCensoredWord = '*'.repeat(badWord.length);
const expectedCensoredWord = badWord[0] + '*'.repeat(badWord.length - 1);
const expectedCensoredPhrase = `This is a phrase with a ${expectedCensoredWord} in it`;
expect(profanity.censor(phrase)).toBe(expectedCensoredPhrase);
});
Expand Down
27 changes: 7 additions & 20 deletions src/services/profanity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@ type Configuration = {
placeHolder?: string;
replaceRegex?: RegExp;
separatorRegex?: RegExp;
wordsList?: string[];
}

class Profanity {
private phrase!: string;
private phrase: string;
private config?: Configuration;
private readonly wordlist?: string[];
private censuredPhrase: string = '';
private readonly wordlist: string[] = wordlist;

constructor(inputStr: string = '', config?: Configuration) {
const configDefaults: Configuration = {
Expand All @@ -23,32 +22,23 @@ class Profanity {
replaceRegex: /[\w\-À-ž]/g,
separatorRegex: /[\w\-À-ž]+|[^\w\s]|\s+/g
};
this.phrase = !inputStr || inputStr.length < 1 ? '' : inputStr;
this.phrase = inputStr;
this.config = { ...configDefaults, ...config };
this.wordlist = wordlist;
}

private scan() {
if (this.phrase.length < 1) {
this.censuredPhrase = this.phrase;
return this;
}
const separatorRegex = this.config?.separatorRegex ?? /[\w\-À-ž]+|[^\w\s]|\s+/g;
this.censuredPhrase = this.phrase
.match(separatorRegex)
?.map((value) => {
return this.isProfane(value) ? this.censureWord(value) : value;
})
.reduce((current, next) => current + next, '');

.reduce((current, next) => current + next, '') as string;
return this;
}

censureWord(word: any) {
if (word === undefined) {
return;
}
return word.replace(this.config?.replaceRegex, this.config?.placeHolder);
censureWord(word: string) {
return word[0] + word.substring(1).replace(this.config?.replaceRegex!, this.config?.placeHolder!);
}

censor(str?: string) {
Expand All @@ -61,11 +51,8 @@ class Profanity {
}

isProfane(value: string) {
if (this.wordlist === undefined) {
return;
}
return this.wordlist.filter((word) => {
const regex = new RegExp(`\\b${word.replace(/([^\wÀ-ź])/, '')}\\b`, 'gi');
const regex = new RegExp(`\\b${word.replace(/([^\wÀ-ź\-])/, '')}\\b`, 'gi');
return regex.test(value);
}).length > 0;
}
Expand Down