unifly

repository·main·Indexed 42 days ago

https://github.com/hyperb1iss/unifly

A CLI and TUI toolkit for managing Ubiquiti UniFi network controllers. It unifies various UniFi API dialects (Local, Cloud, Site Manager) into a single interface for human operators and automated agents. Features include a real-time 11-screen TUI dashboard, 28 top-level automation commands with machine-readable output (JSON, YAML), and the unifly-api async Rust client for programmatic integration with UniFi's Integration and Session APIs.

Tokens
111.4K
Snippets
353
Records
562
Agent score
55%

What's inside unifly

  1. What is unifly?

    main

    unifly is a command-line toolkit for managing Ubiquiti UniFi network controllers. It provides a single binary with 28 top-level commands for automation and scripting, alongside a built-in Terminal User Interface (TUI) for real-time monitoring.

    Key capabilities include:

    • Unified API Engine: Supports Integration API, Session API (via UniFi OS API keys), Site Manager cloud fleet APIs, and the cloud connector.
    • Real-Time Monitoring: An 11-screen TUI featuring traffic charts, CPU/MEM gauges, and zoomable topology.
    • Observability: Wi-Fi experience scores, neighboring AP detection, and live event streaming via WebSockets.
    • Automation-Friendly: Pipe-friendly output in Table, JSON, compact JSON, YAML, and plain text formats.
  2. Overview of Unifly CLI and TUI

    main

    Unifly provides two primary interfaces for managing UniFi infrastructure directly from the terminal, eliminating the need for the web dashboard:

    • unifly <command>: A CLI designed for scripting, automation, and quick lookups.
    • unifly tui: A real-time terminal dashboard for monitoring network status.

    Both interfaces are powered by a shared async engine that automatically handles routing, authentication, and data merging across different UniFi API dialects.

  3. Perform a UniFi Security Audit with unifly-audit

    main

    The unifly-audit tool performs a security-focused audit of your UniFi configuration. It identifies vulnerabilities such as open WiFi networks, permissive firewall rules, outdated device firmware, and network isolation issues. Findings are categorized by severity levels:

    • CRITICAL: Open WiFi networks, no firewall between zones.
    • HIGH: WPA2-only networks, allow-all firewall rules, no logging.
    • MODERATE: Outdated firmware, unused networks.
    • INFO: Network isolation status, device counts.
  4. Overview of unifly-api API surfaces

    main

    The unifly-api crate provides an async Rust client for communicating with Ubiquiti UniFi Network controllers via two distinct API surfaces:

    1. Integration API: A RESTful OpenAPI-based interface. It uses X-API-KEY header authentication and is the primary surface for CRUD operations on managed entities like devices, clients, networks, and firewall rules.
    2. Session API: Authenticated via session cookies and CSRF tokens (under /proxy/network/api/ and /proxy/network/v2/api/), or via X-API-KEY on UniFi OS session HTTP. This surface provides access to events, traffic stats, Wi-Fi observability, DPI, admin users, system info, switch port management, firewall groups, site settings, and the WebSocket event stream.
  5. Choose a Controller connection mode in unifly-api

    main

    When using the unifly-api library, you can choose between two connection modes depending on your use case:

    1. Controller::connect(): Use this for long-running applications (like a TUI). It manages the full lifecycle, including background data refreshes and real-time WebSocket event handling.
    2. Controller::oneshot(): Use this for short-lived tasks (like a CLI command). It is a "fire-and-forget" mode that does not spawn background refresh tasks.
  6. Key capabilities of unifly

    main

    unifly provides several advanced features for UniFi management:

    • Dual-API enrichment: Merges data from the Integration and Session APIs. This is useful because certain data (like client bytes, hostnames, and uplink MACs) only exists in the Session API, while configuration CRUD requires the Integration API.
    • Real-time event streaming: Use unifly events watch to stream live events over WebSockets (requires session or hybrid mode).
    • Firewall policy reordering: Use reorder --get and reorder --set for deterministic, round-trippable ordering of firewall rules.
    • Raw API access: Use unifly api as an escape hatch to call endpoints not explicitly wrapped by the CLI.
    • Multi-profile management: Use the -p flag (e.g., -p home, -p office) to manage multiple controllers from a single CLI instance.
  7. How the Dual-API Architecture works in unifly

    main

    unifly uses two distinct APIs to provide a complete view of the UniFi network. Understanding the difference is critical for choosing the correct authentication mode and knowing which commands are available.

    Integration API

    • Purpose: Best for Configuration CRUD (networks, WiFi, firewall policies/zones, DNS, ACL, traffic lists, hotspot, WANs, RADIUS, VPN servers/tunnels).
    • Auth: Uses an API key in the X-API-KEY header.
    • Format: Modern JSON with UUIDs; returns clean, well-typed responses without envelopes.
    • Limitations: Lacks device-level operations, historical stats, WebSocket events, and certain client enrichment fields (e.g., bytes, hostname, VLAN).

    Session API

    • Purpose: Best for Events (WebSocket), stats, device commands (restart, adopt, locate, upgrade, provision), DPI, admin management, backups, and site management.
    • Auth: Uses session cookies and CSRF tokens (or X-API-KEY on UniFi OS for HTTP routes).
    • Format: Envelope-wrapped JSON ({"meta": {...}, "data": [...]}).
    • Capabilities: Provides everything the controller web UI sees, including fields omitted by the Integration API.

    Hybrid Mode

    Hybrid mode merges both APIs at login. For commands like devices list or clients list, unifly fetches data from the Integration API and then supplements it with Session API fields (e.g., tx_bytes, rx_bytes, hostname, wireless, vlan). This is the recommended mode for maximum compatibility and live WebSocket features (events watch).

  8. Unifly Architecture and Library Usage

    main

    Unifly is composed of two main parts:

    1. unifly: The single binary containing both the CLI and the TUI.
    2. unifly-api: A library crate available on crates.io for Rust developers.

    If you are building custom integrations in Rust, you should use the unifly-api crate. The library manages the following components:

    • Integration Client: Handles REST + API Key.
    • Session Client: Handles Cookie + CSRF.
    • WebSocket: Handles Live Events.
    • DataStore: Uses DashMap and watch channels for state management.
  9. Understand unifly configuration precedence

    main

    When a setting is requested, unifly resolves the value using the following priority (highest to lowest):

    1. CLI flags (e.g., --controller, --site, -o json)
    2. Environment variables (e.g., UNIFI_URL, UNIFI_API_KEY)
    3. Profile config (the specific [profiles.<name>] section in config.toml)
    4. Default values (the [defaults] section in config.toml, then built-in defaults)

    Special Resolution Rules

    • Timeout: Resolves via Flag $\rightarrow$ Env $\rightarrow$ Profile timeout $\rightarrow$ [defaults].timeout $\rightarrow$ Built-in (30s).
    • TLS/Insecure: An explicit insecure = true (via flag, env, or profile) skips verification. If not explicitly set, a profile's ca_cert takes precedence over [defaults].insecure = true. Passing --insecure=false forces verification regardless of configuration.
  10. Understand the unifly-api architecture

    main

    The library is organized into several layers that work together to provide a reactive data experience:

    • Controller: The main entry point that routes requests and manages the lifecycle.
    • Clients: IntegrationClient (REST + API Key) and SessionClient (Cookie + CSRF) handle the actual communication with the UniFi controller.
    • WebSocket: Provides live event updates.
    • DataStore: Uses DashMap and watch channels to store entities in a lock-free manner.
    • EntityStream<T>: Provides reactive subscriptions. Use .current() for a snapshot and .changed() to await updates. .changed() returns None when the controller disconnects.
  11. Choose the right client approach

    main

    Select the appropriate client based on your application's requirements:

    ApproachUse Case
    IntegrationClientDirect REST calls, custom query patterns, Integration API only
    SessionClientEvents, stats, device commands, Session API only
    ControllerFull lifecycle with both APIs, automatic refresh, reactive subscriptions
    Controller::oneshot()Single CLI-style fetch with no background tasks
  12. Limitations of Cloud Mode (What stays Session-Only)

    main

    The cloud connector only proxies the Integration API. Features that require a direct connection to the controller (Session-backed features) will not work in cloud mode. These include:

    • events list / events watch and live event streams.
    • stats (historical reports) and DPI status/control.
    • Device commands (e.g., restart, adopt, locate, upgrade, speedtest).
    • Switch port configuration, firewall groups, NAT, and site settings.
    • The Session-backed VPN surface.
    • Admin management and backups.

    To use these features, you must use a direct profile (integration, session, or hybrid) from a network that has a direct path to the controller. You can switch between profiles per-command using the -p flag.