Metadata-Version: 2.4
Name: wg-api-client
Version: 0.2.0
Summary: WireGuard Configuration API Client
Home-page: https://github.com/tiiuae/wg-api-client-lib
Author: TII UAE
Author-email: info@tii.ae
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: System :: Networking
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.25.0
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: license-file
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# WireGuard API Client

Python client library and CLI for the WireGuard Config Distributor API.
Handles authentication, device registration, cluster management,
and WireGuard configuration file generation.

## Installation

```bash
pip install wg-api-client
```

From source:

```bash
git clone https://github.com/tiiuae/wg-api-client-lib.git
cd wg-api-client-lib
pip install -e .
```

Requires `wireguard-tools` for key generation:

```bash
sudo apt install -y wireguard-tools
```

## Configuration

All configuration is done via environment variables, CLI flags, or config file.
No defaults are hardcoded for credentials or API URL.

### Environment Variables

| Variable            | Description                    |
| ------------------- | ------------------------------ |
| `WG_API_URL`        | API base URL                   |
| `WG_API_CREDENTIAL` | SHA-256 hashed credential      |
| `WG_API_CA_CERT`    | Path to CA cert bundle for TLS |

### Config File

Stored at `~/.wg_api_config` (permissions 0600). Created on first `auth`.

## CLI Usage

### Global Flags

```text
--api-url URL              API base URL (env: WG_API_URL)
--hashed-credential HASH   Hashed credential (env: WG_API_CREDENTIAL)
--ca-cert PATH             CA certificate bundle (env: WG_API_CA_CERT)
--config-file PATH         Config file path (default: ~/.wg_api_config)
```

### Authentication

```bash
wg-api-client --api-url https://vpn.example.com/api/v1 auth
```

### Register a Device

```bash
wg-api-client get-config \
  --cluster-id <CLUSTER_ID> \
  --role node \
  --output wg.conf
```

Options for `get-config`:

| Flag            | Description                                  |
| --------------- | -------------------------------------------- |
| `--cluster-id`  | Cluster to join (required)                   |
| `--role`        | Device role: `node`, `controller`, or `uxu`  |
| `--device-id`   | Custom device ID (auto-generated if omitted) |
| `--public-key`  | WireGuard public key (generated if omitted)  |
| `--output`      | Output file (default: `wg.conf`)             |
| `--allowed-ips` | Additional allowed IP ranges (repeatable)    |
| `--table`       | Routing table name                           |
| `--listen-port` | WireGuard listen port                        |

### Cluster Management (admin)

```bash
wg-api-client create-cluster production
wg-api-client list-clusters
wg-api-client get-cluster <CLUSTER_ID>
wg-api-client delete-cluster <CLUSTER_ID>
wg-api-client get-controller <CLUSTER_ID>
wg-api-client list-cluster-devices <CLUSTER_ID>
```

### Device Management (admin)

```bash
wg-api-client list-devices
wg-api-client get-device <DEVICE_ID>
wg-api-client delete-device <DEVICE_ID>
wg-api-client delete-all-devices --confirm
```

### Other Commands

```bash
wg-api-client get-uxu
wg-api-client add-credential --hashed-credential <HASH> --role admin
```

## Device Roles

| Role       | Description                             | Default |
| ---------- | --------------------------------------- | ------- |
| node       | Spoke device, can only reach controller | yes     |
| controller | Hub device, one per cluster             | no      |
| uxu        | Operator laptop, global access, unique  | no      |

## Python Library

### Basic Usage

```python
from wg_api_client import WireGuardAPI, WireGuardHelper
from wg_api_client.unique_id import get_unique_device_id

api = WireGuardAPI(
    api_url="https://vpn.example.com/api/v1",
    hashed_credential="your-sha256-hash",
)

success, message = api.authenticate()

private_key, public_key = WireGuardHelper.generate_keypair()
device_id = get_unique_device_id()

success, config_data = api.request_wireguard_config(
    device_id=device_id,
    role="node",
    public_key=public_key,
    cluster_id="your-cluster-id",
)

if success:
    WireGuardHelper.create_client_config(
        config_data,
        "wg.conf",
        private_key=private_key,
    )
```

### Cluster Operations

```python
success, data = api.create_cluster("production")
cluster_id = data["id"]

success, clusters = api.list_clusters()
success, devices = api.list_cluster_devices(cluster_id)
success, controller = api.get_cluster_controller(cluster_id)
success, message = api.delete_cluster(cluster_id)
```

### Admin Operations

```python
success, devices = api.list_devices()
success, device = api.get_device("device-id")
success, message = api.delete_device("device-id")
success, uxu = api.get_uxu_device()
success, message = api.add_credential("sha256-hash", "admin")
```

### API Reference

#### WireGuardAPI

| Method                       | Description                 | Auth  |
| ---------------------------- | --------------------------- | ----- |
| `authenticate()`             | Login, get JWT token        | cred  |
| `refresh_auth_token()`       | Refresh expired token       | token |
| `ensure_authenticated()`     | Auto-refresh if needed      | auto  |
| `request_wireguard_config()` | Register device, get config | JWT   |
| `list_devices()`             | List all devices            | admin |
| `get_device(id)`             | Get device details          | admin |
| `delete_device(id)`          | Delete device               | admin |
| `delete_all_devices()`       | Delete all devices          | admin |
| `create_cluster(name)`       | Create cluster              | admin |
| `list_clusters()`            | List clusters               | admin |
| `get_cluster(id)`            | Get cluster                 | admin |
| `delete_cluster(id)`         | Delete cluster and devices  | admin |
| `get_cluster_controller(id)` | Get cluster controller      | admin |
| `list_cluster_devices(id)`   | List devices in cluster     | admin |
| `get_uxu_device()`           | Get UXU device              | admin |
| `add_credential(hash, role)` | Add credential              | admin |

#### WireGuardHelper

| Method                   | Description                        |
| ------------------------ | ---------------------------------- |
| `generate_keypair()`     | Generate WireGuard key pair        |
| `create_client_config()` | Write WireGuard config file (0600) |

#### ConfigManager

| Method                     | Description           |
| -------------------------- | --------------------- |
| `load_config()`            | Load from file        |
| `save_config()`            | Save to file (0600)   |
| `get_api_url()`            | Get stored API URL    |
| `set_api_url(url)`         | Set API URL           |
| `get_hashed_credential()`  | Get stored credential |
| `set_hashed_credential(c)` | Set credential        |
| `get_token()`              | Get stored JWT token  |
| `set_token(token)`         | Set JWT token         |

## Security

- No hardcoded credentials or API URLs
- Credentials accepted via env var only (not visible in process list)
- TLS verification enabled by default, custom CA bundle supported
- Config and key files written atomically with 0600 permissions
- Private keys passed explicitly through call chain (no class-level state)
- API response data validated before writing to config files
- URL path parameters are percent-encoded
- Error messages do not leak internal details

## Development

```bash
pip install -r requirements-dev.txt
pip install -e .
```

### Test

```bash
pytest -v
```

### Lint

```bash
black --check wg_api_client/ tests/
isort --check wg_api_client/ tests/
flake8 wg_api_client/ tests/ --max-line-length 120
```

## License

Apache 2.0
