chore: delete script

This commit is contained in:
2026-05-01 20:55:52 +02:00
parent b217a57a15
commit 46b287c960
5 changed files with 0 additions and 793 deletions
-197
View File
@@ -1,197 +0,0 @@
#!/usr/bin/env python3
"""
Import adresse_correction depuis data2.txt (format psql pipe-séparé, avec
gestion des valeurs multi-lignes et des lignes fusionnées sans newline).
Usage : python3 import_adresse_correction.py [--dry-run]
"""
import os
import re
import sys
import psycopg2
DB_CONFIG = {
"host": "localhost",
"port": 5432,
"user": "",
"password": "",
"dbname": "",
}
DATA_FILE = os.path.join(os.path.dirname(__file__), "data2.txt")
DRY_RUN = "--dry-run" in sys.argv
SOURCE_COLUMNS = [
"id",
"invalid_address",
"correct_address",
"created_at",
"updated_at",
]
def preprocess(content: str) -> list[str]:
"""
Sépare les lignes physiquement fusionnées :
ex: "...2026-03-13 22:33:10.353601 79 | 55 Quai..." → deux lignes.
Pattern : timestamp immédiatement suivi (sans \n) d'un entier + '|'.
"""
content = re.sub(
r"(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+)\s{2,}(\d+\s*\|)",
r"\1\n \2",
content,
)
return content.splitlines()
def parse_psql_rows(path: str) -> list[list[str]]:
"""
Parse le format aligné psql :
- Lignes de continuation (sans id, commençant par ' |') : valeur multi-ligne.
- Champ se terminant par '+' avant '|' : continuation sur la ligne suivante.
"""
with open(path, encoding="utf-8") as f:
raw = f.read()
lines = preprocess(raw)
rows: list[list[str]] = []
current: list[str] | None = None
for line in lines:
line = line.rstrip("\n")
stripped = line.strip()
# Ligne vide
if not stripped:
continue
# Ligne séparateur psql (----+----)
if (
set(
stripped.replace("|", "")
.replace("+", "")
.replace("-", "")
.replace(" ", "")
)
== set()
):
continue
parts = line.split("|")
if len(parts) < 2:
continue
first = parts[0].strip()
is_continuation = current is not None and (first == "" or not first.isdigit())
if is_continuation:
# Fusionner avec la ligne en cours
cont = parts[:-1] if parts[-1].strip() == "" else parts
for i, cf in enumerate(cont):
if i < len(current):
prev = current[i].rstrip("+").rstrip()
add = cf.strip()
current[i] = (prev + (" " if prev and add else "") + add).strip()
continue
# Sauvegarder la ligne précédente
if current is not None:
rows.append(current)
# Nouvelle ligne de données : nettoyer le '+' de continuation
raw_fields = parts[:-1] if parts[-1].strip() == "" else parts
current = [f.strip().rstrip("+").strip() for f in raw_fields]
if current is not None:
rows.append(current)
return rows
def parse_value(v: str):
v = v.strip()
if v == "" or v.lower() == "null":
return None
return v
def main():
raw_rows = parse_psql_rows(DATA_FILE)
if not raw_rows:
print("❌ Aucune ligne trouvée dans data2.txt")
sys.exit(1)
# Filtrer l'en-tête éventuel
rows = [[parse_value(v) for v in r] for r in raw_rows if r[0].strip() != "id"]
print(f"📂 {len(rows)} lignes de données à importer depuis {DATA_FILE}")
insert_cols = [c for c in SOURCE_COLUMNS if c != "id"]
insert_cols_all = ["id"] + insert_cols
placeholders = ", ".join(["%s"] * len(insert_cols_all))
col_names = ", ".join(insert_cols_all)
update_expr = ", ".join(f"{c} = EXCLUDED.{c}" for c in insert_cols)
sql = f"""
INSERT INTO adresse_correction ({col_names})
VALUES ({placeholders})
ON CONFLICT (invalid_address) DO UPDATE SET {update_expr}
"""
conn = psycopg2.connect(**DB_CONFIG)
conn.autocommit = False
cur = conn.cursor()
inserted = updated = errors = 0
for i, row in enumerate(rows, 1):
if len(row) < len(SOURCE_COLUMNS):
print(f" ⚠️ Ligne {i} ignorée ({len(row)} champs) : {row}")
continue
row_dict = {SOURCE_COLUMNS[j]: row[j] for j in range(len(SOURCE_COLUMNS))}
values = [row_dict[c] for c in insert_cols_all]
inv_addr = row_dict.get("invalid_address", "?")
if DRY_RUN:
print(
f" [DRY-RUN] {i:3}. {inv_addr!r}{row_dict.get('correct_address')!r}"
)
inserted += 1
continue
try:
cur.execute(
"SELECT 1 FROM adresse_correction WHERE invalid_address = %s",
(inv_addr,),
)
exists = cur.fetchone() is not None
cur.execute(sql, values)
if exists:
updated += 1
else:
inserted += 1
except Exception as e:
print(f" ❌ Erreur ligne {i} ({inv_addr!r}) : {e}")
conn.rollback()
errors += 1
if not DRY_RUN:
cur.execute(
"SELECT setval('adresse_correction_id_seq', COALESCE((SELECT MAX(id) FROM adresse_correction), 1))"
)
conn.commit()
cur.close()
conn.close()
print(f"\n{'🔍 DRY-RUN — ' if DRY_RUN else ''}✅ Terminé")
print(f" Insérés : {inserted}")
print(f" Mis à jour : {updated}")
print(f" Erreurs : {errors}")
if __name__ == "__main__":
main()
-179
View File
@@ -1,179 +0,0 @@
#!/usr/bin/env python3
"""
Import clients depuis data.txt (format psql pipe-séparé) vers PostgreSQL.
Usage : python3 import_clients.py [--dry-run]
"""
import os
import sys
import psycopg2
# ── Connexion ──────────────────────────────────────────────────────────────────
DB_CONFIG = {
"host": "localhost",
"port": 5432,
"user": "",
"password": "",
"dbname": "",
}
DATA_FILE = os.path.join(os.path.dirname(__file__), "data.txt")
DRY_RUN = "--dry-run" in sys.argv
# ── Ordre des colonnes dans data.txt (DB production, construite incrémentalement)
# None = colonne inconnue/obsolète à ignorer
SOURCE_COLUMNS = [
"id",
"username",
"password",
"nom",
"prenom",
"telephone",
"command",
"amende",
"cancel_commande",
"referral_balance", # position 9 : NUMERIC(10,2) → "0.00"
"cancellations_count", # position 10 : INTEGER → "0"
None, # position 11 : colonne obsolète/inconnue, ignorée
"last_penalty_reason", # position 12 : TEXT
"updated_at",
"created_at",
"must_change_password", # position 15 : BOOLEAN → "f"/"t"
]
def parse_value(v: str):
"""Convertit une valeur brute psql en type Python (None si vide)."""
v = v.strip()
if v == "" or v.lower() == "null":
return None
if v.lower() == "t":
return True
if v.lower() == "f":
return False
return v
def load_data(path: str) -> list[list]:
rows = []
with open(path, encoding="utf-8") as f:
for line in f:
line = line.rstrip("\n")
if not line.strip():
continue
# Lignes séparateur psql (ex: "----+----")
if (
set(
line.replace("|", "")
.replace("+", "")
.replace("-", "")
.replace(" ", "")
)
== set()
):
continue
parts = line.split("|")
values = (
[parse_value(p) for p in parts[:-1]]
if parts[-1].strip() == ""
else [parse_value(p) for p in parts]
)
if values:
rows.append(values)
return rows
def main():
rows = load_data(DATA_FILE)
if not rows:
print("❌ Aucune ligne trouvée dans data.txt")
sys.exit(1)
print(f"📂 {len(rows)} lignes lues depuis {DATA_FILE}")
data_col_count = len(rows[0])
print(
f"📋 Colonnes data.txt : {data_col_count} | SOURCE_COLUMNS définis : {len(SOURCE_COLUMNS)}"
)
if data_col_count != len(SOURCE_COLUMNS):
print(
f"⚠️ Ajuste SOURCE_COLUMNS dans le script ({len(SOURCE_COLUMNS)} définis, {data_col_count} dans le fichier)"
)
sys.exit(1)
# Colonnes à insérer (on filtre les None = colonnes ignorées)
insert_cols = [col for col in SOURCE_COLUMNS if col is not None and col != "id"]
# On conserve aussi l'id pour FORCE_ID
insert_cols_with_id = ["id"] + insert_cols
placeholders = ", ".join(["%s"] * len(insert_cols_with_id))
col_names = ", ".join(insert_cols_with_id)
update_expr = ", ".join(f"{c} = EXCLUDED.{c}" for c in insert_cols)
sql = f"""
INSERT INTO clients ({col_names})
VALUES ({placeholders})
ON CONFLICT (username) DO UPDATE SET {update_expr}
"""
conn = psycopg2.connect(**DB_CONFIG)
conn.autocommit = False
cur = conn.cursor()
inserted = 0
updated = 0
errors = 0
for i, row in enumerate(rows, 1):
# Construire un dict {col_name: value} depuis SOURCE_COLUMNS
row_dict = {}
for pos, col in enumerate(SOURCE_COLUMNS):
if col is None:
continue
row_dict[col] = row[pos] if pos < len(row) else None
values = [row_dict.get(c) for c in insert_cols_with_id]
username = row_dict.get("username", "?")
try:
if DRY_RUN:
print(f" [DRY-RUN] ligne {i} : {username}{row_dict}")
inserted += 1
continue
cur.execute("SELECT 1 FROM clients WHERE username = %s", (username,))
exists = cur.fetchone() is not None
cur.execute(sql, values)
if exists:
updated += 1
else:
inserted += 1
except Exception as e:
print(f" ❌ Erreur ligne {i} ({username}) : {e}")
conn.rollback()
errors += 1
continue
if not DRY_RUN:
cur.execute(
"SELECT setval('clients_id_seq', COALESCE((SELECT MAX(id) FROM clients), 1))"
)
conn.commit()
cur.close()
conn.close()
print(f"\n{'🔍 DRY-RUN — ' if DRY_RUN else ''}✅ Terminé")
print(f" Insérés : {inserted}")
print(f" Mis à jour : {updated}")
print(f" Erreurs : {errors}")
print(f" ️ Séquence clients_id_seq resynchronisée sur MAX(id)")
if __name__ == "__main__":
main()
-162
View File
@@ -1,162 +0,0 @@
#!/usr/bin/env python3
"""
Import users depuis data3.txt (format psql pipe-séparé) vers PostgreSQL.
Usage : python3 import_users.py [--dry-run]
"""
import os
import sys
import psycopg2
DB_CONFIG = {
"host": "localhost",
"port": 5432,
"user": "",
"password": "",
"dbname": "",
}
DATA_FILE = os.path.join(os.path.dirname(__file__), "data3.txt")
DRY_RUN = "--dry-run" in sys.argv
# Colonnes dans data3.txt — None = ignoré (push_token supprimé)
SOURCE_COLUMNS = [
"id",
"username",
"password",
"role",
"total",
"livraison",
"created_at",
"updated_at",
]
def parse_value(v: str):
v = v.strip()
if v == "" or v.lower() == "null":
return None
if v.lower() == "t":
return True
if v.lower() == "f":
return False
return v
def load_data(path: str) -> list[list]:
rows = []
with open(path, encoding="utf-8") as f:
for line in f:
line = line.rstrip("\n")
if not line.strip():
continue
if (
set(
line.replace("|", "")
.replace("+", "")
.replace("-", "")
.replace(" ", "")
)
== set()
):
continue
parts = line.split("|")
values = (
[parse_value(p) for p in parts[:-1]]
if parts[-1].strip() == ""
else [parse_value(p) for p in parts]
)
# Ignorer la ligne d'en-tête
if values and values[0] == "id":
continue
if values:
rows.append(values)
return rows
def main():
rows = load_data(DATA_FILE)
if not rows:
print("❌ Aucune ligne trouvée dans data3.txt")
sys.exit(1)
print(f"📂 {len(rows)} lignes lues depuis {DATA_FILE}")
data_col_count = len(rows[0])
print(
f"📋 Colonnes data3.txt : {data_col_count} | SOURCE_COLUMNS définis : {len(SOURCE_COLUMNS)}"
)
if data_col_count != len(SOURCE_COLUMNS):
print(
f"⚠️ Ajuste SOURCE_COLUMNS ({len(SOURCE_COLUMNS)} définis, {data_col_count} dans le fichier)"
)
sys.exit(1)
insert_cols = [col for col in SOURCE_COLUMNS if col is not None and col != "id"]
insert_cols_with_id = ["id"] + insert_cols
placeholders = ", ".join(["%s"] * len(insert_cols_with_id))
col_names = ", ".join(insert_cols_with_id)
update_expr = ", ".join(f"{c} = EXCLUDED.{c}" for c in insert_cols)
sql = f"""
INSERT INTO users ({col_names})
VALUES ({placeholders})
ON CONFLICT (username) DO UPDATE SET {update_expr}
"""
conn = psycopg2.connect(**DB_CONFIG)
conn.autocommit = False
cur = conn.cursor()
inserted = updated = errors = 0
for i, row in enumerate(rows, 1):
row_dict = {}
for pos, col in enumerate(SOURCE_COLUMNS):
if col is None:
continue
row_dict[col] = row[pos] if pos < len(row) else None
values = [row_dict.get(c) for c in insert_cols_with_id]
username = row_dict.get("username", "?")
try:
if DRY_RUN:
print(f" [DRY-RUN] {i}. {username}{row_dict}")
inserted += 1
continue
cur.execute("SELECT 1 FROM users WHERE username = %s", (username,))
exists = cur.fetchone() is not None
cur.execute(sql, values)
if exists:
updated += 1
else:
inserted += 1
except Exception as e:
print(f" ❌ Erreur ligne {i} ({username}) : {e}")
conn.rollback()
errors += 1
if not DRY_RUN:
cur.execute(
"SELECT setval('users_id_seq', COALESCE((SELECT MAX(id) FROM users), 1))"
)
conn.commit()
cur.close()
conn.close()
print(f"\n{'🔍 DRY-RUN — ' if DRY_RUN else ''}✅ Terminé")
print(f" Insérés : {inserted}")
print(f" Mis à jour : {updated}")
print(f" Erreurs : {errors}")
print(" ️ Séquence users_id_seq resynchronisée sur MAX(id)")
if __name__ == "__main__":
main()
-25
View File
@@ -1,25 +0,0 @@
[Unit]
Description=SSH Monitor — alertes Telegram + bannissement automatique
Documentation=https://github.com/pyTelegramBotAPI/pyTelegramBotAPI
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/bin/python3 /home/xor_fakers/projet_gestion_commande/scripts/ssh_monitor.py
Restart=always
RestartSec=5
# Root requis pour iptables
User=root
# Sortie dans journald (journalctl -u ssh-monitor -f)
StandardOutput=journal
StandardError=journal
SyslogIdentifier=ssh-monitor
# Redémarrer même si le process quitte proprement (ex : erreur init)
RestartForceExitStatus=1
[Install]
WantedBy=multi-user.target
-230
View File
@@ -1,230 +0,0 @@
#!/usr/bin/env python3
"""
pip install pyTelegramBotAPI
"""
import os
import re
import subprocess
import sys
import time
from collections import defaultdict
from datetime import datetime
import telebot
# ============================================================
# CONFIGURATION — à modifier avant de lancer
# ============================================================
BOT_TOKEN = "7671151228:AAHI_xJqaXkbf2RnDGotn6ZwO_fWgoY-WJk"
CHAT_ID = "7950889398"
LOG_FILE = "/var/log/auth.log"
BRUTE_FORCE_THRESHOLD = 5
BRUTE_FORCE_WINDOW = 60
# Fenêtre de déduplication : évite d'envoyer 2 fois le même type
# d'alerte pour la même IP en moins de DEDUP_WINDOW secondes.
# Toute IP hors whitelist est considérée malveillante → on alerte toujours.
DEDUP_WINDOW = 10
WHITELIST_IPS = {"86.217.21.144"}
ACTIVE_RESPONSE = True
BAN_ON_BRUTE_FORCE = True
BAN_ON_MAX_AUTH = True
banned_ips: set[str] = set()
RE_FAILED = re.compile(
r"sshd\[\d+\]: Failed (?:password|publickey) for (?:invalid user )?(\S+) from ([\d.]+)"
)
RE_INVALID_USER = re.compile(r"sshd\[\d+\]: Invalid user (\S+) from ([\d.]+)")
RE_ACCEPTED = re.compile(
r"sshd\[\d+\]: Accepted (?:password|publickey) for (\S+) from ([\d.]+)"
)
RE_MAX_AUTH = re.compile(
r"sshd\[\d+\]: error: maximum authentication attempts exceeded.*from ([\d.]+)"
)
RE_DISCONNECT_INVALID = re.compile(
r"sshd\[\d+\]: Disconnected from invalid user (\S+) ([\d.]+)"
)
failed_attempts: dict[str, list[float]] = defaultdict(list)
last_sent: dict[tuple, float] = {}
known_ips: set[str] = set()
# ============================================================
# TELEGRAM
# ============================================================
bot = telebot.TeleBot(BOT_TOKEN, parse_mode="HTML")
def send_alert(message: str) -> None:
try:
bot.send_message(CHAT_ID, message)
except Exception as e:
print(f"[TELEGRAM ERROR] {e}", file=sys.stderr)
def dedup_ok(ip: str, event: str) -> bool:
"""Retourne True si on peut envoyer l'alerte (pas envoyée depuis DEDUP_WINDOW s)."""
key = (ip, event)
now = time.time()
if key in last_sent and now - last_sent[key] < DEDUP_WINDOW:
return False
last_sent[key] = now
return True
def ts() -> str:
return datetime.now().strftime("%d/%m/%Y %H:%M:%S")
# ============================================================
# ANALYSE DES LIGNES
# ============================================================
def process_line(line: str) -> None:
line = line.strip()
if not line:
return
m = RE_ACCEPTED.search(line)
if m:
user, ip = m.group(1), m.group(2)
if ip in WHITELIST_IPS:
return
icon = "🔴" if user == "root" else "🟡"
new_ip = "" if ip in known_ips else "(nouvelle IP !)"
known_ips.add(ip)
send_alert(
f"{icon}IP Alertes Connecter: {new_ip}\n"
f"👤 Utilisateur : <code>{user}</code>\n"
f"🌐 IP : <code>{ip}</code>\n"
f"🕐 {ts()}"
)
return
m = RE_MAX_AUTH.search(line)
if m:
ip = m.group(1)
if ip in WHITELIST_IPS:
return
if dedup_ok(ip, "maxauth"):
send_alert(f"🚫 Max authentifications atteint\n🌐 IP : {ip}\n🕐 {ts()}")
return
# --- Utilisateur invalide ---
m = RE_INVALID_USER.search(line)
if m:
user, ip = m.group(1), m.group(2)
if ip in WHITELIST_IPS:
return
_record_failure(ip)
_alert(ip, user)
return
# --- Mot de passe / clé échouée ---
m = RE_FAILED.search(line)
if m:
user, ip = m.group(1), m.group(2)
if ip in WHITELIST_IPS:
return
_record_failure(ip)
_alert(ip, user)
return
def _record_failure(ip: str) -> None:
now = time.time()
failed_attempts[ip].append(now)
failed_attempts[ip] = [
t for t in failed_attempts[ip] if now - t <= BRUTE_FORCE_WINDOW
]
def _alert(ip: str, user: str) -> None:
count = len(failed_attempts[ip])
if count >= BRUTE_FORCE_THRESHOLD:
if dedup_ok(ip, "bruteforce"):
send_alert(
f"🔥 <b>Brute force SSH détecté !</b>\n"
f"🌐 IP : <code>{ip}</code>\n"
f"👤 Dernier user : <code>{user}</code>\n"
f"📊 {count} échecs en {BRUTE_FORCE_WINDOW}s\n"
f"🕐 {ts()}"
)
return
if dedup_ok(ip, "fail"):
send_alert(
f"⚠️ <b>Tentative SSH échouée</b>\n"
f"🌐 IP : <code>{ip}</code>\n"
f"👤 User : <code>{user}</code>\n"
f"📊 {count} échec(s) récent(s)\n"
f"🕐 {ts()}"
)
# ============================================================
# LECTURE EN CONTINU (tail -f)
# ============================================================
def follow(filepath: str):
if not os.path.exists(filepath):
print(f"[ERREUR] Fichier introuvable : {filepath}", file=sys.stderr)
sys.exit(1)
with open(filepath, "r", encoding="utf-8", errors="ignore") as f:
f.seek(0, os.SEEK_END)
print(f"[INFO] Surveillance de {filepath} démarrée.")
send_alert(
f"✅ <b>SSH Monitor démarré</b>\n📂 <code>{filepath}</code>\n🕐 {ts()}"
)
while True:
line = f.readline()
if line:
yield line
else:
try:
if os.stat(filepath).st_ino != os.fstat(f.fileno()).st_ino:
print("[INFO] Rotation du fichier détectée, réouverture.")
f.close()
f = open(filepath, "r", encoding="utf-8", errors="ignore")
except OSError:
pass
time.sleep(0.2)
# ============================================================
# POINT D'ENTRÉE
# ============================================================
if __name__ == "__main__":
if BOT_TOKEN == "VOTRE_BOT_TOKEN" or CHAT_ID == "VOTRE_CHAT_ID":
print("[ERREUR] Configure BOT_TOKEN et CHAT_ID avant de lancer le script.")
sys.exit(1)
print(
f"[INFO] Brute force : {BRUTE_FORCE_THRESHOLD} échecs en {BRUTE_FORCE_WINDOW}s"
)
print(f"[INFO] Déduplication : {DEDUP_WINDOW}s par (IP, type d'événement)")
try:
for log_line in follow(LOG_FILE):
process_line(log_line)
except KeyboardInterrupt:
print("\n[INFO] Arrêt du moniteur.")
send_alert(f"🛑 <b>SSH Monitor arrêté</b>\n🕐 {ts()}")