How the Experimental iOS Client Connects to the Desktop Core with TunnelTransport in OpenHuman
The experimental OpenHuman iOS client connects to the desktop core using TunnelTransport, which implements an XChaCha20‑Poly1305 encrypted tunnel over TCP to secure JSON‑RPC communication between the mobile client and the localhost core server.
The OpenHuman repository contains an experimental iOS client that requires secure communication with the desktop‑bundled core process. The project achieves this through a pluggable transport layer that supports multiple strategies, with TunnelTransport providing the cryptographic guarantees necessary for safe RPC transmission over local network interfaces.
Core Server Architecture
When the OpenHuman desktop application launches, it initializes the core process to expose a JSON‑RPC interface that the experimental iOS client can consume.
Process Initialization and Token Generation
The core launches in‑process via CoreProcessHandle defined in app/src-tauri/src/core_process.rs. This Rust module opens an HTTP RPC listener on a random localhost port and generates a unique bearer token stored as core_rpc_token. Frontend clients, including the iOS transport layer, retrieve this token through the Tauri command exposed in app/src-tauri/src/core_rpc_token.rs, ensuring that only authorized local clients can authenticate subsequent RPC requests.
ConnectionProfile Transport Selection
The transport abstraction lives in app/src/services/transport/index.ts, which exports the ConnectionProfile class. This profile acts as a factory that instantiates one of three transport implementations based on the deployment scenario:
LanHttpTransport– Plain HTTP over the local area network without encryption, suitable only for trusted networks.CloudHttpTransport– Connects to a remote cloud endpoint for internet‑based synchronization.TunnelTransport– The encrypted strategy used by the iOS client to protect data in transit.
TunnelTransport Implementation Details
The TunnelTransport class resides in app/src/services/transport/tunnel_transport.ts and provides the cryptographic layer that shields JSON‑RPC traffic from network observers.
Encryption Handshake and Key Derivation
When instantiated, the transport performs the following operations:
- TCP Socket Creation – Opens a raw TCP socket (or WebSocket wrapper) to
127.0.0.1on the port advertised by the desktop core. - Symmetric Key Generation – Generates a random 32‑byte key using a secure random number generator.
- Cipher Initialization – Constructs an
XChaCha20Poly1305instance from the@stablelib/xchacha20poly1305library, providing authenticated encryption with associated data (AEAD).
Request Encryption and Authentication
Every RPC request follows this encryption workflow:
- The plaintext JSON‑RPC body is sealed using
XChaCha20Poly1305.seal(), which generates a 24‑byte nonce prepended to the ciphertext. - The bearer token obtained from
core_rpc_tokenis included as anAuthorization: Bearer <token>header inside the encrypted envelope, ensuring that authentication credentials remain confidential. - The combined nonce and ciphertext payload transmits over the TCP socket to the core.
On receiving a response, the transport extracts the response nonce, decrypts the payload using XChaCha20Poly1305.open(), and returns the decrypted JSON to the caller.
iOS Client Integration
The experimental iOS codebase instantiates the secure transport in app/src/ios/transport.ts:
import { ConnectionProfile } from '../services/transport';
import { TunnelTransport } from '../services/transport/tunnel_transport';
export const iosCore = new ConnectionProfile({
transport: new TunnelTransport(),
});
// Example RPC invocation from iOS UI layer
export async function fetchUserInfo() {
const response = await iosCore.request({
method: 'GET',
path: '/auth/me',
headers: {},
});
return JSON.parse(new TextDecoder().decode(response.body));
}
The iosCore object exposes a request method that iOS UI layers call to execute domain‑specific OpenHuman RPC endpoints such as GET /rpc or POST /rpc, with all underlying encryption handled transparently by the TunnelTransport instance.
End‑to‑End Data Flow
The complete communication path between the experimental iOS client and the desktop core follows this sequence:
- iOS Client calls
ConnectionProfile.request()with an unencrypted JSON‑RPC payload. TunnelTransport.encrypt()generates a random 24‑byte nonce, seals the payload (including the Authorization header), and transmits the combined nonce+ciphertext over the TCP socket.- Desktop Core receives the raw bytes on the port managed by
CoreProcessHandle, decrypts the envelope using the shared cipher context, and forwards the plaintext to the RPC handler. - Core Response travels back through the same encrypted tunnel, where
TunnelTransport.decrypt()recovers the JSON payload before returning it to the iOS UI.
This flow ensures that the underlying TCP traffic remains opaque to any network interceptor, providing confidentiality and integrity for all RPC exchanges.
Implementation Code Examples
Client‑Side TunnelTransport Class
// app/src/services/transport/tunnel_transport.ts
import { XChaCha20Poly1305 } from '@stablelib/xchacha20poly1305';
import { randomBytes } from '@stablelib/random';
export class TunnelTransport {
private socket: WebSocket;
private cipher: XChaCha20Poly1305;
constructor(corePort: number) {
const key = randomBytes(32);
this.cipher = new XChaCha20Poly1305(key);
this.socket = new WebSocket(`ws://127.0.0.1:${corePort}`);
}
async request(payload: Uint8Array): Promise<Uint8Array> {
// Encrypt with unique nonce per request
const nonce = randomBytes(24);
const encrypted = this.cipher.seal(nonce, payload);
// Transmit nonce + ciphertext
this.socket.send(this.concat(nonce, encrypted));
// Await and decrypt response
const raw = await this.waitMessage();
const respNonce = raw.subarray(0, 24);
const respCipher = raw.subarray(24);
return this.cipher.open(respNonce, respCipher);
}
private concat(a: Uint8Array, b: Uint8Array): Uint8Array {
const result = new Uint8Array(a.length + b.length);
result.set(a);
result.set(b, a.length);
return result;
}
private waitMessage(): Promise<Uint8Array> {
return new Promise((resolve) => {
this.socket.onmessage = (event) => {
resolve(new Uint8Array(event.data));
};
});
}
}
Core‑Side RPC Handler
The Rust core does not require tunnel‑specific logic; it processes decrypted JSON‑RPC requests in src/openhuman/core/rpc.rs:
pub async fn handle_http_rpc(req: Request<Body>) -> Result<Response<Body>, RpcError> {
// Body arrives decrypted from the client side
let json_payload = parse_json_body(req).await?;
process_json_rpc(json_payload).await
}
Key Files and Components
app/src/services/transport/tunnel_transport.ts– Implements the XChaCha20‑Poly1305 encryption layer, manages the TCP/WebSocket tunnel, and exposes therequestmethod consumed by iOS.app/src/services/transport/index.ts– Defines theConnectionProfileabstraction that selects between LAN, Cloud, and Tunnel transport strategies.app/src/ios/transport.ts– Entry point for the experimental iOS client that instantiatesConnectionProfilewithTunnelTransport.app/src-tauri/src/core_process.rs– Launches the embedded core process, binds the RPC listener to a random localhost port, and generates the bearer token.app/src-tauri/src/core_rpc_token.rs– Exposes thecore_rpc_tokento authorized frontend clients via Tauri commands.src/openhuman/core/rpc.rs– Rust RPC handler that processes decrypted JSON‑RPC requests as standard HTTP traffic.
Summary
- The experimental iOS client uses
TunnelTransportto establish an encrypted communication channel with the OpenHuman desktop core. - XChaCha20‑Poly1305 provides authenticated encryption for all RPC payloads, with unique nonces generated per request.
- The bearer token authenticating the client travels inside the encrypted envelope, protecting credentials from network eavesdropping.
- The architecture maps encrypted TCP traffic to the standard JSON‑RPC interface exposed by
CoreProcessHandle, requiring no changes to the core's request handling logic.
Frequently Asked Questions
What encryption standard does TunnelTransport use?
TunnelTransport uses XChaCha20‑Poly1305, an authenticated encryption with associated data (AEAD) cipher. The implementation leverages the @stablelib/xchacha20poly1305 library to generate 24‑byte nonces and 32‑byte symmetric keys for each tunnel session, ensuring both confidentiality and integrity of JSON‑RPC traffic.
How does the iOS client authenticate with the desktop core?
The iOS client retrieves a bearer token via the Tauri command core_rpc_token exposed in app/src-tauri/src/core_rpc_token.rs. This token is embedded as an Authorization: Bearer <token> header inside the encrypted payload before transmission. Because the encryption occurs before the data leaves the client, the authentication credentials remain protected from any intermediary network observer.
Can TunnelTransport connect over Wi‑Fi or is it restricted to localhost?
While the current implementation targets localhost TCP connections (typically 127.0.0.1 on the random port assigned by CoreProcessHandle), the transport layer itself is protocol‑agnostic. The encrypted tunnel could theoretically traverse any TCP‑capable network path, though the experimental iOS client in the OpenHuman repository is designed specifically for local device‑to‑desktop pairing over shared network interfaces or USB forwarding.
Why use TunnelTransport instead of standard HTTPS?
TunnelTransport specifically solves the local trust boundary problem for an experimental iOS client that cannot easily validate self‑signed certificates or trust store configurations required for local HTTPS. By using a pre‑shared symmetric key derived via the core_rpc_token handshake and XChaCha20‑Poly1305 encryption, the system achieves zero‑configuration encrypted communication without the certificate management overhead of TLS, making it ideal for rapid prototyping in the OpenHuman development environment.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →