Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
2 changes: 2 additions & 0 deletions incs/ircserv.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
#define GRE "\e[1;32m"
#define YEL "\e[1;33m"

std::string sanitizeString(const std::string& input);

class ArgumentValidator {
public:
static void validate(int count, char** args);
Expand Down
75 changes: 64 additions & 11 deletions srcs/commands/NickCommand.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,39 @@
#include "../../incs/ircserv.hpp"
#include <sstream>

static const size_t MAX_NICKNAME_LENGTH = 9;


static bool isValidNicknameStart(char c);
static bool isValidNicknameChar(char c);
static bool isControlChar(char c);

static bool validateNickname(Server *server, const std::string &nickname, int clientFd) {
if (nickname.length() > MAX_NICKNAME_LENGTH) {
std::ostringstream oss;
oss << "432 * " << nickname << " :Nickname too long (max " << MAX_NICKNAME_LENGTH << " chars)\r\n";
server->SendToClient(clientFd, oss.str());
return false;
}

if (!isValidNicknameStart(nickname[0])) {
server->SendToClient(clientFd, "432 * " + nickname + " :Nickname must start with letter or special char\r\n");
return false;
}

for (size_t i = 0; i < nickname.length(); i++) {
if (!isValidNicknameChar(nickname[i])) {
if (isControlChar(nickname[i])) {
server->SendToClient(clientFd, "432 * " + nickname + " :Nickname contains invalid characters\r\n");
} else {
server->SendToClient(clientFd, "432 * " + nickname + " :Erroneous nickname\r\n");
}
return false;
}
}

return true;
}

void Parser::handleNick(Server *server, const std::string &nickname, int clientFd) {
Client* client = server->FindClientByFd(clientFd);
Expand All @@ -9,21 +44,39 @@ void Parser::handleNick(Server *server, const std::string &nickname, int clientF
return;
}

for (size_t i = 0; i < nickname.length(); i++) {
char c = nickname[i];
if (!isalnum(c) && c != '-' && c != '_' && c != '[' && c != ']' && c != '{' && c != '}' && c != '\\' && c != '|' && c != '`' && c != '^') {
server->SendToClient(clientFd, "432 * " + nickname + " :Erroneous nickname\r\n");
return;
}
std::string sanitizedNickname = sanitizeString(nickname);

if (!validateNickname(server, sanitizedNickname, clientFd)) {
return;
}

if (server->IsNicknameInUse(nickname)) {
server->SendToClient(clientFd, "433 * " + nickname + " :Nickname is already in use\r\n");
if (server->IsNicknameInUse(sanitizedNickname)) {
server->SendToClient(clientFd, "433 * " + sanitizedNickname + " :Nickname is already in use\r\n");
return;
}

client->SetNickname(nickname);
server->SendToClient(clientFd, "Nickname set to " + nickname + "\r\n");
std::string oldNickname = client->getNickname();
client->SetNickname(sanitizedNickname);

if (oldNickname.empty()) {
server->SendToClient(clientFd, "001 " + sanitizedNickname + " :Welcome to the IRC server\r\n");
} else {
server->SendToClient(clientFd, ":" + oldNickname + " NICK " + sanitizedNickname + "\r\n");
}

server->CheckClientAuthentication(client);
}
}

static bool isValidNicknameStart(char c) {
return isalpha(c) || c == '_' || c == '[' || c == '{' ||
c == '\\' || c == '|' || c == '`' || c == '^';
}

static bool isValidNicknameChar(char c) {
return isalnum(c) || c == '-' || c == '_' || c == '[' || c == ']' ||
c == '{' || c == '}' || c == '\\' || c == '|' || c == '`' || c == '^';
}

static bool isControlChar(char c) {
return c < 32 || c == 127;
}
12 changes: 10 additions & 2 deletions srcs/commands/PrivmsgCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ void Parser::handlePrivmsg(Server *server, const std::string &target, const std:
return;
}

std::string formattedMessage = ":" + sender->getNickname() + " PRIVMSG " + target + " :" + message + "\r\n";
std::string sanitizedMessage = sanitizeString(message);
std::string formattedMessage = ":" + sender->getNickname() + " PRIVMSG " + target + " :" + sanitizedMessage + "\r\n";
channel->broadcastMessage(formattedMessage, sender, server);
// Bot stores last 100 messages
if (channel->isBotActive()) {
Expand Down Expand Up @@ -88,7 +89,8 @@ void Parser::handlePrivmsg(Server *server, const std::string &target, const std:
return;
}

std::string formattedMessage = ":" + sender->getNickname() + " PRIVMSG " + target + " :" + message + "\r\n";
std::string sanitizedMessage = sanitizeString(message);
std::string formattedMessage = ":" + sender->getNickname() + " PRIVMSG " + target + " :" + sanitizedMessage + "\r\n";
server->SendToClient(recipient->GetFd(), formattedMessage);
}
}
Expand All @@ -109,6 +111,12 @@ bool isValidOperation(Server *server, Client *sender, const std::string &target,
server->SendToClient(clientFd, "412 :No text to send\r\n");
return false;
}

if (message.length() > 512) {
server->SendToClient(clientFd, "412 :Message too long (max 512 chars)\r\n");
return false;
}

return true;
}

Expand Down
14 changes: 11 additions & 3 deletions srcs/commands/UserCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,17 @@ void Parser::handleUser(Server *server, const std::string &username, const std::
return;
}

client->SetUsername(username);
client->SetRealname(realname);
server->SendToClient(clientFd, "Username set to " + username + "\r\n");
std::string sanitizedUsername = sanitizeString(username);
std::string sanitizedRealname = sanitizeString(realname);

if (sanitizedUsername.length() > 10) {
server->SendToClient(clientFd, "461 * USER :Username too long (max 10 chars)\r\n");
return;
}

client->SetUsername(sanitizedUsername);
client->SetRealname(sanitizedRealname);
server->SendToClient(clientFd, "Username set to " + sanitizedUsername + "\r\n");

server->CheckClientAuthentication(client);
}
33 changes: 32 additions & 1 deletion srcs/ircserv.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "../incs/ircserv.hpp"
#include <stdexcept>
#include <string>
#include <algorithm>
#include <cctype>

int main(int argc, char **argv) {
ServerController controller;
Expand All @@ -19,9 +21,17 @@ void ServerController::execute(int argc, char** argv) {

void ServerController::prepareExecution(int argc, char** argv) {
ArgumentValidator::validate(argc, argv);

char* endptr;
long portValue = std::strtol(argv[1], &endptr, 10);
if (*endptr != '\0' || endptr == argv[1]) {
throw std::runtime_error("Porta deve ser um número válido.");
}

this->validatePort(static_cast<int>(portValue));
SignalConfigurator::configure();
introduce();
this->server.ServerInit(std::atoi(argv[1]), argv[2]);
this->server.ServerInit(static_cast<int>(portValue), argv[2]);
}

void ServerController::validatePort(int portValue) {
Expand All @@ -34,6 +44,11 @@ void ArgumentValidator::validate(int count, char** args) {
if (count != 3) {
throw std::runtime_error("Uso: " + std::string(args[0]) + " <porta> <senha>");
}

std::string password(args[2]);
if (password.empty() || password.find_first_not_of(" \t\r\n") == std::string::npos) {
throw std::runtime_error("Senha não pode estar vazia.");
}
}

void SignalConfigurator::configure() {
Expand All @@ -48,4 +63,20 @@ void ServerController::handleError(const std::exception& e) {

void ServerController::announceShutdown() {
std::cout << "O Servidor Foi Fechado!" << std::endl;
}

bool isControlChar(char c) {
return c < 32 || c == 127;
}

std::string sanitizeString(const std::string& input) {
std::string result = input;

result.erase(std::remove_if(result.begin(), result.end(), isControlChar), result.end());

if (result.length() > 512) {
result = result.substr(0, 512);
}

return (result);
}