Files
pyssh-client/app/paths.py
snoopy b977842186 Client SSH/SFTP personnel pour Windows
Reunit en un seul outil les fonctions utiles de MobaXterm, Termius et Bitvise,
sans compte ni service tiers, avec toutes les donnees en local.

- Terminaux multi-onglets : sessions SSH et terminaux Windows locaux
  (PowerShell / cmd) via la pseudo-console native ConPTY
- Gestionnaire de fichiers SFTP facon WinSCP : double panneau, colonnes
  triables, glisser-deposer, renommage, permissions, file de transferts.
  Ouvrable sur une connexion en cours sans creer de favori
- Gestion des cles SSH : generation Ed25519/RSA, import, export
- Gestion du fichier known_hosts, avec remplacement guide d'une cle d'hote
  modifiee (cas frequent des serveurs en DHCP)
- Trois themes (clair, bleu nuit, noir), commutables a chaud
- Authentification automatique reprenant le comportement de la commande ssh
  (agent SSH et cles ~/.ssh), mot de passe demande seulement en secours

Aucun mot de passe n'est stocke sur le disque.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 06:50:10 +02:00

50 lines
1.7 KiB
Python

"""Emplacements des donnees et des ressources, valables en mode script comme en .exe.
Point d'attention : une fois l'application figee par PyInstaller, `__file__` pointe vers
un dossier temporaire (`sys._MEIPASS`) que Windows supprime a la fermeture. Y ecrire les
sessions, les cles ou known_hosts reviendrait a les perdre a chaque sortie. Les donnees
utilisateur vont donc a cote de l'executable (mode portable), avec repli sur %APPDATA%
si cet emplacement n'est pas accessible en ecriture (installation dans Program Files,
lancement depuis un support en lecture seule...).
"""
from __future__ import annotations
import os
import sys
from pathlib import Path
FROZEN = getattr(sys, "frozen", False)
def _app_dir() -> Path:
"""Dossier de l'executable (mode figé) ou racine du projet (mode script)."""
if FROZEN:
return Path(sys.executable).resolve().parent
return Path(__file__).resolve().parent.parent
def _resolve_resources() -> Path:
if FROZEN:
bundled = getattr(sys, "_MEIPASS", None)
if bundled: # onefile : ressources extraites dans un dossier temporaire
return Path(bundled) / "resources"
return _app_dir() / "resources"
def _resolve_data() -> Path:
candidate = _app_dir() / "data"
try:
candidate.mkdir(parents=True, exist_ok=True)
probe = candidate / ".write_test"
probe.write_text("", encoding="utf-8")
probe.unlink()
return candidate
except OSError:
fallback = Path(os.environ.get("APPDATA") or Path.home()) / "PySSHClient"
fallback.mkdir(parents=True, exist_ok=True)
return fallback
RESOURCES_DIR = _resolve_resources()
DATA_DIR = _resolve_data()