Skip to main content

D-Bus API Reference

FIDO Bridge provides a D-Bus interface for service management, device pairing, and status monitoring. This interface allows external applications and scripts to interact with the FIDO Bridge daemon.

Source: /path/to/fido-bridge/crates/client/src/dbus_interface.rs

Interface Details

Bus Information

  • Bus Type: Session bus
  • Bus Name: org.fidobridge.Client
  • Object Path: /org/fidobridge/Client
  • Interface Name: org.fidobridge.Client

Registration: Lines 477-496 in dbus_interface.rs

Connecting to the Interface

The daemon automatically registers on the session bus when started. Verify it's running:

busctl --user list | grep fidobridge

Expected output:

org.fidobridge.Client    1234  fido-bridge

D-Bus Methods

All methods are defined in the #[interface(name = "org.fidobridge.Client")] block (lines 119-418).

InitiatePairing

Initiate a new pairing session with a device.

Signature: InitiatePairing(s) -> s

Parameters:

  • pin (string): 6-digit PIN for pairing. If empty string, a random PIN is generated.

Returns:

  • session_id (string): Unique session ID for this pairing attempt

Errors:

  • zbus::fdo::Error::Failed: Pairing initiation failed (network error, etc.)

Implementation: Lines 122-173

Example using busctl:

# Generate random PIN
busctl --user call org.fidobridge.Client \
/org/fidobridge/Client \
org.fidobridge.Client \
InitiatePairing s ""

# Use specific PIN
busctl --user call org.fidobridge.Client \
/org/fidobridge/Client \
org.fidobridge.Client \
InitiatePairing s "123456"

What it does:

  1. Generates random 6-digit PIN if not provided (lines 125-129)
  2. Cleans up expired pairing sessions (line 132)
  3. Creates SPAKE2 pairing manager with PIN
  4. Calls server's pairing initiation endpoint
  5. Stores session info locally with status "pending"
  6. Emits PairingRequested signal (line 169)
  7. Returns session ID to caller

ListPairingSessions

List all active pairing sessions.

Signature: ListPairingSessions() -> a(sss)

Parameters: None

Returns:

  • Array of tuples (session_id, initiator_token, pin)
    • session_id (string): Session identifier
    • initiator_token (string): Device token of initiator
    • pin (string): The 6-digit PIN for this session

Errors: None

Implementation: Lines 175-189

Example using busctl:

busctl --user call org.fidobridge.Client \
/org/fidobridge/Client \
org.fidobridge.Client \
ListPairingSessions

Output format:

a(sss) 2 "session-123" "linux-abc123" "456789" "session-456" "linux-def456" "012345"

Note: Automatically cleans up expired sessions before returning the list (line 179).

RespondToPairing

Respond to an existing pairing session (called by the responder device).

Signature: RespondToPairing(ss) -> s

Parameters:

  • session_id (string): Session ID from the initiator
  • pin (string): 6-digit PIN from the initiator

Returns:

  • device_id (string): Device ID of the paired initiator

Errors:

  • zbus::fdo::Error::Failed: Pairing failed (wrong PIN, expired session, network error, etc.)

Implementation: Lines 191-250

Example using busctl:

busctl --user call org.fidobridge.Client \
/org/fidobridge/Client \
org.fidobridge.Client \
RespondToPairing ss "session-abc123" "456789"

What it does:

  1. Creates SPAKE2 responder with provided PIN
  2. Calls server to get initiator's SPAKE2 message
  3. Derives shared secret from SPAKE2 exchange
  4. Stores paired device with shared secret
  5. Emits PairingCompleted signal (line 234)
  6. Returns initiator's device ID

GetPairingStatus

Get the current status of a pairing session.

Signature: GetPairingStatus(s) -> (ss)

Parameters:

  • session_id (string): Session ID to check

Returns:

  • Tuple (status, device_name)
    • status (string): "pending", "completed", or "expired"
    • device_name (string): Name of paired device (empty if not completed)

Errors:

  • zbus::fdo::Error::Failed: Session not found

Implementation: Lines 252-366

Example using busctl:

busctl --user call org.fidobridge.Client \
/org/fidobridge/Client \
org.fidobridge.Client \
GetPairingStatus s "session-abc123"

Output examples:

# Pending (responder hasn't responded yet)
ss "pending" ""

# Completed
ss "completed" "Android Phone"

# Expired
ss "expired" ""

What it does:

  1. Checks if session exists in local storage
  2. Validates session hasn't expired (config.pairing_timeout, default 300s)
  3. If pending, attempts to poll server for responder's message
  4. If responder has submitted, completes SPAKE2 exchange and stores paired device
  5. Emits appropriate signals (PairingCompleted or PairingFailed)
  6. Returns current status

Note: This method is designed to be polled by the initiator to detect when pairing completes.

ListPairedDevices

List all paired devices.

Signature: ListPairedDevices() -> a(sss)

Parameters: None

Returns:

  • Array of tuples (device_id, display_name, last_seen)
    • device_id (string): Unique device identifier
    • display_name (string): Human-readable device name (or "Unknown")
    • last_seen (string): RFC3339 timestamp of last activity

Errors:

  • zbus::fdo::Error::Failed: Storage error

Implementation: Lines 368-395

Example using busctl:

busctl --user call org.fidobridge.Client \
/org/fidobridge/Client \
org.fidobridge.Client \
ListPairedDevices

Output format:

a(sss) 2 "device-abc123" "Android Phone" "2025-10-06T10:30:15Z" "device-def456" "Tablet" "2025-10-05T15:20:00Z"

UnpairDevice

Remove a paired device.

Signature: UnpairDevice(s) -> b

Parameters:

  • device_id (string): Device ID to unpair

Returns:

  • success (boolean): true if device was unpaired, false if device not found

Errors:

  • zbus::fdo::Error::Failed: Storage error

Implementation: Lines 397-418

Example using busctl:

busctl --user call org.fidobridge.Client \
/org/fidobridge/Client \
org.fidobridge.Client \
UnpairDevice s "device-abc123"

Output:

b true   # Device was unpaired
b false # Device not found

GetStatus

Get current service status and configuration.

Signature: GetStatus() -> a{ss}

Parameters: None

Returns:

  • Dictionary mapping string keys to string values:
    • service: "running" (always, since you can only call this if service is running)
    • device_id: This client's device identifier
    • server_url: Current server URL
    • server_mode: "embedded" or "remote"
    • paired_devices: Number of paired devices (as string)
    • active_sessions: Number of active pairing sessions (as string)

Errors: None

Implementation: Lines 420-450

Example using busctl:

busctl --user call org.fidobridge.Client \
/org/fidobridge/Client \
org.fidobridge.Client \
GetStatus

Output format:

a{ss} 6 "service" "running" "device_id" "linux-abc123" "server_url" "http://localhost:3000" "server_mode" "embedded" "paired_devices" "2" "active_sessions" "1"

D-Bus Signals

Signals are emitted by the service to notify clients of asynchronous events. Defined in lines 452-474.

PairingRequested

Emitted when a new pairing session is initiated.

Signature: PairingRequested(ss)

Parameters:

  • pin (string): The 6-digit PIN for this pairing
  • session_id (string): Unique session identifier

Implementation: Lines 453-458, emitted at line 169

Example monitoring with busctl:

busctl --user monitor org.fidobridge.Client

Use case: UI applications can listen for this signal to display pairing QR codes or notifications.

PairingCompleted

Emitted when a pairing session successfully completes.

Signature: PairingCompleted(ss)

Parameters:

  • device_id (string): Device ID of newly paired device
  • device_name (string): Human-readable name of paired device

Implementation: Lines 460-466, emitted at lines 234, 324

Example use case: Display notification "Paired with Android Phone"

PairingFailed

Emitted when a pairing session fails or expires.

Signature: PairingFailed(ss)

Parameters:

  • session_id (string): The session that failed
  • reason (string): Human-readable error message

Implementation: Lines 468-474, emitted at lines 242, 272, 346

Common reasons:

  • "Session expired" - Timeout reached (default 300s)
  • "Pairing response failed: < error >" - Network or crypto error
  • "Message too old" - Timestamp validation failed

Background Tasks

The D-Bus service spawns background tasks for maintenance.

Session Cleanup Task

Source: Lines 520-563

What it does:

  • Runs every 60 seconds
  • Scans all pairing sessions for expired ones
  • Removes sessions older than config.pairing_timeout (default 300s)
  • Emits PairingFailed signals for expired sessions

Implementation details:

tokio::spawn( async move {
let mut interval = tokio::time::interval(tokio::time::Duration::from_secs(60));
// ... cleanup logic
});

Using the D-Bus Interface

From Command Line (busctl)

List all methods and signals:

busctl --user introspect org.fidobridge.Client /org/fidobridge/Client

Monitor all signals:

busctl --user monitor org.fidobridge.Client

From Python (python-dbus)

#!/usr/bin/env python3
import dbus
from dbus.mainloop.glib import DBusGMainLoop
from gi.repository import GLib

DBusGMainLoop(set_as_default=True)

# Connect to session bus
bus = dbus.SessionBus()

# Get proxy object
proxy = bus.get_object('org.fidobridge.Client', '/org/fidobridge/Client')
iface = dbus.Interface(proxy, 'org.fidobridge.Client')

# Call methods
status = iface.GetStatus()
print(f"Service status: {dict(status)}")

devices = iface.ListPairedDevices()
for device_id, name, last_seen in devices:
print(f"Device: {name} ({device_id}), Last seen: {last_seen}")

# Listen for signals
def on_pairing_completed(device_id, device_name):
print(f"Pairing completed: {device_name} ({device_id})")

bus.add_signal_receiver(
on_pairing_completed,
signal_name='PairingCompleted',
dbus_interface='org.fidobridge.Client',
bus_name='org.fidobridge.Client',
path='/org/fidobridge/Client'
)

# Start event loop
loop = GLib.MainLoop()
loop.run()

From Rust (zbus)

The FIDO Bridge CLI uses zbus to communicate with the daemon:

Source: /path/to/fido-bridge/crates/client/src/cli_dbus_client.rs

use zbus::{Connection, Proxy};

async fn get_status() -> anyhow::Result<HashMap<String, String>> {
let connection = Connection::session().await?;

let proxy = Proxy::new(
&connection,
"org.fidobridge.Client",
"/org/fidobridge/Client",
"org.fidobridge.Client",
).await?;

let status: HashMap<String, String> = proxy.call("GetStatus", &()).await?;
Ok(status)
}

Listening for signals (from cli_dbus_client.rs lines 139-173):

use futures_util::StreamExt;

async fn wait_for_pairing_signal() -> anyhow::Result<(String, String)> {
let connection = Connection::session().await?;
let proxy = Proxy::new(
&connection,
"org.fidobridge.Client",
"/org/fidobridge/Client",
"org.fidobridge.Client",
).await?;

let mut stream = proxy.receive_signal("PairingCompleted").await?;

while let Some(signal) = stream.next().await {
let (device_id, device_name): (String, String) =
signal.body().deserialize()?;
return Ok((device_id, device_name));
}

anyhow::bail!("Stream ended")
}

From Shell Scripts

Check if service is running:

if busctl --user list | grep -q "org.fidobridge.Client"; then
echo "FIDO Bridge is running"
else
echo "FIDO Bridge is not running"
fi

Get service status:

busctl --user call org.fidobridge.Client \
/org/fidobridge/Client \
org.fidobridge.Client \
GetStatus | grep -oP 'paired_devices" "\K\d+'

List paired devices:

busctl --user call org.fidobridge.Client \
/org/fidobridge/Client \
org.fidobridge.Client \
ListPairedDevices --json=short | jq

Error Handling

All methods use zbus error types. Common errors:

Method Call Errors

Service Not Available:

Error: org.freedesktop.DBus.Error.ServiceUnknown

Solution: Start the service with systemctl --user start fido-bridge

Invalid Arguments:

Error: org.freedesktop.DBus.Error.InvalidArgs

Solution: Check method signature and argument types

Method Failed:

Error: org.freedesktop.zbus.Error.Failure

Solution: Check service logs with fido-bridge logs

Security Considerations

D-Bus Access Control

The service registers on the session bus, which means:

  • Only accessible to the current user session
  • Not accessible to other users on the system
  • Protected by D-Bus's built-in session isolation

No additional authentication is required beyond D-Bus session access.

Sensitive Data in Methods

  • Shared secrets: Never exposed via D-Bus API
  • PINs: Only transmitted during pairing, not stored or exposed after
  • Device credentials: Only device IDs and names are exposed, not encryption keys

Signal Privacy

Signals are broadcast to all listeners on the session bus. Applications should:

  • Not display PINs from PairingRequested signals if screen might be visible to others
  • Verify session IDs match expected values before acting on signals

Troubleshooting

"Service Not Found" Error

# Check if service is running
systemctl --user status fido-bridge

# Start if not running
systemctl --user start fido-bridge

# Verify D-Bus registration
busctl --user list | grep fidobridge

"Permission Denied" Error

D-Bus session permissions should allow access. If blocked:

# Check D-Bus policy
cat /etc/dbus-1/session.conf

Method Calls Hang

Check if service is responsive:

# Quick status check
fido-bridge status

# Check logs for errors
fido-bridge logs

See Also