Metadata-Version: 2.4
Name: turbossh
Version: 0.18.4
Summary: TurboSSH — SSH / Serial / SFTP / SCP / FTP / RDP terminal & automation toolkit for automotive & embedded (Python API, CLI, and a full PyQt5 GUI with a VT100 terminal).
Author: TurboSSH contributors
License-Expression: MIT
Keywords: ssh,sftp,scp,ftp,paramiko,automation,pyqt5,testing
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Classifier: Topic :: System :: Networking
Classifier: Topic :: Software Development :: Testing
Classifier: Intended Audience :: Developers
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: paramiko>=3.0
Requires-Dist: scp>=0.14
Requires-Dist: pyserial>=3.5
Requires-Dist: keyring>=23.0
Requires-Dist: pywinrm>=0.4.3
Requires-Dist: pyte>=0.8.1
Provides-Extra: gui
Requires-Dist: PyQt5>=5.15; extra == "gui"
Provides-Extra: all
Requires-Dist: PyQt5>=5.15; extra == "all"
Dynamic: license-file

# TurboSSH

[![PyPI](https://img.shields.io/pypi/v/turbossh.svg)](https://pypi.org/project/turbossh/)
[![Python](https://img.shields.io/pypi/pyversions/turbossh.svg)](https://pypi.org/project/turbossh/)

**TurboSSH** is an SSH / Serial / SFTP / SCP / FTP / RDP terminal and automation
toolkit built on [Paramiko](https://www.paramiko.org/) — for automotive &
embedded work, test automation, and everyday remote ops. It ships three ways in
one install:

1. **Python API** — `import turbossh` for scripts and test frameworks.
2. **CLI** — `turbossh …`, fully argument-driven.
3. **GUI** — `turbossh-gui`, a tabbed multi-session terminal with a true **VT100
   emulator** (htop / vim / top work), an **SFTP browser**, **serial** consoles,
   and **RDP** launch. Ships as a **prebuilt Windows exe** (PyQt5 baked in — no
   PyQt5 install needed, even on Windows ARM64).

```bash
pip install turbossh
turbossh-gui
```

---

## Table of contents
- [Install](#install)
- [The GUI](#the-gui)
- [Quick start (API)](#quick-start-api)
- [Connecting — local, jump host, RDP](#connecting--local-jump-host-rdp)
- [Running commands](#running-commands)
- [Continuous logs](#continuous-logs)
- [File transfer — SFTP / SCP / FTP](#file-transfer--sftp--scp--ftp)
- [Serial / COM ports](#serial--com-ports)
- [Port forwarding (tunnels)](#port-forwarding-tunnels)
- [Keys & passwordless setup](#keys--passwordless-setup)
- [Automotive / legacy devices](#automotive--legacy-devices)
- [Confidential credentials](#confidential-credentials)
- [Enable SSH on a Windows box (offline)](#enable-ssh-on-a-windows-box-offline)
- [CLI reference](#cli-reference)
- [Result objects & error handling](#result-objects--error-handling)
- [Full Paramiko capability](#full-paramiko-capability)
- [API map](#api-map)

## Install

```bash
pip install turbossh           # API + CLI + prebuilt Windows GUI exe
pip install "turbossh[gui]"    # also installs PyQt5 to run the GUI from source
```

Batteries included: `paramiko`, `scp`, `pyserial`, `keyring`, `pywinrm`, and
`pyte` (VT100) are pulled in automatically. Only PyQt5 is optional — the shipped
GUI exe already contains it, so `turbossh-gui` works without installing PyQt5.

## The GUI

```bash
turbossh-gui
```

- **Session manager sidebar** — saved SSH / Serial / RDP sessions (right-click for
  New / Open / Edit / Duplicate / Delete). Passwords live in the OS credential
  vault, never in plaintext. A **Quick connect** box filters as you type.
- **Tabbed sessions** + a **`+`** button; **Split** tiles several sessions in a grid.
- **True VT100 terminal** (pyte) — full-screen apps (htop, vim, top, less, nano)
  render correctly, with colors, a block cursor, and live PTY resize.
- **Quick buttons** — one-click `slog2info -w`, `journalctl -f`, `dmesg -w`,
  `tail -f`, plus Ctrl-C and Clear.
- **Split SFTP browser** under each terminal — navigate, upload, download, mkdir,
  rename, delete (transfers on a separate channel; the UI never blocks).
- **Serial console** and **RDP launch** as session types.
- **Settings** — dark/light theme, terminal font + size, default baud (persisted,
  applied live). **MultiExec** broadcasts a command to all open SSH tabs.
- **Crash-proof** — all I/O on background threads; a startup failure shows a popup
  and writes a crash log; runtime errors are logged, never fatal.

## Quick start (API)

```python
from turbossh import SSHHandler, SSHConfig

with SSHHandler(SSHConfig(host="10.0.0.5", username="root", password="pw")) as ssh:
    print(ssh.run("uname -a").text)            # clean single-line output
    ssh.run("systemctl restart nginx", check=True)
    ssh.push("local.txt", "/tmp/remote.txt")
    ssh.pull("/etc/nginx", "./backup", recursive=True)
```

## Connecting — local, jump host, RDP

```python
# direct
cfg = SSHConfig(host="10.0.0.5", username="root", password="pw",
                host_key_policy="ignore")          # ignore = lab/reimaged devices

# through a bastion/jump (laptop -> jump -> target)
jump = SSHConfig(host="10.232.9.22", domain="CORP", username="user", password="pw")
cfg  = SSHConfig(host="10.120.1.91", username="root", password="pw", jump_host=jump)
```

| `host_key_policy` | Behaviour |
|---|---|
| `"auto"` (default) | add unknown keys, **reject changed** keys |
| `"ignore"` | accept any key incl. changed — for reimaged/DHCP lab devices |
| `"reject"` | strict; only keys already in known_hosts |

Auth is auto-selected: password, private key (+ passphrase), agent / discovered
keys, empty-password accounts, or `passwordless=True`. Connects retry with
backoff and reconnect automatically; a failed connect self-diagnoses (probes the
SSH/RDP ports and explains why).

## Running commands

```python
r = ssh.run("ls -la", timeout=30, check=False)
print(r.text, r.exit_code, r.ok, r.duration)
ssh.run_many(["a", "b", "c"], stop_on_error=True)
ssh.sudo("systemctl restart app", password="pw")
with ssh.open_shell() as sh:                    # interactive send/expect
    sh.send("cd /var/log"); print(sh.read_until("$", timeout=5).output)
```

## Continuous logs

```python
ssh.stream("slog2info -w", on_line=print,
           match=r"error|fail", save_to="device.log", timeout=120)  # ANSI auto-cleaned
for line in ssh.iter_lines("journalctl -f"):
    print(line)
```

## File transfer — SFTP / SCP / FTP

```python
ssh.push("fw.bin", "/tmp/fw.bin")                 # SFTP upload
ssh.pull("/var/log/messages", "messages.log")     # SFTP download
ssh.push("./build", "/tmp/build", recursive=True) # folder, progress callback
ssh.scp_push("img.tar", "/tmp/img.tar")           # SCP protocol

from turbossh import FTPHandler, FTPConfig
with FTPHandler(FTPConfig(host="ftp.x", username="u", password="p", use_tls=True)) as ftp:
    ftp.push("a.txt", "a.txt"); ftp.pull("b.txt", "b.txt")
```
Through a jump host, transfers ride the tunnel automatically. Remote FS helpers:
`listdir, stat, exists, isdir, mkdir, makedirs, rename, remove, chmod, read_text,
write_text, walk`.

## Serial / COM ports

```python
# local port (device plugged into THIS machine)
from turbossh import SerialHandler, list_serial_ports
print(list_serial_ports())
with SerialHandler("COM5", baudrate=115200) as ser:
    ser.write_line("version")
    ser.stream(on_line=print, match=r"login:", save_to="com5.log")

# port on a REMOTE machine, over SSH/jump (COM = Windows, /dev/tty* = Linux)
ssh.serial_write("COM5", "version", baudrate=115200)
ssh.serial_stream("COM5", baudrate=115200, on_line=print, match=r"login:",
                  save_to="com5.log")
```

## Port forwarding (tunnels)

```python
# ssh -L : reach a remote service on a local port (e.g. a web UI behind the host)
fwd = ssh.forward_local("127.0.0.1", 8080, local_port=18080)
print("now browse http://127.0.0.1:%d" % fwd.local_port)
fwd.close()

# ssh -R : expose a local service on a remote port
rfwd = ssh.forward_remote(9000, "127.0.0.1", 3000)
rfwd.close()
```
Both work through a jump host and return a handle with `.close()` (or use as a
context manager).

## Keys & passwordless setup

```python
from turbossh import generate_keypair
generate_keypair("~/.ssh/turbo_key")          # writes turbo_key and turbo_key.pub

# deploy it (ssh-copy-id) so future logins are passwordless
ssh.copy_id(public_key_file="~/.ssh/turbo_key.pub")
```

## Automotive / legacy devices

Old ECUs / embedded SSH servers often use crypto modern Paramiko drops. Re-enable it:

```python
cfg = SSHConfig(host="10.0.0.9", username="root", password="pw",
                enable_legacy_algorithms=True)     # old KEX/ciphers/host-keys
# fine-grained: disabled_algorithms={"pubkeys": ["rsa-sha2-512"]}
```
In the GUI, tick **"Enable legacy algorithms"** in the session dialog.

## Confidential credentials

| Mechanism | What it does |
|---|---|
| `Secret` | wraps a password; logs/reprs show `********`; only `.reveal()` exposes it |
| `mask()` | redacts secrets from any string (applied to all logging automatically) |
| `CredentialStore` | stores/reads passwords in the OS vault via `keyring` — no plaintext |
| `prompt_password()` | hidden terminal input |

## Enable SSH on a Windows box (offline)

```powershell
turbossh-setup            # self-elevates, installs OpenSSH Server from a bundled
                          # ZIP (ARM64/Win64/Win32), starts sshd, opens firewall,
                          # generates + fixes host keys. No internet / Windows Update.
```
Or auto-enable a remote box over WinRM: `SSHConfig(auto_bootstrap_via_winrm=True)`.

## CLI reference

```bash
turbossh run    --host H --user U [--domain CORP] [--use-stored] uname -a
turbossh push   --host H --user U ./build /tmp/build --recursive
turbossh pull   --host H --user U /var/log ./logs --recursive
turbossh info   --host H --user U --json
turbossh store-credential --user U --domain CORP --service my_lab
turbossh-gui              # launch the GUI
turbossh-setup            # install OpenSSH Server on this machine (offline)
turbossh-shortcut         # create a Desktop shortcut to the GUI
turbossh-docs             # open the docs
```

## Result objects & error handling

- `CommandResult` — `.exit_code`, `.stdout`, `.text`, `.stderr`, `.duration`, `.ok`
- `TransferResult` — `.size_bytes`, `.duration`, `.human_speed`, `.files`
- `OperationResult` — safe-mode wrapper: `bool(res)`, `.value`, `.error`, `.unwrap()`

**Raise mode** (default): typed exceptions — `SSHConnectionError`,
`SSHAuthenticationError`, `SSHTimeoutError`, `SSHCommandError`, `SSHTransferError`,
`FTPError`, `SerialError`, `WinRMError`, `CredentialError` (all subclass `SSHError`).

**Safe mode** (`SSHHandler(cfg, safe=True)`): every call returns an
`OperationResult` instead of raising — ideal for GUIs and long-running tools.

## Full Paramiko capability

TurboSSH wraps the common operations with retries, structured results, and safe
secrets — but it never hides Paramiko. Anything Paramiko can do is available:

- **Commands / shells** — `run`, `run_many`, `sudo`, `open_shell`, `stream`, `iter_lines`
- **SFTP** — full file operations + recursive `push`/`pull` with progress
- **SCP** — `scp_push` / `scp_pull`
- **Port forwarding** — `forward_local` (`-L`), `forward_remote` (`-R`)
- **Keys** — `generate_keypair`, `copy_id` (ssh-copy-id)
- **Jump host / ProxyJump** — `SSHConfig(jump_host=…)`
- **Algorithm control** — `enable_legacy_algorithms`, `disabled_algorithms`
- **Keepalives, compression, timeouts, host-key policy** — all on `SSHConfig`
- **Raw escape hatch** — `ssh.client` (the `paramiko.SSHClient`) and `ssh.transport`
  (the `paramiko.Transport`) are exposed, so any lower-level Paramiko call works:

```python
transport = ssh.transport
sftp = ssh.client.open_sftp()
chan = transport.open_session()
# …anything Paramiko supports
```

## API map

```
turbossh/
  config.py        SSHConfig (jump, legacy algos, host-key policy…), FTPConfig
  core.py          SSHHandler  (SSH + SFTP + SCP + stream + serial + tunnels +
                                keys + diagnose), ShellSession
  tunnel.py        LocalForward, RemoteForward, generate_keypair
  serial_handler.py  SerialHandler, list_serial_ports
  ftp.py           FTPHandler (FTP/FTPS)
  winrm_bootstrap.py  enable_openssh_via_winrm
  pool.py          SSHPool (parallel multi-host)
  credentials.py   Secret, CredentialStore, mask, prompt_password
  results.py       CommandResult, TransferResult, ShellResult, OperationResult
  cli.py           CLI + launchers (gui / docs / setup / shortcut / rdp)
  pyqt_worker.py   SSHWorker (embed in your own PyQt5 app)
  bin/turbossh-gui.exe   prebuilt GUI (PyQt5 baked in)
  gui/             the desktop app
    vt100.py       true VT100 terminal (pyte) — htop/vim render correctly
    sftp_browser.py · session_widgets.py · session_dialog.py · sessions.py
    settings.py · settings_dialog.py · main_window.py · app.py · theme.py
```

## License

MIT
