Compare commits

..

No commits in common. "a3ec75b86bb84614ed5d00c90f5d4f27271d9490" and "aa589ab64d1d22d178d0de68a814ef008fc07414" have entirely different histories.

7 changed files with 16 additions and 757 deletions

Binary file not shown.

View File

@ -73,12 +73,13 @@ export default function Detections() {
const totalCount = data?.total || 0; const totalCount = data?.total || 0;
const totalPages = Math.ceil(totalCount / ITEMS_PER_PAGE); const totalPages = Math.ceil(totalCount / ITEMS_PER_PAGE);
const { data: whitelistData } = useQuery<{ items: Whitelist[]; total: number }>({ // Fetch whitelist to check if IP is already whitelisted
queryKey: ["/api/whitelist", "all"], const { data: whitelistData } = useQuery<Whitelist[]>({
queryFn: () => fetch("/api/whitelist?limit=10000").then(r => r.json()), queryKey: ["/api/whitelist"],
}); });
const whitelistedIps = new Set(whitelistData?.items?.map(w => w.ipAddress) || []); // Create a Set of whitelisted IPs for fast lookup
const whitelistedIps = new Set(whitelistData?.map(w => w.ipAddress) || []);
// Mutation per aggiungere a whitelist // Mutation per aggiungere a whitelist
const addToWhitelistMutation = useMutation({ const addToWhitelistMutation = useMutation({

View File

@ -2,7 +2,7 @@
-- PostgreSQL database dump -- PostgreSQL database dump
-- --
\restrict m8BX2OAI4IqpPQYg9LDdkx9gw71E8mW7NhAoc6tFhxIWe7hPFxv4gky0SVxio2N \restrict bngYLsJZNRm4sGjAcrPW2v7ZwM0VwW8FjcxWfRcYzZDDKc2X525bYmyFEXzl1yh
-- Dumped from database version 16.11 (df20cf9) -- Dumped from database version 16.11 (df20cf9)
-- Dumped by pg_dump version 16.10 -- Dumped by pg_dump version 16.10
@ -387,5 +387,5 @@ ALTER TABLE ONLY public.public_blacklist_ips
-- PostgreSQL database dump complete -- PostgreSQL database dump complete
-- --
\unrestrict m8BX2OAI4IqpPQYg9LDdkx9gw71E8mW7NhAoc6tFhxIWe7hPFxv4gky0SVxio2N \unrestrict bngYLsJZNRm4sGjAcrPW2v7ZwM0VwW8FjcxWfRcYzZDDKc2X525bYmyFEXzl1yh

View File

@ -1,622 +0,0 @@
#!/usr/bin/env python3
"""Genera documento Word IDS - Conformità ISO 27001"""
from docx import Document
from docx.shared import Inches, Pt, Cm, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT
from datetime import datetime
doc = Document()
style = doc.styles['Normal']
font = style.font
font.name = 'Calibri'
font.size = Pt(11)
sections = doc.sections
for section in sections:
section.top_margin = Cm(2.5)
section.bottom_margin = Cm(2.5)
section.left_margin = Cm(2.5)
section.right_margin = Cm(2.5)
# --- COVER PAGE ---
for _ in range(6):
doc.add_paragraph("")
title = doc.add_paragraph()
title.alignment = WD_ALIGN_PARAGRAPH.CENTER
run = title.add_run("INTRUSION DETECTION SYSTEM (IDS)")
run.bold = True
run.font.size = Pt(28)
run.font.color.rgb = RGBColor(0, 51, 102)
subtitle = doc.add_paragraph()
subtitle.alignment = WD_ALIGN_PARAGRAPH.CENTER
run = subtitle.add_run("Documentazione Funzionale e Conformità ISO/IEC 27001:2022")
run.font.size = Pt(16)
run.font.color.rgb = RGBColor(51, 51, 51)
doc.add_paragraph("")
info = doc.add_paragraph()
info.alignment = WD_ALIGN_PARAGRAPH.CENTER
run = info.add_run("Sistema di Rilevamento Intrusioni per Router MikroTik\ncon Machine Learning e Blocco Automatico")
run.font.size = Pt(12)
run.font.color.rgb = RGBColor(100, 100, 100)
doc.add_paragraph("")
doc.add_paragraph("")
meta = doc.add_paragraph()
meta.alignment = WD_ALIGN_PARAGRAPH.CENTER
run = meta.add_run(f"Versione: 2.0.0\nData: {datetime.now().strftime('%d/%m/%Y')}\nClassificazione: Riservato")
run.font.size = Pt(11)
run.font.color.rgb = RGBColor(100, 100, 100)
doc.add_page_break()
# --- TABLE OF CONTENTS ---
doc.add_heading('Indice', level=1)
toc_items = [
"1. Introduzione e Scopo del Documento",
"2. Panoramica del Sistema IDS",
"3. Architettura del Sistema",
"4. Funzionalità del Sistema",
" 4.1 Raccolta e Analisi Log (Syslog)",
" 4.2 Rilevamento Anomalie con Machine Learning",
" 4.3 Blocco Automatico degli IP Malevoli",
" 4.4 Gestione Whitelist e Blacklist",
" 4.5 Liste Pubbliche e Threat Intelligence",
" 4.6 Dashboard e Monitoraggio in Tempo Reale",
" 4.7 Geolocalizzazione IP",
" 4.8 Gestione Router MikroTik",
" 4.9 Pulizia Automatica dei Dati",
" 4.10 Monitoraggio Servizi",
"5. Mappatura Controlli ISO/IEC 27001:2022",
"6. Controlli Annex A Coperti",
"7. Politiche di Sicurezza Implementate",
"8. Gestione degli Incidenti",
"9. Continuità Operativa e Disponibilità",
"10. Audit e Tracciabilità",
"11. Conclusioni",
]
for item in toc_items:
p = doc.add_paragraph(item)
p.paragraph_format.space_after = Pt(2)
doc.add_page_break()
# --- 1. INTRODUZIONE ---
doc.add_heading('1. Introduzione e Scopo del Documento', level=1)
doc.add_paragraph(
"Il presente documento descrive le funzionalità, l'architettura e le misure di sicurezza "
"implementate nel Sistema di Rilevamento Intrusioni (IDS) progettato per ambienti di rete "
"basati su router MikroTik. Lo scopo principale è fornire evidenza documentale della conformità "
"del sistema ai requisiti dello standard ISO/IEC 27001:2022, con particolare riferimento ai "
"controlli dell'Annex A relativi alla sicurezza delle reti, al monitoraggio, alla gestione "
"degli incidenti e alla protezione delle informazioni."
)
doc.add_paragraph(
"Questo documento è destinato a responsabili della sicurezza informatica, auditor interni "
"ed esterni, e al management aziendale coinvolto nel Sistema di Gestione della Sicurezza "
"delle Informazioni (SGSI/ISMS)."
)
# --- 2. PANORAMICA ---
doc.add_heading('2. Panoramica del Sistema IDS', level=1)
doc.add_paragraph(
"L'IDS è un sistema completo di sicurezza di rete che integra raccolta log in tempo reale, "
"analisi basata su Machine Learning, blocco automatico degli IP malevoli e monitoraggio "
"continuo dello stato della rete. Il sistema è progettato per operare in ambienti con "
"10+ router MikroTik e gestire volumi elevati di traffico (186M+ record di log di rete)."
)
doc.add_heading('Caratteristiche Principali', level=2)
features_main = [
"Rilevamento anomalie in tempo reale tramite Isolation Forest e classificatore ensemble",
"Blocco automatico degli IP con risk score >= 80 sui router MikroTik via REST API",
"Integrazione con feed di threat intelligence pubblici (Spamhaus, Talos, AWS, GCP, Microsoft Azure, Meta/Facebook, Cloudflare)",
"Dashboard web interattiva con visualizzazioni in tempo reale",
"Gestione whitelist/blacklist con supporto completo CIDR",
"Geolocalizzazione automatica degli IP rilevati",
"Sistema di pulizia automatica dei dati obsoleti",
"Monitoraggio continuo dei servizi di sistema",
]
for f in features_main:
doc.add_paragraph(f, style='List Bullet')
# --- 3. ARCHITETTURA ---
doc.add_heading('3. Architettura del Sistema', level=1)
doc.add_paragraph(
"Il sistema adotta un'architettura a microservizi composta da tre componenti principali:"
)
arch_table = doc.add_table(rows=5, cols=3)
arch_table.style = 'Light Grid Accent 1'
arch_table.alignment = WD_TABLE_ALIGNMENT.CENTER
headers = ['Componente', 'Tecnologia', 'Funzione']
for i, h in enumerate(headers):
arch_table.rows[0].cells[i].text = h
for paragraph in arch_table.rows[0].cells[i].paragraphs:
for run in paragraph.runs:
run.bold = True
arch_data = [
['Frontend Web', 'React, ShadCN UI, TanStack Query', 'Dashboard di monitoraggio, gestione whitelist/blacklist, visualizzazione rilevamenti'],
['Backend API', 'Node.js, Express, Drizzle ORM', 'API REST, gestione database PostgreSQL, coordinamento servizi'],
['Backend ML', 'Python, FastAPI, scikit-learn, XGBoost', 'Analisi anomalie con Isolation Forest e classificatore ensemble, blocco automatico IP'],
['Database', 'PostgreSQL', 'Persistenza dati: log di rete, rilevamenti, whitelist, blacklist, configurazione router'],
]
for i, row_data in enumerate(arch_data):
for j, cell_text in enumerate(row_data):
arch_table.rows[i+1].cells[j].text = cell_text
doc.add_paragraph("")
doc.add_paragraph(
"La comunicazione tra i componenti avviene tramite API REST protette da autenticazione "
"mediante API Key (header X-API-Key). Il database PostgreSQL è accessibile solo dai "
"backend tramite connessione autenticata."
)
# --- 4. FUNZIONALITÀ ---
doc.add_heading('4. Funzionalità del Sistema', level=1)
# 4.1
doc.add_heading('4.1 Raccolta e Analisi Log (Syslog)', level=2)
doc.add_paragraph(
"Il componente syslog_parser.py riceve i log syslog via protocollo UDP sulla porta 514 "
"da tutti i router MikroTik configurati. I log vengono analizzati, normalizzati e "
"memorizzati nel database PostgreSQL nella tabella network_logs."
)
doc.add_heading('Caratteristiche:', level=3)
syslog_features = [
"Ricezione syslog UDP sulla porta 514 (standard RFC 5424)",
"Parsing automatico dei messaggi syslog con estrazione di IP sorgente, destinazione, porte, protocollo",
"Auto-reconnect e recovery in caso di errori di connessione al database",
"Politica di retention dei dati: 3 giorni di conservazione dei log grezzi",
"Gestione di volumi elevati: oltre 186 milioni di record processati",
]
for f in syslog_features:
doc.add_paragraph(f, style='List Bullet')
# 4.2
doc.add_heading('4.2 Rilevamento Anomalie con Machine Learning', level=2)
doc.add_paragraph(
"Il cuore del sistema è il motore di Machine Learning che utilizza un approccio ibrido "
"per il rilevamento delle anomalie, combinando due algoritmi complementari per ridurre "
"i falsi positivi e migliorare l'accuratezza del rilevamento."
)
doc.add_heading('Algoritmi Utilizzati:', level=3)
ml_features = [
"Extended Isolation Forest (EIF): algoritmo non supervisionato per il rilevamento di anomalie basato sull'isolamento dei punti dati anomali. Analizza 25 feature di rete estratte dai log.",
"Classificatore Ensemble con Voting Pesato: combina XGBoost e altri classificatori per una classificazione più precisa delle anomalie rilevate.",
"Risk Score (0-100): ogni IP riceve un punteggio di rischio su scala 0-100 distribuito su 5 livelli (Normale <40, Basso 40-59, Medio 60-69, Alto 70-84, Critico >=85).",
"Retraining automatico settimanale del modello ML per adattarsi ai nuovi pattern di traffico.",
"Analisi ogni 2 minuti dei log dell'ultima ora per rilevamento near-real-time.",
]
for f in ml_features:
doc.add_paragraph(f, style='List Bullet')
doc.add_heading('Feature di Rete Analizzate (25 feature):', level=3)
doc.add_paragraph(
"Il modello analizza feature quali: frequenza delle connessioni per IP, distribuzione delle porte "
"di destinazione, rapporto pacchetti in/out, diversità dei protocolli, pattern temporali, "
"entropia delle connessioni, velocità di scansione porte, distribuzione geografica delle "
"connessioni, e altre metriche statistiche derivate dal traffico di rete."
)
# 4.3
doc.add_heading('4.3 Blocco Automatico degli IP Malevoli', level=2)
doc.add_paragraph(
"Gli IP identificati come critici (risk score >= 80) vengono automaticamente bloccati "
"su tutti i router MikroTik configurati tramite la REST API di RouterOS."
)
block_features = [
"Blocco automatico ogni 2 minuti per IP con risk score >= 80",
"Comunicazione con router MikroTik tramite REST API (HTTP/HTTPS)",
"Blocco parallelo su tutti i router abilitati contemporaneamente",
"Verifica whitelist prima del blocco (gli IP in whitelist non vengono mai bloccati)",
"Blocco massivo retroattivo: endpoint /block-all-critical per bloccare tutti gli IP critici storici non ancora bloccati",
"Sblocco manuale disponibile dalla dashboard web (pulsante 'Sblocca Router')",
"Auto-sblocco quando un IP viene aggiunto alla whitelist",
"Timeout configurabile per le regole di blocco sul router",
"Tracciamento dello stato di blocco nel database (campo blocked e blocked_at)",
]
for f in block_features:
doc.add_paragraph(f, style='List Bullet')
# 4.4
doc.add_heading('4.4 Gestione Whitelist e Blacklist', level=2)
doc.add_paragraph(
"Il sistema gestisce whitelist e blacklist con supporto completo per singoli IP e "
"range CIDR, utilizzando i tipi nativi INET/CIDR di PostgreSQL per un matching efficiente."
)
wl_features = [
"Whitelist manuale: aggiunta/rimozione IP dalla dashboard web con motivo e note",
"Blacklist automatica: alimentata da feed di threat intelligence pubblici",
"Supporto completo CIDR: matching di range di rete (es. 192.168.0.0/16) con operatori PostgreSQL <<=",
"Logica di priorità: Whitelist manuale > Whitelist pubblica > Blacklist",
"Auto-sblocco dai router quando un IP viene aggiunto alla whitelist",
"Paginazione server-side (50 record/pagina) e ricerca con debounce per performance",
"Campo source per tracciare l'origine di ogni entry (manuale, Spamhaus, AWS, ecc.)",
]
for f in wl_features:
doc.add_paragraph(f, style='List Bullet')
# 4.5
doc.add_heading('4.5 Liste Pubbliche e Threat Intelligence', level=2)
doc.add_paragraph(
"Il sistema integra automaticamente feed di threat intelligence da fonti pubbliche riconosciute, "
"sincronizzandoli ogni 10 minuti per mantenere aggiornate le liste di IP noti come malevoli "
"o appartenenti a provider cloud legittimi."
)
lists_table = doc.add_table(rows=8, cols=3)
lists_table.style = 'Light Grid Accent 1'
lists_table.alignment = WD_TABLE_ALIGNMENT.CENTER
list_headers = ['Feed', 'Tipo', 'Descrizione']
for i, h in enumerate(list_headers):
lists_table.rows[0].cells[i].text = h
for paragraph in lists_table.rows[0].cells[i].paragraphs:
for run in paragraph.runs:
run.bold = True
list_data = [
['Spamhaus DROP', 'Blacklist', "Lista di IP/CIDR noti per attività malevole (spam, botnet, C&C)"],
['Talos Intelligence', 'Blacklist', 'Feed di threat intelligence di Cisco Talos'],
['Amazon AWS', 'Whitelist', 'Range IP ufficiali dei servizi cloud AWS'],
['Google Cloud/GCP', 'Whitelist', 'Range IP ufficiali dei servizi Google Cloud'],
['Microsoft Azure', 'Whitelist', 'Range IP ufficiali dei servizi cloud Microsoft Azure'],
['Meta (Facebook)', 'Whitelist', 'Range IP di Meta (Facebook, Instagram, WhatsApp)'],
['Cloudflare', 'Whitelist', 'Range IP della CDN Cloudflare'],
]
for i, row_data in enumerate(list_data):
for j, cell_text in enumerate(row_data):
lists_table.rows[i+1].cells[j].text = cell_text
doc.add_paragraph("")
doc.add_paragraph(
"La merge logic applica una priorità basata sul tipo: gli IP in whitelist manuale hanno "
"sempre la precedenza, seguiti dalla whitelist pubblica e infine dalla blacklist. Questo "
"previene il blocco accidentale di servizi cloud legittimi."
)
# 4.6
doc.add_heading('4.6 Dashboard e Monitoraggio in Tempo Reale', level=2)
doc.add_paragraph(
"La dashboard web fornisce una visione completa e in tempo reale dello stato della "
"sicurezza di rete, con aggiornamento automatico ogni 10 secondi."
)
dash_features = [
"Panoramica generale: contatori di router attivi, rilevamenti totali, IP bloccati, IP critici",
"Pagina Rilevamenti: elenco paginato (50/pagina) con ricerca server-side su IP, paese, organizzazione",
"Pagina Whitelist: gestione paginata con ricerca e operazioni CRUD",
"Pagina Analytics: grafici e visualizzazioni del traffico normale vs attacco",
"Filtri avanzati: per tipo di anomalia (DDoS, Port Scan, Brute Force, Botnet), range di risk score",
"Indicatori visivi: badge colorati per livelli di rischio, stato di blocco, flag paese",
"Monitoraggio servizi: stato in tempo reale di ML Backend, Database, Syslog Parser",
"Operazioni dirette: pulsanti per aggiungere a whitelist, sbloccare router, avviare training ML",
]
for f in dash_features:
doc.add_paragraph(f, style='List Bullet')
# 4.7
doc.add_heading('4.7 Geolocalizzazione IP', level=2)
doc.add_paragraph(
"Integrazione con il servizio ip-api.com per arricchire ogni rilevamento con informazioni "
"geografiche e di rete, inclusi paese, città, ISP, numero AS e organizzazione. "
"Il sistema implementa caching intelligente per ridurre le chiamate API e rispettare i "
"rate limit del servizio."
)
# 4.8
doc.add_heading('4.8 Gestione Router MikroTik', level=2)
doc.add_paragraph(
"Il sistema comunica con i router MikroTik tramite la REST API di RouterOS, "
"supportando operazioni parallele su multipli router contemporaneamente."
)
router_features = [
"Configurazione router: IP, porta API, credenziali, abilitazione/disabilitazione",
"Test di connettività automatico",
"Supporto HTTP (porta 80) e HTTPS (porta 443) con gestione certificati SSL/TLS",
"Operazioni parallele su tutti i router (blocco/sblocco simultaneo)",
"Gestione address-list di firewall (aggiunta, rimozione, lettura)",
"Compatibilità con RouterOS 7.x e versioni successive",
]
for f in router_features:
doc.add_paragraph(f, style='List Bullet')
# 4.9
doc.add_heading('4.9 Pulizia Automatica dei Dati', level=2)
doc.add_paragraph(
"Un timer systemd orario esegue lo script cleanup_detections.py che:"
)
cleanup_features = [
"Rimuove rilevamenti più vecchi di 48 ore",
"Sblocca automaticamente gli IP bloccati da più di 2 ore",
"Mantiene la retention dei log di rete a 3 giorni",
"Registra statistiche di pulizia nei log di sistema",
]
for f in cleanup_features:
doc.add_paragraph(f, style='List Bullet')
# 4.10
doc.add_heading('4.10 Monitoraggio Servizi', level=2)
doc.add_paragraph(
"La dashboard fornisce monitoraggio in tempo reale dello stato dei servizi critici "
"con possibilità di riavvio tramite API protette."
)
service_features = [
"Monitoraggio stato: ML Backend, Database PostgreSQL, Syslog Parser",
"API per gestione servizi (start/stop/restart) protette da API Key",
"Integrazione con systemd per il controllo dei servizi Python",
"Health check endpoint (/health) per verifica rapida dello stato del sistema",
]
for f in service_features:
doc.add_paragraph(f, style='List Bullet')
# --- 5. MAPPATURA ISO 27001 ---
doc.add_heading('5. Mappatura Controlli ISO/IEC 27001:2022', level=1)
doc.add_paragraph(
"La seguente tabella mappa le funzionalità dell'IDS ai controlli dell'Annex A dello "
"standard ISO/IEC 27001:2022, evidenziando come il sistema contribuisce alla conformità."
)
iso_table = doc.add_table(rows=1, cols=4)
iso_table.style = 'Light Grid Accent 1'
iso_table.alignment = WD_TABLE_ALIGNMENT.CENTER
iso_headers = ['Controllo', 'Titolo', 'Funzionalità IDS', 'Copertura']
for i, h in enumerate(iso_headers):
iso_table.rows[0].cells[i].text = h
for paragraph in iso_table.rows[0].cells[i].paragraphs:
for run in paragraph.runs:
run.bold = True
iso_mappings = [
['A.5.1', 'Politiche per la sicurezza delle informazioni',
'Politiche di blocco automatico, soglie di rischio configurabili, logica di priorità whitelist/blacklist',
'Parziale'],
['A.5.7', 'Threat intelligence',
'Integrazione automatica con 7+ feed di threat intelligence (Spamhaus, Talos, AWS, GCP, Azure, Meta, Cloudflare)',
'Completa'],
['A.5.24', 'Pianificazione e preparazione della gestione degli incidenti',
'Rilevamento automatico anomalie, classificazione per livello di rischio, workflow di risposta automatizzato',
'Completa'],
['A.5.25', 'Valutazione e decisione sugli eventi di sicurezza',
'Risk scoring ML (0-100), classificazione automatica in 5 livelli, soglie configurabili',
'Completa'],
['A.5.26', 'Risposta agli incidenti di sicurezza',
'Blocco automatico IP critici sui router, sblocco manuale, gestione whitelist',
'Completa'],
['A.5.28', 'Raccolta delle evidenze',
'Log completi di tutte le operazioni, timestamp di rilevamento e blocco, geolocalizzazione',
'Completa'],
['A.8.1', 'Dispositivi endpoint utente',
'Protezione della rete tramite blocco IP malevoli a livello router (perimetrale)',
'Parziale'],
['A.8.9', 'Gestione della configurazione',
'Gestione centralizzata della configurazione dei router, migrazioni database versionante',
'Parziale'],
['A.8.15', 'Logging',
'Raccolta syslog centralizzata da tutti i router, retention 3 giorni, 186M+ record',
'Completa'],
['A.8.16', 'Attività di monitoraggio',
'Dashboard real-time, auto-refresh 10s, monitoraggio servizi, alert visivi per livelli di rischio',
'Completa'],
['A.8.20', 'Sicurezza delle reti',
'Firewall automatico via address-list MikroTik, blocco parallelo su tutti i router',
'Completa'],
['A.8.21', 'Sicurezza dei servizi di rete',
'Protezione contro DDoS, port scanning, brute force, botnet tramite rilevamento ML',
'Completa'],
['A.8.22', 'Segregazione delle reti',
'Supporto multi-router con configurazioni indipendenti, blocco selettivo per router',
'Parziale'],
['A.8.23', 'Filtraggio web',
'Blocco IP malevoli a livello di rete, integrazione blacklist/whitelist',
'Parziale'],
]
for mapping in iso_mappings:
row = iso_table.add_row()
for i, cell_text in enumerate(mapping):
row.cells[i].text = cell_text
# --- 6. CONTROLLI ANNEX A ---
doc.add_heading('6. Controlli Annex A Coperti - Dettaglio', level=1)
doc.add_heading('A.5.7 - Threat Intelligence', level=2)
doc.add_paragraph(
"Il sistema implementa un processo automatizzato di raccolta e integrazione di threat intelligence "
"da fonti pubbliche riconosciute a livello internazionale. La sincronizzazione avviene ogni 10 minuti "
"tramite il servizio ids-list-fetcher, che scarica, analizza e aggiorna le liste nel database. "
"La merge logic applica una gerarchia di priorità per evitare conflitti tra liste diverse."
)
doc.add_heading('A.5.24/25/26 - Gestione Incidenti', level=2)
doc.add_paragraph(
"Il ciclo di vita degli incidenti di sicurezza è gestito automaticamente:\n"
"1. RILEVAMENTO: Il modello ML analizza i log ogni 2 minuti e identifica anomalie\n"
"2. CLASSIFICAZIONE: Ogni anomalia riceve un risk score e viene categorizzata (DDoS, Port Scan, Brute Force, Botnet)\n"
"3. RISPOSTA: Gli IP con score >= 80 vengono bloccati automaticamente sui router\n"
"4. DOCUMENTAZIONE: Ogni evento viene registrato con timestamp, geolocalizzazione, score e stato di blocco\n"
"5. RISOLUZIONE: Pulizia automatica dopo 48 ore, sblocco dopo 2 ore, possibilità di whitelist manuale"
)
doc.add_heading('A.8.15/16 - Logging e Monitoraggio', level=2)
doc.add_paragraph(
"Il sistema fornisce capacità complete di logging e monitoraggio:\n"
"- Raccolta centralizzata dei log syslog da tutti i router via UDP:514\n"
"- Conservazione dei log per 3 giorni con retention policy automatica\n"
"- Dashboard di monitoraggio con aggiornamento ogni 10 secondi\n"
"- Monitoraggio dello stato dei servizi (ML Backend, Database, Syslog Parser)\n"
"- Visualizzazioni analitiche del traffico normale vs attacco\n"
"- Paginazione e ricerca server-side per gestire grandi volumi di dati"
)
# --- 7. POLITICHE DI SICUREZZA ---
doc.add_heading('7. Politiche di Sicurezza Implementate', level=1)
doc.add_heading('7.1 Autenticazione e Controllo Accessi', level=2)
sec_features = [
"API Key authentication (header X-API-Key) per tutti gli endpoint del backend ML",
"Credenziali router cifrate nel database",
"Connessioni database autenticate con credenziali separate",
"Supporto HTTPS/TLS per la comunicazione con i router MikroTik",
]
for f in sec_features:
doc.add_paragraph(f, style='List Bullet')
doc.add_heading('7.2 Protezione dei Dati', level=2)
data_features = [
"Database PostgreSQL con accesso autenticato",
"Retention policy automatica: 3 giorni per log, 48 ore per rilevamenti",
"Nessun dato sensibile esposto tramite API pubblica",
"Validazione input con schema Zod per prevenire injection",
"Query parametrizzate per prevenire SQL injection",
]
for f in data_features:
doc.add_paragraph(f, style='List Bullet')
doc.add_heading('7.3 Disponibilità e Resilienza', level=2)
avail_features = [
"Auto-reconnect del parser syslog in caso di disconnessione dal database",
"Timer systemd con restart automatico dei servizi in caso di failure",
"Health check endpoint per monitoraggio esterno",
"Architettura a microservizi: il failure di un componente non blocca gli altri",
]
for f in avail_features:
doc.add_paragraph(f, style='List Bullet')
# --- 8. GESTIONE INCIDENTI ---
doc.add_heading('8. Gestione degli Incidenti', level=1)
doc.add_heading('8.1 Workflow di Risposta Automatica', level=2)
doc.add_paragraph(
"Il sistema implementa un workflow di risposta automatica agli incidenti di sicurezza:"
)
incident_table = doc.add_table(rows=6, cols=3)
incident_table.style = 'Light Grid Accent 1'
incident_table.alignment = WD_TABLE_ALIGNMENT.CENTER
inc_headers = ['Fase', 'Azione', 'Tempistica']
for i, h in enumerate(inc_headers):
incident_table.rows[0].cells[i].text = h
for paragraph in incident_table.rows[0].cells[i].paragraphs:
for run in paragraph.runs:
run.bold = True
inc_data = [
['1. Raccolta', 'Ricezione log syslog da router MikroTik', 'Tempo reale (UDP)'],
['2. Analisi', 'Analisi ML con Isolation Forest + Ensemble', 'Ogni 2 minuti'],
['3. Classificazione', 'Assegnazione risk score e tipo anomalia', 'Automatica'],
['4. Risposta', 'Blocco automatico IP su tutti i router (score >= 80)', 'Immediato dopo analisi'],
['5. Documentazione', 'Registrazione con geolocalizzazione e timestamp', 'Automatica'],
]
for i, row_data in enumerate(inc_data):
for j, cell_text in enumerate(row_data):
incident_table.rows[i+1].cells[j].text = cell_text
doc.add_paragraph("")
doc.add_heading('8.2 Tipi di Anomalie Rilevate', level=2)
anomaly_table = doc.add_table(rows=6, cols=2)
anomaly_table.style = 'Light Grid Accent 1'
anomaly_table.alignment = WD_TABLE_ALIGNMENT.CENTER
anom_headers = ['Tipo', 'Descrizione']
for i, h in enumerate(anom_headers):
anomaly_table.rows[0].cells[i].text = h
for paragraph in anomaly_table.rows[0].cells[i].paragraphs:
for run in paragraph.runs:
run.bold = True
anom_data = [
['DDoS Attack', 'Attacco Distributed Denial of Service - elevato volume di traffico da singola sorgente'],
['Port Scanning', "Scansione sistematica delle porte per identificare servizi vulnerabili"],
['Brute Force', 'Tentativi ripetuti di autenticazione con credenziali diverse'],
['Botnet Activity', 'Traffico riconducibile a reti di dispositivi compromessi (C&C)'],
['Suspicious Activity', 'Comportamento anomalo non classificabile nelle categorie precedenti'],
]
for i, row_data in enumerate(anom_data):
for j, cell_text in enumerate(row_data):
anomaly_table.rows[i+1].cells[j].text = cell_text
# --- 9. CONTINUITÀ ---
doc.add_heading('9. Continuità Operativa e Disponibilità', level=1)
doc.add_paragraph(
"Il sistema è progettato per operare in modo continuo e autonomo, minimizzando "
"l'intervento manuale e garantendo la disponibilità del servizio di monitoraggio."
)
continuity_features = [
"Servizi gestiti da systemd con restart automatico in caso di failure (Restart=always)",
"Timer systemd per operazioni periodiche (analisi ML ogni 2 min, pulizia oraria, sync liste ogni 10 min)",
"Auto-reconnect del parser syslog in caso di perdita connessione al database",
"Architettura a microservizi: il failure del backend ML non blocca la raccolta log",
"Health check endpoint per integrazione con sistemi di monitoraggio esterni (Nagios, Zabbix, ecc.)",
"Database PostgreSQL con supporto a backup e recovery point-in-time",
"Migrazioni database versionante per aggiornamenti sicuri dello schema",
]
for f in continuity_features:
doc.add_paragraph(f, style='List Bullet')
# --- 10. AUDIT ---
doc.add_heading('10. Audit e Tracciabilità', level=1)
doc.add_paragraph(
"Il sistema mantiene traccia completa di tutte le operazioni per supportare attività "
"di audit e conformità:"
)
audit_features = [
"Log di tutti i rilevamenti con timestamp, risk score, tipo anomalia, geolocalizzazione",
"Registrazione delle operazioni di blocco/sblocco con timestamp (blocked_at)",
"Storico delle entry di whitelist con data di creazione e motivo",
"Log delle sincronizzazioni delle liste pubbliche con conteggio IP aggiunti/rimossi",
"Storico dei training del modello ML con parametri e risultati",
"Log di sistema via journald per tutti i servizi (accessibili con journalctl)",
"Database delle migrazioni con versioning per tracciare le modifiche allo schema",
]
for f in audit_features:
doc.add_paragraph(f, style='List Bullet')
# --- 11. CONCLUSIONI ---
doc.add_heading('11. Conclusioni', level=1)
doc.add_paragraph(
"Il Sistema di Rilevamento Intrusioni (IDS) implementa un insieme completo di controlli "
"di sicurezza che contribuiscono significativamente alla conformità con lo standard "
"ISO/IEC 27001:2022. In particolare, il sistema copre in modo completo i controlli "
"relativi a:"
)
conclusions = [
"Threat intelligence (A.5.7): integrazione automatica con 7+ feed pubblici",
"Gestione degli incidenti (A.5.24-A.5.28): workflow completo dalla rilevazione alla risoluzione",
"Logging e monitoraggio (A.8.15-A.8.16): raccolta centralizzata e dashboard real-time",
"Sicurezza delle reti (A.8.20-A.8.21): protezione attiva tramite blocco automatico",
]
for c in conclusions:
doc.add_paragraph(c, style='List Bullet')
doc.add_paragraph("")
doc.add_paragraph(
"Il sistema richiede integrazione con ulteriori controlli organizzativi, procedurali e "
"tecnici per una conformità completa allo standard ISO 27001, tra cui: politiche formali "
"documentate, formazione del personale, gestione degli asset, controllo degli accessi "
"fisici e logici, e processi di audit interno periodico."
)
doc.add_paragraph("")
p = doc.add_paragraph()
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
run = p.add_run("--- Fine del Documento ---")
run.font.color.rgb = RGBColor(128, 128, 128)
run.font.size = Pt(10)
# Save
output_path = "IDS_Conformita_ISO27001.docx"
doc.save(output_path)
print(f"Documento generato: {output_path}")

View File

@ -5,5 +5,4 @@ description = "Add your description here"
requires-python = ">=3.11" requires-python = ">=3.11"
dependencies = [ dependencies = [
"httpx>=0.28.1", "httpx>=0.28.1",
"python-docx>=1.2.0",
] ]

121
uv.lock
View File

@ -71,135 +71,16 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" },
] ]
[[package]]
name = "lxml"
version = "6.0.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/aa/88/262177de60548e5a2bfc46ad28232c9e9cbde697bd94132aeb80364675cb/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62", size = 4073426, upload-time = "2025-09-22T04:04:59.287Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/77/d5/becbe1e2569b474a23f0c672ead8a29ac50b2dc1d5b9de184831bda8d14c/lxml-6.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:13e35cbc684aadf05d8711a5d1b5857c92e5e580efa9a0d2be197199c8def607", size = 8634365, upload-time = "2025-09-22T04:00:45.672Z" },
{ url = "https://files.pythonhosted.org/packages/28/66/1ced58f12e804644426b85d0bb8a4478ca77bc1761455da310505f1a3526/lxml-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b1675e096e17c6fe9c0e8c81434f5736c0739ff9ac6123c87c2d452f48fc938", size = 4650793, upload-time = "2025-09-22T04:00:47.783Z" },
{ url = "https://files.pythonhosted.org/packages/11/84/549098ffea39dfd167e3f174b4ce983d0eed61f9d8d25b7bf2a57c3247fc/lxml-6.0.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8ac6e5811ae2870953390452e3476694196f98d447573234592d30488147404d", size = 4944362, upload-time = "2025-09-22T04:00:49.845Z" },
{ url = "https://files.pythonhosted.org/packages/ac/bd/f207f16abf9749d2037453d56b643a7471d8fde855a231a12d1e095c4f01/lxml-6.0.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5aa0fc67ae19d7a64c3fe725dc9a1bb11f80e01f78289d05c6f62545affec438", size = 5083152, upload-time = "2025-09-22T04:00:51.709Z" },
{ url = "https://files.pythonhosted.org/packages/15/ae/bd813e87d8941d52ad5b65071b1affb48da01c4ed3c9c99e40abb266fbff/lxml-6.0.2-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de496365750cc472b4e7902a485d3f152ecf57bd3ba03ddd5578ed8ceb4c5964", size = 5023539, upload-time = "2025-09-22T04:00:53.593Z" },
{ url = "https://files.pythonhosted.org/packages/02/cd/9bfef16bd1d874fbe0cb51afb00329540f30a3283beb9f0780adbb7eec03/lxml-6.0.2-cp311-cp311-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:200069a593c5e40b8f6fc0d84d86d970ba43138c3e68619ffa234bc9bb806a4d", size = 5344853, upload-time = "2025-09-22T04:00:55.524Z" },
{ url = "https://files.pythonhosted.org/packages/b8/89/ea8f91594bc5dbb879734d35a6f2b0ad50605d7fb419de2b63d4211765cc/lxml-6.0.2-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d2de809c2ee3b888b59f995625385f74629707c9355e0ff856445cdcae682b7", size = 5225133, upload-time = "2025-09-22T04:00:57.269Z" },
{ url = "https://files.pythonhosted.org/packages/b9/37/9c735274f5dbec726b2db99b98a43950395ba3d4a1043083dba2ad814170/lxml-6.0.2-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:b2c3da8d93cf5db60e8858c17684c47d01fee6405e554fb55018dd85fc23b178", size = 4677944, upload-time = "2025-09-22T04:00:59.052Z" },
{ url = "https://files.pythonhosted.org/packages/20/28/7dfe1ba3475d8bfca3878365075abe002e05d40dfaaeb7ec01b4c587d533/lxml-6.0.2-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:442de7530296ef5e188373a1ea5789a46ce90c4847e597856570439621d9c553", size = 5284535, upload-time = "2025-09-22T04:01:01.335Z" },
{ url = "https://files.pythonhosted.org/packages/e7/cf/5f14bc0de763498fc29510e3532bf2b4b3a1c1d5d0dff2e900c16ba021ef/lxml-6.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2593c77efde7bfea7f6389f1ab249b15ed4aa5bc5cb5131faa3b843c429fbedb", size = 5067343, upload-time = "2025-09-22T04:01:03.13Z" },
{ url = "https://files.pythonhosted.org/packages/1c/b0/bb8275ab5472f32b28cfbbcc6db7c9d092482d3439ca279d8d6fa02f7025/lxml-6.0.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:3e3cb08855967a20f553ff32d147e14329b3ae70ced6edc2f282b94afbc74b2a", size = 4725419, upload-time = "2025-09-22T04:01:05.013Z" },
{ url = "https://files.pythonhosted.org/packages/25/4c/7c222753bc72edca3b99dbadba1b064209bc8ed4ad448af990e60dcce462/lxml-6.0.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2ed6c667fcbb8c19c6791bbf40b7268ef8ddf5a96940ba9404b9f9a304832f6c", size = 5275008, upload-time = "2025-09-22T04:01:07.327Z" },
{ url = "https://files.pythonhosted.org/packages/6c/8c/478a0dc6b6ed661451379447cdbec77c05741a75736d97e5b2b729687828/lxml-6.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b8f18914faec94132e5b91e69d76a5c1d7b0c73e2489ea8929c4aaa10b76bbf7", size = 5248906, upload-time = "2025-09-22T04:01:09.452Z" },
{ url = "https://files.pythonhosted.org/packages/2d/d9/5be3a6ab2784cdf9accb0703b65e1b64fcdd9311c9f007630c7db0cfcce1/lxml-6.0.2-cp311-cp311-win32.whl", hash = "sha256:6605c604e6daa9e0d7f0a2137bdc47a2e93b59c60a65466353e37f8272f47c46", size = 3610357, upload-time = "2025-09-22T04:01:11.102Z" },
{ url = "https://files.pythonhosted.org/packages/e2/7d/ca6fb13349b473d5732fb0ee3eec8f6c80fc0688e76b7d79c1008481bf1f/lxml-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e5867f2651016a3afd8dd2c8238baa66f1e2802f44bc17e236f547ace6647078", size = 4036583, upload-time = "2025-09-22T04:01:12.766Z" },
{ url = "https://files.pythonhosted.org/packages/ab/a2/51363b5ecd3eab46563645f3a2c3836a2fc67d01a1b87c5017040f39f567/lxml-6.0.2-cp311-cp311-win_arm64.whl", hash = "sha256:4197fb2534ee05fd3e7afaab5d8bfd6c2e186f65ea7f9cd6a82809c887bd1285", size = 3680591, upload-time = "2025-09-22T04:01:14.874Z" },
{ url = "https://files.pythonhosted.org/packages/f3/c8/8ff2bc6b920c84355146cd1ab7d181bc543b89241cfb1ebee824a7c81457/lxml-6.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a59f5448ba2ceccd06995c95ea59a7674a10de0810f2ce90c9006f3cbc044456", size = 8661887, upload-time = "2025-09-22T04:01:17.265Z" },
{ url = "https://files.pythonhosted.org/packages/37/6f/9aae1008083bb501ef63284220ce81638332f9ccbfa53765b2b7502203cf/lxml-6.0.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e8113639f3296706fbac34a30813929e29247718e88173ad849f57ca59754924", size = 4667818, upload-time = "2025-09-22T04:01:19.688Z" },
{ url = "https://files.pythonhosted.org/packages/f1/ca/31fb37f99f37f1536c133476674c10b577e409c0a624384147653e38baf2/lxml-6.0.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a8bef9b9825fa8bc816a6e641bb67219489229ebc648be422af695f6e7a4fa7f", size = 4950807, upload-time = "2025-09-22T04:01:21.487Z" },
{ url = "https://files.pythonhosted.org/packages/da/87/f6cb9442e4bada8aab5ae7e1046264f62fdbeaa6e3f6211b93f4c0dd97f1/lxml-6.0.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:65ea18d710fd14e0186c2f973dc60bb52039a275f82d3c44a0e42b43440ea534", size = 5109179, upload-time = "2025-09-22T04:01:23.32Z" },
{ url = "https://files.pythonhosted.org/packages/c8/20/a7760713e65888db79bbae4f6146a6ae5c04e4a204a3c48896c408cd6ed2/lxml-6.0.2-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c371aa98126a0d4c739ca93ceffa0fd7a5d732e3ac66a46e74339acd4d334564", size = 5023044, upload-time = "2025-09-22T04:01:25.118Z" },
{ url = "https://files.pythonhosted.org/packages/a2/b0/7e64e0460fcb36471899f75831509098f3fd7cd02a3833ac517433cb4f8f/lxml-6.0.2-cp312-cp312-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:700efd30c0fa1a3581d80a748157397559396090a51d306ea59a70020223d16f", size = 5359685, upload-time = "2025-09-22T04:01:27.398Z" },
{ url = "https://files.pythonhosted.org/packages/b9/e1/e5df362e9ca4e2f48ed6411bd4b3a0ae737cc842e96877f5bf9428055ab4/lxml-6.0.2-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c33e66d44fe60e72397b487ee92e01da0d09ba2d66df8eae42d77b6d06e5eba0", size = 5654127, upload-time = "2025-09-22T04:01:29.629Z" },
{ url = "https://files.pythonhosted.org/packages/c6/d1/232b3309a02d60f11e71857778bfcd4acbdb86c07db8260caf7d008b08f8/lxml-6.0.2-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90a345bbeaf9d0587a3aaffb7006aa39ccb6ff0e96a57286c0cb2fd1520ea192", size = 5253958, upload-time = "2025-09-22T04:01:31.535Z" },
{ url = "https://files.pythonhosted.org/packages/35/35/d955a070994725c4f7d80583a96cab9c107c57a125b20bb5f708fe941011/lxml-6.0.2-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:064fdadaf7a21af3ed1dcaa106b854077fbeada827c18f72aec9346847cd65d0", size = 4711541, upload-time = "2025-09-22T04:01:33.801Z" },
{ url = "https://files.pythonhosted.org/packages/1e/be/667d17363b38a78c4bd63cfd4b4632029fd68d2c2dc81f25ce9eb5224dd5/lxml-6.0.2-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fbc74f42c3525ac4ffa4b89cbdd00057b6196bcefe8bce794abd42d33a018092", size = 5267426, upload-time = "2025-09-22T04:01:35.639Z" },
{ url = "https://files.pythonhosted.org/packages/ea/47/62c70aa4a1c26569bc958c9ca86af2bb4e1f614e8c04fb2989833874f7ae/lxml-6.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6ddff43f702905a4e32bc24f3f2e2edfe0f8fde3277d481bffb709a4cced7a1f", size = 5064917, upload-time = "2025-09-22T04:01:37.448Z" },
{ url = "https://files.pythonhosted.org/packages/bd/55/6ceddaca353ebd0f1908ef712c597f8570cc9c58130dbb89903198e441fd/lxml-6.0.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6da5185951d72e6f5352166e3da7b0dc27aa70bd1090b0eb3f7f7212b53f1bb8", size = 4788795, upload-time = "2025-09-22T04:01:39.165Z" },
{ url = "https://files.pythonhosted.org/packages/cf/e8/fd63e15da5e3fd4c2146f8bbb3c14e94ab850589beab88e547b2dbce22e1/lxml-6.0.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:57a86e1ebb4020a38d295c04fc79603c7899e0df71588043eb218722dabc087f", size = 5676759, upload-time = "2025-09-22T04:01:41.506Z" },
{ url = "https://files.pythonhosted.org/packages/76/47/b3ec58dc5c374697f5ba37412cd2728f427d056315d124dd4b61da381877/lxml-6.0.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:2047d8234fe735ab77802ce5f2297e410ff40f5238aec569ad7c8e163d7b19a6", size = 5255666, upload-time = "2025-09-22T04:01:43.363Z" },
{ url = "https://files.pythonhosted.org/packages/19/93/03ba725df4c3d72afd9596eef4a37a837ce8e4806010569bedfcd2cb68fd/lxml-6.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f91fd2b2ea15a6800c8e24418c0775a1694eefc011392da73bc6cef2623b322", size = 5277989, upload-time = "2025-09-22T04:01:45.215Z" },
{ url = "https://files.pythonhosted.org/packages/c6/80/c06de80bfce881d0ad738576f243911fccf992687ae09fd80b734712b39c/lxml-6.0.2-cp312-cp312-win32.whl", hash = "sha256:3ae2ce7d6fedfb3414a2b6c5e20b249c4c607f72cb8d2bb7cc9c6ec7c6f4e849", size = 3611456, upload-time = "2025-09-22T04:01:48.243Z" },
{ url = "https://files.pythonhosted.org/packages/f7/d7/0cdfb6c3e30893463fb3d1e52bc5f5f99684a03c29a0b6b605cfae879cd5/lxml-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:72c87e5ee4e58a8354fb9c7c84cbf95a1c8236c127a5d1b7683f04bed8361e1f", size = 4011793, upload-time = "2025-09-22T04:01:50.042Z" },
{ url = "https://files.pythonhosted.org/packages/ea/7b/93c73c67db235931527301ed3785f849c78991e2e34f3fd9a6663ffda4c5/lxml-6.0.2-cp312-cp312-win_arm64.whl", hash = "sha256:61cb10eeb95570153e0c0e554f58df92ecf5109f75eacad4a95baa709e26c3d6", size = 3672836, upload-time = "2025-09-22T04:01:52.145Z" },
{ url = "https://files.pythonhosted.org/packages/53/fd/4e8f0540608977aea078bf6d79f128e0e2c2bba8af1acf775c30baa70460/lxml-6.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9b33d21594afab46f37ae58dfadd06636f154923c4e8a4d754b0127554eb2e77", size = 8648494, upload-time = "2025-09-22T04:01:54.242Z" },
{ url = "https://files.pythonhosted.org/packages/5d/f4/2a94a3d3dfd6c6b433501b8d470a1960a20ecce93245cf2db1706adf6c19/lxml-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c8963287d7a4c5c9a432ff487c52e9c5618667179c18a204bdedb27310f022f", size = 4661146, upload-time = "2025-09-22T04:01:56.282Z" },
{ url = "https://files.pythonhosted.org/packages/25/2e/4efa677fa6b322013035d38016f6ae859d06cac67437ca7dc708a6af7028/lxml-6.0.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1941354d92699fb5ffe6ed7b32f9649e43c2feb4b97205f75866f7d21aa91452", size = 4946932, upload-time = "2025-09-22T04:01:58.989Z" },
{ url = "https://files.pythonhosted.org/packages/ce/0f/526e78a6d38d109fdbaa5049c62e1d32fdd70c75fb61c4eadf3045d3d124/lxml-6.0.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb2f6ca0ae2d983ded09357b84af659c954722bbf04dea98030064996d156048", size = 5100060, upload-time = "2025-09-22T04:02:00.812Z" },
{ url = "https://files.pythonhosted.org/packages/81/76/99de58d81fa702cc0ea7edae4f4640416c2062813a00ff24bd70ac1d9c9b/lxml-6.0.2-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb2a12d704f180a902d7fa778c6d71f36ceb7b0d317f34cdc76a5d05aa1dd1df", size = 5019000, upload-time = "2025-09-22T04:02:02.671Z" },
{ url = "https://files.pythonhosted.org/packages/b5/35/9e57d25482bc9a9882cb0037fdb9cc18f4b79d85df94fa9d2a89562f1d25/lxml-6.0.2-cp313-cp313-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:6ec0e3f745021bfed19c456647f0298d60a24c9ff86d9d051f52b509663feeb1", size = 5348496, upload-time = "2025-09-22T04:02:04.904Z" },
{ url = "https://files.pythonhosted.org/packages/a6/8e/cb99bd0b83ccc3e8f0f528e9aa1f7a9965dfec08c617070c5db8d63a87ce/lxml-6.0.2-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:846ae9a12d54e368933b9759052d6206a9e8b250291109c48e350c1f1f49d916", size = 5643779, upload-time = "2025-09-22T04:02:06.689Z" },
{ url = "https://files.pythonhosted.org/packages/d0/34/9e591954939276bb679b73773836c6684c22e56d05980e31d52a9a8deb18/lxml-6.0.2-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef9266d2aa545d7374938fb5c484531ef5a2ec7f2d573e62f8ce722c735685fd", size = 5244072, upload-time = "2025-09-22T04:02:08.587Z" },
{ url = "https://files.pythonhosted.org/packages/8d/27/b29ff065f9aaca443ee377aff699714fcbffb371b4fce5ac4ca759e436d5/lxml-6.0.2-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:4077b7c79f31755df33b795dc12119cb557a0106bfdab0d2c2d97bd3cf3dffa6", size = 4718675, upload-time = "2025-09-22T04:02:10.783Z" },
{ url = "https://files.pythonhosted.org/packages/2b/9f/f756f9c2cd27caa1a6ef8c32ae47aadea697f5c2c6d07b0dae133c244fbe/lxml-6.0.2-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a7c5d5e5f1081955358533be077166ee97ed2571d6a66bdba6ec2f609a715d1a", size = 5255171, upload-time = "2025-09-22T04:02:12.631Z" },
{ url = "https://files.pythonhosted.org/packages/61/46/bb85ea42d2cb1bd8395484fd72f38e3389611aa496ac7772da9205bbda0e/lxml-6.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8f8d0cbd0674ee89863a523e6994ac25fd5be9c8486acfc3e5ccea679bad2679", size = 5057175, upload-time = "2025-09-22T04:02:14.718Z" },
{ url = "https://files.pythonhosted.org/packages/95/0c/443fc476dcc8e41577f0af70458c50fe299a97bb6b7505bb1ae09aa7f9ac/lxml-6.0.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2cbcbf6d6e924c28f04a43f3b6f6e272312a090f269eff68a2982e13e5d57659", size = 4785688, upload-time = "2025-09-22T04:02:16.957Z" },
{ url = "https://files.pythonhosted.org/packages/48/78/6ef0b359d45bb9697bc5a626e1992fa5d27aa3f8004b137b2314793b50a0/lxml-6.0.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dfb874cfa53340009af6bdd7e54ebc0d21012a60a4e65d927c2e477112e63484", size = 5660655, upload-time = "2025-09-22T04:02:18.815Z" },
{ url = "https://files.pythonhosted.org/packages/ff/ea/e1d33808f386bc1339d08c0dcada6e4712d4ed8e93fcad5f057070b7988a/lxml-6.0.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fb8dae0b6b8b7f9e96c26fdd8121522ce5de9bb5538010870bd538683d30e9a2", size = 5247695, upload-time = "2025-09-22T04:02:20.593Z" },
{ url = "https://files.pythonhosted.org/packages/4f/47/eba75dfd8183673725255247a603b4ad606f4ae657b60c6c145b381697da/lxml-6.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:358d9adae670b63e95bc59747c72f4dc97c9ec58881d4627fe0120da0f90d314", size = 5269841, upload-time = "2025-09-22T04:02:22.489Z" },
{ url = "https://files.pythonhosted.org/packages/76/04/5c5e2b8577bc936e219becb2e98cdb1aca14a4921a12995b9d0c523502ae/lxml-6.0.2-cp313-cp313-win32.whl", hash = "sha256:e8cd2415f372e7e5a789d743d133ae474290a90b9023197fd78f32e2dc6873e2", size = 3610700, upload-time = "2025-09-22T04:02:24.465Z" },
{ url = "https://files.pythonhosted.org/packages/fe/0a/4643ccc6bb8b143e9f9640aa54e38255f9d3b45feb2cbe7ae2ca47e8782e/lxml-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:b30d46379644fbfc3ab81f8f82ae4de55179414651f110a1514f0b1f8f6cb2d7", size = 4010347, upload-time = "2025-09-22T04:02:26.286Z" },
{ url = "https://files.pythonhosted.org/packages/31/ef/dcf1d29c3f530577f61e5fe2f1bd72929acf779953668a8a47a479ae6f26/lxml-6.0.2-cp313-cp313-win_arm64.whl", hash = "sha256:13dcecc9946dca97b11b7c40d29fba63b55ab4170d3c0cf8c0c164343b9bfdcf", size = 3671248, upload-time = "2025-09-22T04:02:27.918Z" },
{ url = "https://files.pythonhosted.org/packages/03/15/d4a377b385ab693ce97b472fe0c77c2b16ec79590e688b3ccc71fba19884/lxml-6.0.2-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:b0c732aa23de8f8aec23f4b580d1e52905ef468afb4abeafd3fec77042abb6fe", size = 8659801, upload-time = "2025-09-22T04:02:30.113Z" },
{ url = "https://files.pythonhosted.org/packages/c8/e8/c128e37589463668794d503afaeb003987373c5f94d667124ffd8078bbd9/lxml-6.0.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4468e3b83e10e0317a89a33d28f7aeba1caa4d1a6fd457d115dd4ffe90c5931d", size = 4659403, upload-time = "2025-09-22T04:02:32.119Z" },
{ url = "https://files.pythonhosted.org/packages/00/ce/74903904339decdf7da7847bb5741fc98a5451b42fc419a86c0c13d26fe2/lxml-6.0.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:abd44571493973bad4598a3be7e1d807ed45aa2adaf7ab92ab7c62609569b17d", size = 4966974, upload-time = "2025-09-22T04:02:34.155Z" },
{ url = "https://files.pythonhosted.org/packages/1f/d3/131dec79ce61c5567fecf82515bd9bc36395df42501b50f7f7f3bd065df0/lxml-6.0.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:370cd78d5855cfbffd57c422851f7d3864e6ae72d0da615fca4dad8c45d375a5", size = 5102953, upload-time = "2025-09-22T04:02:36.054Z" },
{ url = "https://files.pythonhosted.org/packages/3a/ea/a43ba9bb750d4ffdd885f2cd333572f5bb900cd2408b67fdda07e85978a0/lxml-6.0.2-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:901e3b4219fa04ef766885fb40fa516a71662a4c61b80c94d25336b4934b71c0", size = 5055054, upload-time = "2025-09-22T04:02:38.154Z" },
{ url = "https://files.pythonhosted.org/packages/60/23/6885b451636ae286c34628f70a7ed1fcc759f8d9ad382d132e1c8d3d9bfd/lxml-6.0.2-cp314-cp314-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:a4bf42d2e4cf52c28cc1812d62426b9503cdb0c87a6de81442626aa7d69707ba", size = 5352421, upload-time = "2025-09-22T04:02:40.413Z" },
{ url = "https://files.pythonhosted.org/packages/48/5b/fc2ddfc94ddbe3eebb8e9af6e3fd65e2feba4967f6a4e9683875c394c2d8/lxml-6.0.2-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2c7fdaa4d7c3d886a42534adec7cfac73860b89b4e5298752f60aa5984641a0", size = 5673684, upload-time = "2025-09-22T04:02:42.288Z" },
{ url = "https://files.pythonhosted.org/packages/29/9c/47293c58cc91769130fbf85531280e8cc7868f7fbb6d92f4670071b9cb3e/lxml-6.0.2-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:98a5e1660dc7de2200b00d53fa00bcd3c35a3608c305d45a7bbcaf29fa16e83d", size = 5252463, upload-time = "2025-09-22T04:02:44.165Z" },
{ url = "https://files.pythonhosted.org/packages/9b/da/ba6eceb830c762b48e711ded880d7e3e89fc6c7323e587c36540b6b23c6b/lxml-6.0.2-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:dc051506c30b609238d79eda75ee9cab3e520570ec8219844a72a46020901e37", size = 4698437, upload-time = "2025-09-22T04:02:46.524Z" },
{ url = "https://files.pythonhosted.org/packages/a5/24/7be3f82cb7990b89118d944b619e53c656c97dc89c28cfb143fdb7cd6f4d/lxml-6.0.2-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8799481bbdd212470d17513a54d568f44416db01250f49449647b5ab5b5dccb9", size = 5269890, upload-time = "2025-09-22T04:02:48.812Z" },
{ url = "https://files.pythonhosted.org/packages/1b/bd/dcfb9ea1e16c665efd7538fc5d5c34071276ce9220e234217682e7d2c4a5/lxml-6.0.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9261bb77c2dab42f3ecd9103951aeca2c40277701eb7e912c545c1b16e0e4917", size = 5097185, upload-time = "2025-09-22T04:02:50.746Z" },
{ url = "https://files.pythonhosted.org/packages/21/04/a60b0ff9314736316f28316b694bccbbabe100f8483ad83852d77fc7468e/lxml-6.0.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:65ac4a01aba353cfa6d5725b95d7aed6356ddc0a3cd734de00124d285b04b64f", size = 4745895, upload-time = "2025-09-22T04:02:52.968Z" },
{ url = "https://files.pythonhosted.org/packages/d6/bd/7d54bd1846e5a310d9c715921c5faa71cf5c0853372adf78aee70c8d7aa2/lxml-6.0.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b22a07cbb82fea98f8a2fd814f3d1811ff9ed76d0fc6abc84eb21527596e7cc8", size = 5695246, upload-time = "2025-09-22T04:02:54.798Z" },
{ url = "https://files.pythonhosted.org/packages/fd/32/5643d6ab947bc371da21323acb2a6e603cedbe71cb4c99c8254289ab6f4e/lxml-6.0.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:d759cdd7f3e055d6bc8d9bec3ad905227b2e4c785dc16c372eb5b5e83123f48a", size = 5260797, upload-time = "2025-09-22T04:02:57.058Z" },
{ url = "https://files.pythonhosted.org/packages/33/da/34c1ec4cff1eea7d0b4cd44af8411806ed943141804ac9c5d565302afb78/lxml-6.0.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:945da35a48d193d27c188037a05fec5492937f66fb1958c24fc761fb9d40d43c", size = 5277404, upload-time = "2025-09-22T04:02:58.966Z" },
{ url = "https://files.pythonhosted.org/packages/82/57/4eca3e31e54dc89e2c3507e1cd411074a17565fa5ffc437c4ae0a00d439e/lxml-6.0.2-cp314-cp314-win32.whl", hash = "sha256:be3aaa60da67e6153eb15715cc2e19091af5dc75faef8b8a585aea372507384b", size = 3670072, upload-time = "2025-09-22T04:03:38.05Z" },
{ url = "https://files.pythonhosted.org/packages/e3/e0/c96cf13eccd20c9421ba910304dae0f619724dcf1702864fd59dd386404d/lxml-6.0.2-cp314-cp314-win_amd64.whl", hash = "sha256:fa25afbadead523f7001caf0c2382afd272c315a033a7b06336da2637d92d6ed", size = 4080617, upload-time = "2025-09-22T04:03:39.835Z" },
{ url = "https://files.pythonhosted.org/packages/d5/5d/b3f03e22b3d38d6f188ef044900a9b29b2fe0aebb94625ce9fe244011d34/lxml-6.0.2-cp314-cp314-win_arm64.whl", hash = "sha256:063eccf89df5b24e361b123e257e437f9e9878f425ee9aae3144c77faf6da6d8", size = 3754930, upload-time = "2025-09-22T04:03:41.565Z" },
{ url = "https://files.pythonhosted.org/packages/5e/5c/42c2c4c03554580708fc738d13414801f340c04c3eff90d8d2d227145275/lxml-6.0.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:6162a86d86893d63084faaf4ff937b3daea233e3682fb4474db07395794fa80d", size = 8910380, upload-time = "2025-09-22T04:03:01.645Z" },
{ url = "https://files.pythonhosted.org/packages/bf/4f/12df843e3e10d18d468a7557058f8d3733e8b6e12401f30b1ef29360740f/lxml-6.0.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:414aaa94e974e23a3e92e7ca5b97d10c0cf37b6481f50911032c69eeb3991bba", size = 4775632, upload-time = "2025-09-22T04:03:03.814Z" },
{ url = "https://files.pythonhosted.org/packages/e4/0c/9dc31e6c2d0d418483cbcb469d1f5a582a1cd00a1f4081953d44051f3c50/lxml-6.0.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48461bd21625458dd01e14e2c38dd0aea69addc3c4f960c30d9f59d7f93be601", size = 4975171, upload-time = "2025-09-22T04:03:05.651Z" },
{ url = "https://files.pythonhosted.org/packages/e7/2b/9b870c6ca24c841bdd887504808f0417aa9d8d564114689266f19ddf29c8/lxml-6.0.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:25fcc59afc57d527cfc78a58f40ab4c9b8fd096a9a3f964d2781ffb6eb33f4ed", size = 5110109, upload-time = "2025-09-22T04:03:07.452Z" },
{ url = "https://files.pythonhosted.org/packages/bf/0c/4f5f2a4dd319a178912751564471355d9019e220c20d7db3fb8307ed8582/lxml-6.0.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5179c60288204e6ddde3f774a93350177e08876eaf3ab78aa3a3649d43eb7d37", size = 5041061, upload-time = "2025-09-22T04:03:09.297Z" },
{ url = "https://files.pythonhosted.org/packages/12/64/554eed290365267671fe001a20d72d14f468ae4e6acef1e179b039436967/lxml-6.0.2-cp314-cp314t-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:967aab75434de148ec80597b75062d8123cadf2943fb4281f385141e18b21338", size = 5306233, upload-time = "2025-09-22T04:03:11.651Z" },
{ url = "https://files.pythonhosted.org/packages/7a/31/1d748aa275e71802ad9722df32a7a35034246b42c0ecdd8235412c3396ef/lxml-6.0.2-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d100fcc8930d697c6561156c6810ab4a508fb264c8b6779e6e61e2ed5e7558f9", size = 5604739, upload-time = "2025-09-22T04:03:13.592Z" },
{ url = "https://files.pythonhosted.org/packages/8f/41/2c11916bcac09ed561adccacceaedd2bf0e0b25b297ea92aab99fd03d0fa/lxml-6.0.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ca59e7e13e5981175b8b3e4ab84d7da57993eeff53c07764dcebda0d0e64ecd", size = 5225119, upload-time = "2025-09-22T04:03:15.408Z" },
{ url = "https://files.pythonhosted.org/packages/99/05/4e5c2873d8f17aa018e6afde417c80cc5d0c33be4854cce3ef5670c49367/lxml-6.0.2-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:957448ac63a42e2e49531b9d6c0fa449a1970dbc32467aaad46f11545be9af1d", size = 4633665, upload-time = "2025-09-22T04:03:17.262Z" },
{ url = "https://files.pythonhosted.org/packages/0f/c9/dcc2da1bebd6275cdc723b515f93edf548b82f36a5458cca3578bc899332/lxml-6.0.2-cp314-cp314t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b7fc49c37f1786284b12af63152fe1d0990722497e2d5817acfe7a877522f9a9", size = 5234997, upload-time = "2025-09-22T04:03:19.14Z" },
{ url = "https://files.pythonhosted.org/packages/9c/e2/5172e4e7468afca64a37b81dba152fc5d90e30f9c83c7c3213d6a02a5ce4/lxml-6.0.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e19e0643cc936a22e837f79d01a550678da8377d7d801a14487c10c34ee49c7e", size = 5090957, upload-time = "2025-09-22T04:03:21.436Z" },
{ url = "https://files.pythonhosted.org/packages/a5/b3/15461fd3e5cd4ddcb7938b87fc20b14ab113b92312fc97afe65cd7c85de1/lxml-6.0.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:1db01e5cf14345628e0cbe71067204db658e2fb8e51e7f33631f5f4735fefd8d", size = 4764372, upload-time = "2025-09-22T04:03:23.27Z" },
{ url = "https://files.pythonhosted.org/packages/05/33/f310b987c8bf9e61c4dd8e8035c416bd3230098f5e3cfa69fc4232de7059/lxml-6.0.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:875c6b5ab39ad5291588aed6925fac99d0097af0dd62f33c7b43736043d4a2ec", size = 5634653, upload-time = "2025-09-22T04:03:25.767Z" },
{ url = "https://files.pythonhosted.org/packages/70/ff/51c80e75e0bc9382158133bdcf4e339b5886c6ee2418b5199b3f1a61ed6d/lxml-6.0.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:cdcbed9ad19da81c480dfd6dd161886db6096083c9938ead313d94b30aadf272", size = 5233795, upload-time = "2025-09-22T04:03:27.62Z" },
{ url = "https://files.pythonhosted.org/packages/56/4d/4856e897df0d588789dd844dbed9d91782c4ef0b327f96ce53c807e13128/lxml-6.0.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:80dadc234ebc532e09be1975ff538d154a7fa61ea5031c03d25178855544728f", size = 5257023, upload-time = "2025-09-22T04:03:30.056Z" },
{ url = "https://files.pythonhosted.org/packages/0f/85/86766dfebfa87bea0ab78e9ff7a4b4b45225df4b4d3b8cc3c03c5cd68464/lxml-6.0.2-cp314-cp314t-win32.whl", hash = "sha256:da08e7bb297b04e893d91087df19638dc7a6bb858a954b0cc2b9f5053c922312", size = 3911420, upload-time = "2025-09-22T04:03:32.198Z" },
{ url = "https://files.pythonhosted.org/packages/fe/1a/b248b355834c8e32614650b8008c69ffeb0ceb149c793961dd8c0b991bb3/lxml-6.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:252a22982dca42f6155125ac76d3432e548a7625d56f5a273ee78a5057216eca", size = 4406837, upload-time = "2025-09-22T04:03:34.027Z" },
{ url = "https://files.pythonhosted.org/packages/92/aa/df863bcc39c5e0946263454aba394de8a9084dbaff8ad143846b0d844739/lxml-6.0.2-cp314-cp314t-win_arm64.whl", hash = "sha256:bb4c1847b303835d89d785a18801a883436cdfd5dc3d62947f9c49e24f0f5a2c", size = 3822205, upload-time = "2025-09-22T04:03:36.249Z" },
{ url = "https://files.pythonhosted.org/packages/0b/11/29d08bc103a62c0eba8016e7ed5aeebbf1e4312e83b0b1648dd203b0e87d/lxml-6.0.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1c06035eafa8404b5cf475bb37a9f6088b0aca288d4ccc9d69389750d5543700", size = 3949829, upload-time = "2025-09-22T04:04:45.608Z" },
{ url = "https://files.pythonhosted.org/packages/12/b3/52ab9a3b31e5ab8238da241baa19eec44d2ab426532441ee607165aebb52/lxml-6.0.2-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c7d13103045de1bdd6fe5d61802565f1a3537d70cd3abf596aa0af62761921ee", size = 4226277, upload-time = "2025-09-22T04:04:47.754Z" },
{ url = "https://files.pythonhosted.org/packages/a0/33/1eaf780c1baad88224611df13b1c2a9dfa460b526cacfe769103ff50d845/lxml-6.0.2-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a3c150a95fbe5ac91de323aa756219ef9cf7fde5a3f00e2281e30f33fa5fa4f", size = 4330433, upload-time = "2025-09-22T04:04:49.907Z" },
{ url = "https://files.pythonhosted.org/packages/7a/c1/27428a2ff348e994ab4f8777d3a0ad510b6b92d37718e5887d2da99952a2/lxml-6.0.2-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60fa43be34f78bebb27812ed90f1925ec99560b0fa1decdb7d12b84d857d31e9", size = 4272119, upload-time = "2025-09-22T04:04:51.801Z" },
{ url = "https://files.pythonhosted.org/packages/f0/d0/3020fa12bcec4ab62f97aab026d57c2f0cfd480a558758d9ca233bb6a79d/lxml-6.0.2-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:21c73b476d3cfe836be731225ec3421fa2f048d84f6df6a8e70433dff1376d5a", size = 4417314, upload-time = "2025-09-22T04:04:55.024Z" },
{ url = "https://files.pythonhosted.org/packages/6c/77/d7f491cbc05303ac6801651aabeb262d43f319288c1ea96c66b1d2692ff3/lxml-6.0.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:27220da5be049e936c3aca06f174e8827ca6445a4353a1995584311487fc4e3e", size = 3518768, upload-time = "2025-09-22T04:04:57.097Z" },
]
[[package]]
name = "python-docx"
version = "1.2.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "lxml" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a9/f7/eddfe33871520adab45aaa1a71f0402a2252050c14c7e3009446c8f4701c/python_docx-1.2.0.tar.gz", hash = "sha256:7bc9d7b7d8a69c9c02ca09216118c86552704edc23bac179283f2e38f86220ce", size = 5723256, upload-time = "2025-06-16T20:46:27.921Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d0/00/1e03a4989fa5795da308cd774f05b704ace555a70f9bf9d3be057b680bcf/python_docx-1.2.0-py3-none-any.whl", hash = "sha256:3fd478f3250fbbbfd3b94fe1e985955737c145627498896a8a6bf81f4baf66c7", size = 252987, upload-time = "2025-06-16T20:46:22.506Z" },
]
[[package]] [[package]]
name = "repl-nix-workspace" name = "repl-nix-workspace"
version = "0.1.0" version = "0.1.0"
source = { virtual = "." } source = { virtual = "." }
dependencies = [ dependencies = [
{ name = "httpx" }, { name = "httpx" },
{ name = "python-docx" },
] ]
[package.metadata] [package.metadata]
requires-dist = [ requires-dist = [{ name = "httpx", specifier = ">=0.28.1" }]
{ name = "httpx", specifier = ">=0.28.1" },
{ name = "python-docx", specifier = ">=1.2.0" },
]
[[package]] [[package]]
name = "sniffio" name = "sniffio"

View File

@ -1,13 +1,7 @@
{ {
"version": "1.0.109", "version": "1.0.108",
"lastUpdate": "2026-02-16T07:50:06.148Z", "lastUpdate": "2026-02-14T10:47:54.686Z",
"changelog": [ "changelog": [
{
"version": "1.0.109",
"date": "2026-02-16",
"type": "patch",
"description": "Deployment automatico v1.0.109"
},
{ {
"version": "1.0.108", "version": "1.0.108",
"date": "2026-02-14", "date": "2026-02-14",
@ -301,6 +295,12 @@
"date": "2025-11-24", "date": "2025-11-24",
"type": "patch", "type": "patch",
"description": "Deployment automatico v1.0.60" "description": "Deployment automatico v1.0.60"
},
{
"version": "1.0.59",
"date": "2025-11-24",
"type": "patch",
"description": "Deployment automatico v1.0.59"
} }
] ]
} }