diff --git a/README.md b/README.md
index fede52f9..b936ac41 100644
--- a/README.md
+++ b/README.md
@@ -9,14 +9,22 @@
█████ ░░█████ █████████ █████ █████ █████ ░░█████████
░░░░░ ░░░░░ ░░░░░░░░░ ░░░░░ ░░░░░ ░░░░░ ░░░░░░░░░
```
-Internet Relay Chat project at 42 (a text-based communication protocol on the Internet)
+
+This is the main repository for Internet Relay Chat project at School 42
    
---
+## IRC protocol
+
+IRC is a text-based communication protocol over TCP/IP. It was first published in 1988 through RFC 1459, updated in 2000 by RFC 2810-2813. An IRC v3 was even proposed later on, which we didn't follow in this project.
+
+Established as a a successor to the Bulletin Board Systems, it grew popular the 1990s, before giving way to proprietary messaging services such as ICQ or MSN.
+
+Yet IRC community remains alive, with IRCNet, Libera Chat or OFTC being today's most popular IRC networks.
-## ft_IRC - Subjet
+## Subjet
This project is about creating your own IRC server.
You are required to develop an IRC server using the C++ 98 standard.
@@ -27,140 +35,82 @@ Your executable will be run as follows: `./ircserv `
- Several IRC clients exist. You have to choose one of them as a reference. Your reference client will be used during the evaluation process.
- Communication between client and server has to be done via TCP/IP (v4 or v6).
### Features
-- authenticate, set a nickname, a username, join a channel, send and receive private messages using your reference client.
-- All the messages sent from one client to a channel have to be forwarded to every other client that joined the channel.
-- You must have operators and regular users.
-- Commands that are specific to channel operators:
- - KICK- Eject a client from the channel
- - INVITE- Invite a client to a channel
- - TOPIC- Change or view the channel topic
- - MODE- Change the channel’s mode:
- - i: Set/remove Invite-only channel
- - t: Set/remove the restrictions of the TOPIC command to channel operators
- - k: Set/remove the channel key (password)
- - o: Give/take channel operator privilege
- - l: Set/remove the user limit to channel
+- message forwarding
+- operator status
+- Registration and User related commands
+ - `PASS` Authenticate a client
+ - `NICK` Change client nickname
+ - `USER` Register username and real name
+- Messaging command
+ - `PRIVMSG` send a message to a client or a channel
+- Channel related commands (some of which might be reserved to channel operators):
+ - `JOIN` Enter a channel
+ - `KICK` Eject a client from the channel
+ - `INVITE` Invite a client to a channel
+ - `TOPIC` Change or view the channel topic
+ - `MODE` Change the channel’s mode with following options
+ - `k`: Set/remove the channel key (password)
+ - `i`: Set/remove Invite-only channel
+ - `l`: Set/remove the user limit to channel
+ - `t`: Set/remove the restrictions of the TOPIC command to channel operators
+ - `MODE` Also change user mode with
+ - `o`: Give/take channel operator privilege
### Bonus
- Handle file transfer.
-- bot.
+- Have a bot
+### Extra features
+We implemented extra commands not specifically asked in the subject
+- PART
+- QUIT
+- PING
+- WHO
+- MOTD (message of the day, sent on successful registration)
---
-## ft_IRC — Workflow de collaboration
-
-Ce dépôt est le dépôt principal du projet ft_IRC (école 42).
-Nous travaillons en équipe de 3 étudiants, chacun sur un fork personnel de ce dépôt.
-Toutes les contributions passent par des Pull Requests (PR) vers ce dépôt principal.
-
-### Organisation générale
-
-- `main` — branche stable, propre, toujours fonctionnelle.
-- `feature/...` — branches créées dans chaque fork pour développer une fonctionnalité.
-
-### Mise en place du dépôt local (une seule fois)
+## Collaboration workflow
-1. Forker le dépôt principal
-2. Cloner son fork personnel :
-```bash
-git clone git@github.com:MON-USERNAME/ft_IRC.git
-cd ft_IRC
-```
-3. Relier le dépôt principal en `upstream` :
-```bash
-git remote add upstream https://github.com/TON-USERNAME/ft_IRC.git
-```
-4. Vérifier :
-```bash
-git remote -v
-# doit montrer origin -> votre fork, et upstream -> dépôt principal
-```
-### Workflow de développement
-#### Créer une nouvelle fonctionnalité
-```bash
-# Se mettre à jour avant tout
-git checkout main
-git pull upstream main
-git push origin main
+- a main repository with individual forks
+- issues to define main features or fixes
+- each issue is worked upon on a dedicated branch
+- a `main` branch that feature branches must synchronize with and where PR are submitted to
+- we strived to follow basic commit message formatting
-# Créer une branche de fonctionnalité
-git checkout -b feature/ma_fonction
-```
+cf. [wiki](https://github.com/jmkko/ft_IRC/wiki/Workflow) for details
-#### Coder, puis :
-```bash
-git add .
-git commit -m "Ajoute ma_fonction"
-git push origin feature/ma_fonction
-```
-#### Créer une Pull Request (PR)
+## Quality and continuous integration workflow
-1. Aller sur GitHub → votre fork
-2. Sur votre branche → cliquer « Compare & pull request »
-3. Vérifier :
- - base : `TON-USERNAME/ft_IRC` → `main`
- - compare : `MON-USERNAME/ft_IRC` → `feature/ma_fonction`
-4. Créer la PR
+### Norm and format
-### Mettre à jour votre fork
+- using `clang-format`
+- based upon [LLVM coding rules](https://llvm.org/docs/CodingStandards.html))
-Avant de commencer une nouvelle fonctionnalité, synchronisez votre main local et votre fork :
-```bash
-git checkout main
-git pull upstream main
-git push origin main
-````
-### Conventions de code
+cf. [wiki](https://github.com/jmkko/ft_IRC/wiki/Norm) for details
-- Commits clairs et concis (présent)
- ✅ Ajoute la gestion du JOIN
- ❌ J'ai codé join
-- Branches : `feature/...` ou `fix/...`
-- Jamais coder sur main
-- Faire des PR petites et régulières
+### Static analysis
-### Tests
+- using `clang-tidy`
-We will strive to make different tests to prevent regressions while shipping new features.
-This part of the project is not meant to be evaluated.
-Therefore, we will use a more recent standard (c++20) and give a try at new features such as :
-- lambdas
-- introspection with type traits (ex: printing the name of an exception being thrown)
+cf. [wiki](https://github.com/jmkko/ft_IRC/wiki/Static-Analysis) for details
-Once implemented, each person implementing a new feature or a fix should be also responsible for the tests.
+### Testing
-- unit tests to check the output of a function, for normal and edge cases.
-- integration test, based on a basic client, to check that a command or series or command produces the expected output from the server.
+- a subproject `test` using c++20
+- integration tests to prevent regression
+- no unit tests (as they might be redundant with integration tests most of the time : projet is not that big)
-#### Assertions
+cf. [wiki](https://github.com/jmkko/ft_IRC/wiki/Testing) for details
-- `AssertUtils` contains utility functions to perform basic checks
+### Continuous integration
-#### Continuous integration and development
+- using Github Actions pipelines : one for build and static checks, one for testing
-If possible, we will try to add a Github Action workflow in order to check at each PR that
-- the projects compiles
-- the norm is respected (using a linter based on [LLVM code rules](https://llvm.org/docs/CodingStandards.html))
-- the codebase doesn't have potential bugs (using [CPPcheck](https://github.com/danmar/cppcheck), a static analysis checker)
+## Architecture
-### Résumé visuel
-```bash
- +-----------+
- | upstream |
- | (principal)|
- +-----+-----+
- ^
- |
- +---------+----------+
- | |
-+-----+-----+ +-----+-----+
-| fork 1 | | fork 2 |
-| membre A | | membre B |
-+-----------+ +-----------+
-```
+### Documentation
-✨ Important : toujours synchroniser `main` avant de créer une branche de feature.
----
+cf [Doxygen generated documentation](https://jmkko.github.io/ft_IRC/html/index.html)
-## ft_IRC — Stucture
+### UML Class diagram
```mermaid
---
@@ -389,136 +339,46 @@ classDiagram
---
-## ft_IRC - Compétences acquises
-
-Ce projet est un projet synthèse du tronc commun de 42 qui nous a permis de mener
-un travail en groupe et d'utiliser toutes les compétences apprises.
-
-- Projet en `C++` - Programmation orientée objet sur un projet complet
-- Projet réseau - TCP , Socket , poll
-- Protocol `IRC` - Syntaxe des messages
-- Les `design pattern` - Nous avons utiliser `Singleton` et `Fabric`
-- `Clang tidy` - Respect de règles de nommage et de qualité du code
-- `Github` - Nous avons utiliser toutes les services disponibles
- - `Fork` - Un repo principale + deux autres repos
- - `Actions - Lancement Compilation du projet, puis d'un testeur
- - `Rules` - Obligation d'avoir deux validation pour merge sur la main
- - `Projet` - Roadmap, Issue (avec branch pour chacune)
- - `Wiki`
- - `Pages` - pour notre Documentation `Doxygen`
-- `Doxygen` - Documentation automatique grace à des commentaires dans notre code
-- `Mardown` et `Mermaid` - pour notre README
+## Developed skills
+
+This project is a capstone for the 42 common core curriculum, allowing us to collaborate as a team and apply all the skills we’ve acquired throughout the program.
+
+| Skill/Tool | Description |
+|--------------------------|-----------------------------------------------------------------------------|
+|  | Object-oriented programming on a full-scale project |
+|  | TCP, Sockets, `poll` for event-driven I/O |
+|  | Message syntax and server-client communication |
+|  | Implemented `Singleton` and `Factory` patterns |
+|  | Code quality and naming conventions |
+|  | Full GitHub workflow: Forks, Actions, Rules, Projects, Wiki, and Pages |
+|  | Automatic documentation from code comments |
+|  | Structured documentation with embedded diagrams using `Mermaid` |
---
-## ft_IRC - Principales fonctions réseaux
-
-```c++
-/*
-Crée un socket avec les paramètres passés.
--family définit la famille du socket. Les valeurs principales sont AF_INET pour un socket IPv4, AF_INET6 pour un support IPv6.
--type spécifie le type de socket. Les valeurs principales utilisées sont SOCK_STREAM pour TCP, SOCK_DGRAM pour UDP.
--protocol définit le protocole à utiliser. Il sera dépendant du type de socket et de sa famille. Les valeurs principales sont IPPROTO_TCP pour un socket TCP, IPPROTO_UDP pour un socket UDP.
-*/
- int socket(int family, int type, int protocol);
-
- //close socket
- int close(int socket);
-//Les fonctions de cette forme sont les fonctions Host/Home to Network .
-//Elles servent à convertir les données numériques de la machine en données
-//« réseau ».
-short htons(short value);
-long htonl(long value);
-//Il s’agit des fonctions inverses des hton*.
-short ntohs(short value);
-long ntohl(long value);
- /*
- _socket est le socket à connecter.
-server la structure représentant le serveur auquel se connecter.
-serverlen est la taille de la structure server. socklen_t est un type spécifique aux plateformes UNIX et peut être un int ou unsigned int . Généralement un sizeof(server).
-
- L’appel à cette fonction est bloquant tant que la connexion n’a pas été effectuée. Autrement dit : si cette fonction retourne, c’est que votre connexion a été effectuée et acceptée par l’ordinateur distant. Sauf si elle retourne une erreur bien sûr.
-
- */
- int connect(int _socket, const struct sockaddr* server, socklen_t serverlen);
-
-//ex:
-sockaddr_in server;
-server.sin_addr.s_addr = inet_addr(const char* ipaddress);
-server.sin_family = AF_INET;
-server.sin_port = htons(int port);
-/*
-socket est le socket auquel envoyer les données.
-datas les données à envoyer.
-len est la taille maximale des données à envoyer en octets.
-flags un masque d'options. Généralement 0.
-*/
-int send(int socket, const void* datas, size_t len, int flags);
-int recv(int socket, void* buffer, size_t len, int flags);
-/*
-La fonction bind est utilisée pour assigner une adresse locale à un socket.
-
-sckt est le socket auquel est assigné l'adresse.
-name est la structure à assigner au socket.
-namelen est la taille de cette structure -> sizeof.
-Retourne SOCKET_ERROR -1 en cas d'erreur, 0 sinon.
-*/
-int bind(SOCKET sckt, const struct addr* name, int namelen);
-//ex
-sockaddr_in addr;
-addr.sin_addr.s_addr = INADDR_ANY; // indique que toutes les sources seront acceptées
-addr.sin_port = htons(port); // toujours penser à traduire le port en réseau
-addr.sin_family = AF_INET; // notre socket est TCP
-/*
-sckt est le socket auquel les clients vont se connecter.
-backlog est le nombre de connexions en attente qui peuvent être gérées. La valeur SOMAXCONN peut être utilisée pour laisser le système choisir une valeur correcte selon sa configuration.
-*/
-int listen(SOCKET sckt, int backlog) ;
-/*
-Accepte une connexion entrante.
-
-sckt est le socket serveur qui attend les connexions.
-addr recevra l'adresse du socket qui se connecte.
-addrlen est la taille de la structure pointée par addr.
-*/
-SOCKET accept(SOCKET sckt, struct sockaddr* addr, int* addrlen);
-/*
-Permet de récupérer l'adresse IP d'un socket, IPv4 ou IPv6, sous forme lisible.
-
-family est la famille du socket.
-src le pointeur vers l'adresse du socket.
-dst un pointeur vers un tampon où stocker l'adresse sous forme lisible.
-size la taille maximale du tampon.
-*/
-const char* inet_ntop(int family, const void* src, char* dst, socklen_t size);
-
-/*poll() permet de surveiller plusieurs file descriptors (sockets, fichiers, etc.)
-pour détecter quand ils sont prêts pour certaines opérations (lecture, écriture, erreur)
-sans bloquer. */
-#include
-int poll(struct pollfd *fds, nfds_t nfds, int timeout);
-
-struct pollfd {
- int fd; // File descriptor à surveiller
- short events; // Événements à surveiller (INPUT)
- short revents; // Événements qui se sont produits (OUTPUT)
-};
+## Main networking functions
+- socket creation and closure (`socket`)
+- network byte order conversion (`htons`, `ntohs`, `htonl`, `ntohl`)
+- connection management (`connect`, `bind`, `listen`, `accept`)
+- data transmission (`send`, `recv`)
+- event monitoring (`poll`)
-```
+cf. [wiki](https://github.com/jmkko/ft_IRC/wiki/Networking-functions) for details
---
-## ft_IRC - Source - Documentation
+## Sources
+### RFC
+[RFC-145912](https://www.rfc-editor.org/rfc/rfc1459)
[RFC-2812](https://www.rfc-editor.org/rfc/rfc2812)
-[Server TCP](https://bousk.developpez.com/cours/reseau-c++/TCP/01-premiers-pas/)
+### Networking functions
[Poll](https://devarea.com/linux-io-multiplexing-select-vs-poll-vs-epoll/)
[Network programing](https://beej.us/guide/bgnet/html/)
+[Server TCP](https://bousk.developpez.com/cours/reseau-c++/TCP/01-premiers-pas/)
+### Other interesting resources
[Serveur IRC](https://www.cs.cmu.edu/~srini/15-441/S10/project1/pj1_description.pdf)
[Projet IRC](http://chi.cs.uchicago.edu/chirc/index.html)
[Design Pattern](https://refactoring.guru/fr/design-patterns/singleton)
[Mermaid](https://mermaid.js.org/syntax/classDiagram.html)
-
-
-
diff --git a/includes/consts.hpp b/includes/consts.hpp
index 58f2e04c..b68f469c 100644
--- a/includes/consts.hpp
+++ b/includes/consts.hpp
@@ -32,8 +32,10 @@
#define FORBIDEN_CHAR_BOT_PROMPT "|;"
#define FORBIDEN_CHAR_CHAN_NAME "\x00\x07\x0D\x0A\x20\x2C\x3A" // NOLINT(clang-diagnostic-null-character)
#define FORBIDEN_CHAR_CHAN_KEY "\x00\x09\x0A\x0B\x0C\x0D\x20" // NOLINT(clang-diagnostic-null-character)
+#define FORBIDDEN_CHAR_SERVER_KEY "\x00\x09\x0A\x0B\x0D\x20" // NOLINT(clang-diagnostic-null-character) NUL, HT, LF, VT, CR, space
#define FORBIDEN_CHAR_USER "\x00\x0A\x0D\x20\x40" // NOLINT(clang-diagnostic-null-character)
#define NUMBER_FORB_CCNK 7
+#define NUMBER_FORB_CSK 6
#define NUMBER_FORB_CCU 5
#define VALID_CHAN_MODE_NOPARAM "\x69\x74"
#define VALID_CHAN_MODE_PARAM "\x6B\x6C\x6F"
diff --git a/includes/utils.hpp b/includes/utils.hpp
index 4a40c53a..510133e9 100644
--- a/includes/utils.hpp
+++ b/includes/utils.hpp
@@ -151,6 +151,7 @@ class Utils
static bool is_invalid_char_nick(char c);
static bool is_invalid_char_user(char c);
static bool is_invalid_char_key(char c);
+ static bool is_invalid_char_serverkey(char c);
static bool is_not_digit(char c);
}; // class utils
diff --git a/srcs/utils.cpp b/srcs/utils.cpp
index a023641c..41d3b34f 100644
--- a/srcs/utils.cpp
+++ b/srcs/utils.cpp
@@ -37,6 +37,13 @@ bool Utils::check_password(const std::string& s)
LOG_SERVER.warning(std::string("password must be ") + TO_STRING(MIN_PASSWORD_LEN) + " long at least");
return false;
}
+ for (std::string::const_iterator it = s.begin(); it != s.end(); ++it)
+ {
+ if (Utils::is_invalid_char_key(*it)) {
+ LOG_w_SERVER("password must contain only ASCII chars in range A-Z, a-z, 0-9, !@#$%^&*(), \%x01-05, \%x07-08, \%x0C, and \%x0E-1F");
+ return false;
+ }
+ }
return true;
}
@@ -127,4 +134,5 @@ bool Utils::is_not_alpha_or_specialbnf(char c) { return (!std::isalpha(c) && !Ut
bool Utils::is_invalid_char_nick(char c) { return (!std::isalnum(c) && !is_special_abnf(c)); }
bool Utils::is_invalid_char_user(char c) { return (is_char_of(c, std::string(FORBIDEN_CHAR_USER, NUMBER_FORB_CCU))); }
bool Utils::is_invalid_char_key(char c) { return (is_char_of(c, std::string(FORBIDEN_CHAR_CHAN_KEY, NUMBER_FORB_CCNK))); }
+bool Utils::is_invalid_char_serverkey(char c) { return (is_char_of(c, std::string(FORBIDDEN_CHAR_SERVER_KEY, NUMBER_FORB_CSK))); }
bool Utils::is_not_digit(char c) { return (!std::isdigit(c)); }