Files
rust-ipam/src/models.rs
mathieu 4e9eab0450 feat(models): add domain structs and CIDR validation
Add shared models (Network, Host, Port, Application, ApplicationPort)
with serde derives for Leptos server function serialization.
Add server/validation.rs with valider_ip_dans_reseau() and 5 unit tests.
Gate SSR-only modules (config, validation) with #[cfg(feature = "ssr")].

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 19:48:52 +02:00

135 lines
5.8 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// models.rs — Modèles de données partagés (server + client)
//
// Ce module définit les structs qui représentent les entités métier du projet IPAM.
// Ils sont compilés côté serveur ET côté WASM car Leptos en a besoin des deux côtés :
// - Serveur : pour lire/écrire en BDD et rendre le HTML
// - Client : pour afficher les données dans les composants Leptos
//
// Chaque struct dérive `Serialize` et `Deserialize` de serde.
// C'est obligatoire pour que Leptos puisse transférer les données entre
// le serveur et le navigateur via les "server functions" (#[server]).
use serde::{Deserialize, Serialize};
// ─── Réseau ───────────────────────────────────────────────────────────────────
/// Un réseau IP défini par sa plage CIDR.
///
/// Exemple : { id: 1, cidr: "192.168.1.0/24" }
/// → plage de 192.168.1.0 à 192.168.1.255 (254 hôtes utilisables)
///
/// La notation CIDR (Classless Inter-Domain Routing) combine l'adresse réseau
/// et le masque en un seul champ : <adresse>/<longueur du préfixe>.
/// /24 = 24 bits de masque = 255.255.255.0
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Network {
/// Identifiant unique auto-incrémenté par la base de données.
/// `i64` est le type entier signé 64 bits — correspond à `BIGINT` en SQL.
pub id: i64,
/// Plage d'adresses en notation CIDR.
/// Ex: "10.0.0.0/8", "172.16.0.0/12", "192.168.1.0/24"
pub cidr: String,
}
// ─── Hôte ─────────────────────────────────────────────────────────────────────
/// Un hôte (machine, serveur, équipement réseau) appartenant à un réseau.
///
/// Contrainte : l'IP doit appartenir à la plage CIDR du réseau référencé
/// par `network_id`. Cette contrainte est vérifiée à la création/modification.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Host {
pub id: i64,
/// Nom descriptif de l'hôte. Ex: "serveur-web-01", "routeur-principal"
pub name: String,
/// Adresse IPv4 de l'hôte, stockée en texte.
/// Ex: "192.168.1.10"
/// On utilise String plutôt que IpAddr pour simplifier la sérialisation
/// et le stockage en base de données.
pub ip: String,
/// Référence vers le réseau auquel appartient cet hôte.
/// C'est une "clé étrangère" (Foreign Key) vers la table `networks`.
pub network_id: i64,
}
// ─── Port ─────────────────────────────────────────────────────────────────────
/// Un port réseau ouvert sur un hôte, avec sa description probable.
///
/// Les numéros de ports standards (01023) sont des "well-known ports".
/// Un port peut être associé à plusieurs applications (association non-stricte).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Port {
/// Numéro de port TCP/UDP.
/// `u16` : entier non signé 16 bits → plage 0 à 65535.
/// C'est exactement la plage valide pour les ports réseau.
pub number: u16,
/// Description du protocole probable sur ce port.
/// `Option<String>` : peut être absent (None) si le protocole est inconnu.
/// Ex: Some("SSH"), Some("HTTPS"), None
pub description: Option<String>,
/// Hôte sur lequel ce port est ouvert.
pub host_id: i64,
}
impl Port {
/// Retourne la description standard pour les ports les plus courants.
/// Utilisé pour pré-remplir la description lors de l'ajout d'un port.
///
/// `match` est l'équivalent Rust d'un switch/case, mais exhaustif :
/// le compilateur oblige à gérer tous les cas possibles.
pub fn protocole_connu(numero: u16) -> Option<&'static str> {
// `&'static str` : référence vers une chaîne qui vit toute la durée du programme
// (les littéraux de chaînes comme "SSH" sont stockés dans le binaire compilé)
match numero {
21 => Some("FTP"),
22 => Some("SSH"),
23 => Some("Telnet"),
25 => Some("SMTP"),
53 => Some("DNS"),
80 => Some("HTTP"),
110 => Some("POP3"),
143 => Some("IMAP"),
443 => Some("HTTPS"),
3306 => Some("MySQL"),
5432 => Some("PostgreSQL"),
6379 => Some("Redis"),
8080 => Some("HTTP alternatif"),
_ => None, // `_` est le pattern "tout le reste" (wildcard)
}
}
}
// ─── Application ──────────────────────────────────────────────────────────────
/// Une application qui utilise un ou plusieurs ports.
///
/// L'association entre application et port est non-stricte :
/// un même port peut être partagé par plusieurs applications.
/// Ex: le port 80 peut être utilisé par Nginx ET par un proxy applicatif.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Application {
pub id: i64,
/// Nom de l'application. Ex: "Nginx", "PostgreSQL", "Prometheus"
pub name: String,
}
// ─── Association Application ↔ Port ──────────────────────────────────────────
/// Lien entre une application et un port (relation many-to-many).
///
/// On utilise un struct dédié plutôt qu'un Vec<Port> dans Application
/// pour correspondre directement à la table de jointure en base de données.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApplicationPort {
pub application_id: i64,
pub port_number: u16,
}