Metadata-Version: 2.4
Name: remctl
Version: 0.1.1
Summary: Secure LAN-based remote PC control and administration
Author: remctl contributors
License: MIT
License-File: LICENSE
Keywords: administration,lan,remote-control
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: System :: Networking
Requires-Python: >=3.11
Requires-Dist: cryptography>=42
Requires-Dist: mss>=9.0
Requires-Dist: psutil>=5.9
Requires-Dist: pydantic>=2
Requires-Dist: pywin32>=306; sys_platform == 'win32'
Requires-Dist: rich>=13
Requires-Dist: typer>=0.12
Requires-Dist: zeroconf>=0.132
Provides-Extra: dev
Requires-Dist: mypy>=1.8; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest-mock>=3; extra == 'dev'
Requires-Dist: pytest>=7; extra == 'dev'
Requires-Dist: ruff>=0.3; extra == 'dev'
Description-Content-Type: text/markdown

# remctl

**Secure, LAN-based remote PC control and administration.**

`remctl` lets you control machines on your local network from the command line —
lock, shutdown, execute shell commands with streaming output, transfer files,
take screenshots, and check system status. All communication is authenticated
using Ed25519 keys and encrypted with AES-256-GCM.

> ⚠️ **Intended for your own trusted LAN devices only.** `remctl` is not designed
> for Internet-facing use. Do not expose it via port forwarding or NAT.

## Installation

```bash
pip install remctl
```

### From source

```bash
# TODO: user adds PyPI API token via env var / twine config before publishing
git clone <repo-url>
cd remctl
pip install -e ".[dev]"
```

## Quick Start (Easy Mode)

### On the target machine (the node)

```bash
# First run starts a short setup wizard (name, admin, acceptance mode),
# then runs the agent in the foreground:
remctl node start
```

The wizard asks three things:

1. **Node name** — a friendly name broadcast on your LAN (e.g. `livingroom-pc`).
2. **Allow admin (exec/shell) commands?** — grants the `full` tier to new
   controllers, otherwise they get `standard` (no exec).
3. **Acceptance mode** for new controllers:
   - `auto` — trust any controller that connects (easiest, least safe)
   - `ask` — ask for approval on **every** connection
   - `ask-new` — ask only the first time a controller connects *(recommended)*

You can re-run the wizard any time with `remctl node setup`, or start without it
using the stored config via `remctl node start`.

### On the controlling machine

```bash
# Find nodes on the LAN (lists them by name)
remctl ctl scan

# Connect to one by name — this pairs it and makes it the active node
remctl ctl connect livingroom-pc

# Now run actions on the active node
remctl ctl actions list                       # what can I do?
remctl ctl actions status
remctl ctl actions lock
remctl ctl actions shutdown --delay 60
remctl ctl shell "whoami"                      # = actions exec
```

If you have more than one node, target a specific one with `--node`:

```bash
remctl ctl actions status --node bedroom-pc
remctl ctl nodes                               # list paired nodes + active
remctl ctl forget livingroom-pc                # remove a paired node
```

## Advanced: Manual Two-Way Pairing

If you prefer explicit key exchange (no acceptance-mode prompts), use the
original flow. Both sides must still trust each other:

```bash
# Node: show its fingerprint
remctl node pair --show
remctl node start

# Controller: pair + show its own fingerprint for the node to trust
remctl ctl pair <node-ip>
remctl ctl pair-show

# Node: trust the controller's public key file
remctl node trust-controller /path/to/controller_identity.pub
```

Legacy per-command form (still works, defaults to the active node):

```bash
remctl ctl <target> status
remctl ctl <target> lock
remctl ctl <target> exec "whoami"
remctl ctl <target> screenshot -o screenshot.png
remctl ctl <target> push ./file.txt /remote/path/file.txt
remctl ctl <target> pull /remote/log.log ./log.log
```

## Command Reference

| Command | Description |
|---------|-------------|
| `remctl node start` | First-run wizard (if needed) then start the node agent |
| `remctl node setup` | Run the setup wizard (name, admin, acceptance mode) |
| `remctl node install-service` | Install as OS service |
| `remctl ctl scan` | Discover nodes on the LAN (by name) |
| `remctl ctl connect <name>` | Pair with a node and make it active |
| `remctl ctl nodes` | List paired nodes + active |
| `remctl ctl forget <name>` | Remove a paired node |
| `remctl ctl actions list` | List available actions + tiers |
| `remctl ctl actions <action> [--node <name>]` | Run a named action on the active node |
| `remctl ctl shell "<cmd>"` | Alias for `actions exec` |
| `remctl ctl discover` | Discover nodes on LAN (legacy) |
| `remctl ctl pair <target>` | Pair with a node (manual flow) |
| `remctl ctl <target> lock` | Lock the remote workstation |
| `remctl ctl <target> shutdown --delay 60` | Shutdown with optional delay |
| `remctl ctl <target> restart` | Restart |
| `remctl ctl <target> sleep` | Sleep/Suspend |
| `remctl ctl <target> logout` | Log out current user |
| `remctl ctl <target> closefocused` | Close active window |
| `remctl ctl <target> exec <command>` | Execute shell command (streamed) |
| `remctl ctl <target> status` | Show system status (CPU/mem/disk/uptime) |
| `remctl ctl <target> screenshot -o out.png` | Capture screenshot |
| `remctl ctl <target> push <local> <remote>` | Push file to node |
| `remctl ctl <target> pull <remote> <local>` | Pull file from node |
| `remctl ctl <target> cancel` | Cancel pending shutdown/restart |

## Security Model (Summary)

- **Identity:** Ed25519 keypairs generated on first run.
- **Authentication:** Node accepts controllers per its **acceptance mode**
  (`auto` / `ask` / `ask-new`). Default is `ask-new` — no auto-trust unless you
  opt in. The manual two-way `trust-controller` flow still works.
- **Encryption:** X25519 ECDH key exchange → AES-256-GCM, with forward secrecy.
- **Replay protection:** Per-message sequence numbers + 30-second timestamp window.
- **Permission tiers:** `observe` (status/screenshot), `standard` (commands +
  files), `full` (includes `exec`). Default for new controllers: `standard`.
- **Audit log:** All commands logged unredacted at `~/.remctl/audit.log`.

See [docs/SECURITY.md](docs/SECURITY.md) for the full threat model.

## Configuration

All config files live in `~/.remctl/`:

| File | Purpose |
|------|---------|
| `identity.key` | Private key (keep secure) |
| `identity.pub` | Public key |
| `known_nodes.json` | Paired nodes (ctl side) |
| `known_controllers.json` | Trusted controllers (node side) |
| `node_config.json` | Node settings (name, bind, port, acceptance mode, tiers) |
| `ctl_config.json` | Controller settings (active node) |
| `audit.log` | Command audit log |

## Platform Support

| Platform | Status |
|----------|--------|
| Windows | First-class |
| Linux | Second-class (best-effort) |
| macOS | Not yet implemented |

## Publishing to PyPI

```bash
python -m build
twine upload dist/*
```

You need a **PyPI API token** (not your password):

1. Create a free account at https://pypi.org
2. Go to https://pypi.org/manage/account/token/ and generate a token scoped to `remctl`
3. Copy `.env.example` to `.env` and fill in the token, or set these env vars:

```bash
export TWINE_USERNAME=__token__
export TWINE_PASSWORD=pypi-xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

> See [.env.example](.env.example) for the full list of configurable secrets.
> No credentials are included in the repository.
