Project structure
A tour of the repository for contributors and curious readers.
Directory overview
NeoSSHWinManager/
├── main.py # GUI entry point, single-instance, theme bootstrap
├── cli_main.py # CLI companion — talks to GUI via Named Pipe
├── build_dual.ps1 # PyInstaller build for GUI + CLI
├── NeoSSHWinManager.spec # PyInstaller spec (GUI)
├── NeoSSHWinManager-cli.spec # PyInstaller spec (CLI)
├── file_version_info.txt # Windows VERSIONINFO block
├── requirements.txt
├── LICENSE
├── README.md
├── assets/
│ ├── app_icon.ico # Multi-resolution Windows icon
│ ├── app_icon.png
│ └── screenshots/
├── src/
│ ├── config.py # AppSettings + JSON load/save
│ ├── database.py # SQLite schema + migrations
│ ├── auth_manager.py # Login, key derivation, multi-user
│ ├── sshfs_controller.py # Mount / unmount / status
│ ├── ssh_launcher.py # SSH sessions (OpenSSH / PuTTY)
│ ├── single_instance.py # Mutex + window activation
│ ├── ipc_server.py # Named-pipe server for CLI companion
│ ├── i18n.py # Load / resolve translations
│ ├── translations/
│ │ ├── en.json
│ │ └── de.json
│ ├── models/
│ │ ├── connection.py # Connection data model
│ │ └── settings.py # AppSettings data model
│ └── ui/
│ ├── main_window.py
│ ├── login_window.py
│ ├── widgets/ # ConnectionCard, MountToggle, …
│ └── dialogs/ # add_edit, settings, ask_password, debug
└── tests/
├── test_config.py
├── test_auth_manager.py
└── test_sshfs_controller.py
Main modules
main.py
Entry-Point der GUI. Tut der Reihe nach:
- Lädt die Konfig (
config.AppSettings.load()). - Erzwingt Single-Instance (
SingleInstance("SSHWinManager_Mutex_v1")). - Initialisiert
QApplicationmit dem gespeicherten Theme. - Zeigt Login-Window (außer Auto-Login greift) → Hauptfenster.
- Startet
IPCServerin einem Worker-Thread.
cli_main.py
Argparse-CLI. Verbindet sich mit \\.\pipe\SSHWinManager_IPC_v1, sendet einen JSON-Request {op:"connect", key:"…", exec:"…"}, erhält Credentials zurück und ruft dann ssh_launcher.spawn_session() auf.
src/config.py
AppSettings— Dataclass mit Defaults (Theme, Sprache, PuTTY-Pfad, Auto-Reconnect, Check-Intervall, Tray, Debug, …).load()/save()— JSON in%APPDATA%\SSHWinManager\config.json.- Migrations: fehlende Keys werden mit Defaults aufgefüllt.
src/database.py
- SQLite, Pfad:
%APPDATA%\SSHWinManager\app.db. - Tabellen:
users,connections,settings_per_user. - Schema-Version in
PRAGMA user_version;migrate()fügt neue Spalten idempotent hinzu.
src/auth_manager.py
UserManager— anlegen, einloggen, Passwort ändern, löschen.- Passwort-Hash: PBKDF2-HMAC-SHA256, per-User Salt, 200k Iterations.
- Session-Key wird beim Login abgeleitet und hält nur im RAM.
UserConnectionManager— CRUD für Verbindungen, automatische En/Decryption pro User.
src/sshfs_controller.py
SSHFSController.mount(connection, password=None)— baut die Argumentliste, startetsshfs.exeals detached Subprocess.unmount(letter)— drei Strategien (siehe Verbindungen).list_mounts()— parst fsutil-Output.status_for(connection)— gibt"mounted","unmounted"oder"stale"zurück.
src/ssh_launcher.py
Startet eine interaktive SSH-Session. Wählt OpenSSH oder PuTTY je nach AppSettings.use_putty. Übergibt Key oder Passwort sicher.
src/ipc_server.py
Worker-Thread mit Named-Pipe-Server. Akzeptiert JSON-Requests, validiert Access-Key gegen die DB, gibt entschlüsselte Credentials zurück.
UI modules
| File | Responsibility |
|---|---|
login_window.py | Login-Form, Setup-Wizard für Erstprofil. |
main_window.py | Hauptfenster: Sidebar + Verbindungsliste + Statusbar. |
tray.py | System-Tray-Icon mit Schnellzugriff-Menü. |
widgets/connection_card.py | Kachel pro Verbindung mit Mount-Toggle. |
widgets/mount_toggle.py | Custom Switch mit Cyan/Grün-States + Spinner. |
dialogs/add_edit_dialog.py | Verbindung anlegen / bearbeiten. |
dialogs/settings_dialog.py | App-weite Einstellungen. |
dialogs/ask_password_dialog.py | Passwort-Abfrage für „Jedes Mal fragen”. |
dialogs/debug_dialog.py | Live-Log-Viewer mit Filter. |
Data models
Connection
@dataclass
class Connection:
id: int | None
user_id: int
name: str
host: str
port: int = 22
user: str = ""
remote_path: str = "/"
drive_letter: str = "Z:"
auth_method: str = "password" # password | key | ask
password: str | None = None # plaintext only in RAM
key_path: str | None = None
cli_access_enabled: bool = False
access_key: str | None = None
auto_mount: bool = False
created_at: datetime
updated_at: datetime
AppSettings
@dataclass
class AppSettings:
theme: str = "dark" # dark | light
language: str = "en" # en | de
start_with_windows: bool = False
minimize_to_tray: bool = True
auto_login_with_windows: bool = False
auto_reconnect: bool = False
auto_reconnect_mounts_on_start: bool = True
check_interval_seconds: int = 30
debug_mode: bool = False
use_putty: bool = False
putty_path: str = r"C:\Program Files\PuTTY\putty.exe"
Build & release process
- Version in
file_version_info.txt, README undchangelog.htmlerhöhen. .\build_dual.ps1ausführen — baut GUI- und CLI-EXE per PyInstaller indist/.- Beide EXEs lokal testen (Login, ein Mount, ein CLI-Aufruf).
- Tag setzen:
git tag v1.x.0 && git push --tags. - Auf GitHub neues Release anlegen, beide EXEs anhängen, Changelog einfügen.