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>
135 lines
5.8 KiB
Rust
135 lines
5.8 KiB
Rust
// 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 (0–1023) 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,
|
||
}
|