Skip to content
Merged
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
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;
}
14 changes: 11 additions & 3 deletions srcs/commands/PrivmsgCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ 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()) {
channel->storeMessage("[" + sender->getNickname() + "] " + message);
channel->storeMessage("[" + sender->getNickname() + "] " + sanitizedMessage);
// Bot responds to !help
if (message == "!help") {
std::string helpMsg = ":BOT!bot@server PRIVMSG " + target + " :\nAvailable bot commands:\n!help\n!datenow\n!weather <location>\n!history\r\n";
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);
}