Projektstruktur
Überblick über das Repository für Mitwirkende und Interessierte.
Verzeichnis-Übersicht
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
Hauptmodule
main.py
GUI entry point. In order, it:
- Loads the config (
config.AppSettings.load()). - Enforces single-instance mode (
SingleInstance("SSHWinManager_Mutex_v1")). - Initializes
QApplicationwith the saved theme. - Shows the login window (unless auto-login applies) → main window.
- Starts
IPCServerin a worker thread.
cli_main.py
Argparse CLI. Connects to \\.\pipe\SSHWinManager_IPC_v1, sends a JSON request {op:"connect", key:"…", exec:"…"}, receives credentials, then calls ssh_launcher.spawn_session().
src/config.py
AppSettings— dataclass with defaults (theme, language, PuTTY path, auto-reconnect, check interval, tray, debug, …).load()/save()— JSON in%APPDATA%\SSHWinManager\config.json.- Migrations: missing keys are filled with defaults.
src/database.py
- SQLite, path:
%APPDATA%\SSHWinManager\app.db. - Tables:
users,connections,settings_per_user. - Schema version in
PRAGMA user_version;migrate()adds new columns idempotently.
src/auth_manager.py
UserManager— create, sign in, change password, delete.- Password hash: PBKDF2-HMAC-SHA256, per-user salt, 200k iterations.
- The session key is derived at sign-in and kept only in RAM.
UserConnectionManager— CRUD for connections, automatic encryption/decryption per user.
src/sshfs_controller.py
SSHFSController.mount(connection, password=None)— builds the argument list and startssshfs.exeas a detached subprocess.unmount(letter)— three strategies (see Connections).list_mounts()— parses fsutil output.status_for(connection)— returns"mounted","unmounted", or"stale".
src/ssh_launcher.py
Starts an interactive SSH session. Chooses OpenSSH or PuTTY based on AppSettings.use_putty. Passes the key or password securely.
src/ipc_server.py
Worker thread with a named-pipe server. Accepts JSON requests, validates the access key against the database, and returns decrypted credentials.
UI-Module
| Datei | Aufgabe |
|---|---|
login_window.py | Login form and first-profile setup wizard. |
main_window.py | Main window: sidebar + connection list + status bar. |
tray.py | System tray icon with quick-access menu. |
widgets/connection_card.py | One card per connection with a mount toggle. |
widgets/mount_toggle.py | Custom switch with cyan/green states and spinner. |
dialogs/add_edit_dialog.py | Create / edit a connection. |
dialogs/settings_dialog.py | App-wide settings. |
dialogs/ask_password_dialog.py | Password prompt for “Ask each time”. |
dialogs/debug_dialog.py | Live log viewer with filter. |
Datenmodelle
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-Prozess
- Bump the version in
file_version_info.txt, README, andchangelog.html. - Run
.\build_dual.ps1— builds GUI and CLI EXEs with PyInstaller intodist/. - Test both EXEs locally (login, one mount, one CLI call).
- Create the tag:
git tag v1.x.0 && git push --tags. - Create a new GitHub release, attach both EXEs, and add the changelog.