Skip to content

keshorerode/universal_clipboard

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 

Repository files navigation

LinkSync — Universal Clipboard

A cross-platform clipboard synchronization application that lets you seamlessly share text and images between your Android phone and Windows PC in real time — securely, privately, and without any cloud service.


Table of Contents


What This Project Does

LinkSync keeps your clipboard in sync between your Android phone and Windows PC over your local network. When you copy something on your phone, it instantly appears on your PC, and vice versa — with no cloud, no third-party server, and full end-to-end encryption.

Key Features:

  • Real-time bidirectional clipboard sync (text and images)
  • Secure QR-code-based device pairing
  • Works over WiFi (TCP/mDNS) with Bluetooth Low Energy (BLE) as fallback
  • End-to-end encrypted with XChaCha20-Poly1305
  • Background sync on Android (survives doze mode via VPN service)
  • System tray app on Windows
  • Auto-start on boot (both platforms)
  • Fully local — no internet required

Architecture Overview

┌─────────────────────────────────────────────────────────────┐
│                        LinkSync                             │
│                                                             │
│   Android (Kotlin)              Windows (Tauri/Rust/React)  │
│   ┌─────────────────┐           ┌─────────────────────┐    │
│   │ ClipboardWatcher│◄─────────►│  ClipboardManager   │    │
│   │ VpnService      │           │  TCP Listener :12716 │    │
│   │ TcpClient       │◄─WiFi────►│  mDNS Broadcaster   │    │
│   │ BleClient       │◄─BLE─────►│  BLE Scanner        │    │
│   │ mDNS Discovery  │           │  System Tray UI      │    │
│   │ IdentityManager │           │  IdentityManager     │    │
│   │ SecureSession   │◄─E2E─────►│  SecureSession       │    │
│   └─────────────────┘           └─────────────────────┘    │
│                                                             │
│   Transport: TCP (primary) / BLE GATT (fallback)           │
│   Discovery: mDNS (_linksync._tcp.local) / BLE Advertising  │
│   Encryption: XChaCha20-Poly1305 AEAD                      │
│   Key Exchange: X25519 Diffie-Hellman                       │
│   Identity: Ed25519 signing keypairs                        │
└─────────────────────────────────────────────────────────────┘

Protocols Used

1. JSON-RPC 2.0 (Application Protocol)

All messages between Android and Windows use JSON-RPC 2.0 format, carried over encrypted TCP connections.

Message Format:

// Request
{
  "jsonrpc": "2.0",
  "method": "linksync.clipboard.update",
  "params": { ... },
  "id": "uuid-string"
}

// Response
{
  "jsonrpc": "2.0",
  "result": { ... },
  "error": null,
  "id": "uuid-string"
}

Methods:

Method Direction Purpose
linksync.ping Both Initial handshake / device discovery
linksync.pair_init Android → PC Send Ed25519 + X25519 public keys with pairing token
linksync.clipboard.update Both Send clipboard content (text/image, MIME type, SHA-256 hash)
linksync.heartbeat Both Keep-alive ping to detect disconnection

2. TCP/IP (Primary Transport)

  • Port: 12716 (default, configurable)
  • Frame format: 4-byte big-endian length prefix followed by the encrypted payload
  • All data is encrypted before sending using XChaCha20-Poly1305
  • Supports multiple simultaneous connections (async via Tokio on Windows, Coroutines on Android)
┌──────────────────────────────────────────────────────────┐
│  [4 bytes: payload length (big-endian)] [encrypted data] │
└──────────────────────────────────────────────────────────┘

3. mDNS — Multicast DNS (Service Discovery)

  • Service type: _linksync._tcp.local
  • Windows PC broadcasts itself on the local network using mDNS
  • Android discovers the PC automatically — no manual IP entry needed
  • Uses the mdns-sd Rust crate on Windows and Android's NsdManager API
  • Refreshes on network changes (network watcher detects WiFi switches)

4. Bluetooth Low Energy — BLE (Fallback Transport & Discovery)

  • Used when WiFi is unavailable or as an initial discovery mechanism
  • Android: Advertises via BLE GATT; scans for Windows devices
  • Windows: Uses btleplug crate + Windows BLE APIs (windows::Devices::Bluetooth)
  • BLE GATT characteristics carry device identity info for pairing bootstrap
  • Data transport falls back to BLE when TCP is not available (SyncManager priority queue)

5. X25519 Diffie-Hellman (Key Exchange)

  • Each device generates a permanent X25519 keypair on first launch
  • During pairing, both sides exchange X25519 public keys
  • A shared secret is derived via DH: shared = X25519(my_private, their_public)
  • This shared secret is used as the symmetric key for XChaCha20-Poly1305 encryption
  • Never transmitted in plaintext — only public keys are exchanged

6. Ed25519 (Device Identity & Signing)

  • Each device has a permanent Ed25519 keypair stored in encrypted storage
  • Public key is embedded in the QR code pairing payload
  • Used to verify device identity and authenticate pairing requests
  • On Android: stored in EncryptedSharedPreferences (AES256-GCM)
  • On Windows: stored in local identity file (DPAPI encryption planned)

7. XChaCha20-Poly1305 AEAD (Data Encryption)

All clipboard data is encrypted end-to-end using XChaCha20-Poly1305.

Wire format:

┌──────────────────────────────────────────────────────────────┐
│  [24 bytes: random nonce] [ciphertext] [16 bytes: auth tag]  │
└──────────────────────────────────────────────────────────────┘
  • 24-byte random nonce generated fresh for every message
  • 16-byte Poly1305 authentication tag appended automatically
  • Implementations are cross-compatible:
    • Android: lazysodium-android (libsodium wrapper)
    • Windows: chacha20poly1305 Rust crate

8. QR Code (Out-of-Band Pairing Bootstrap)

  • Windows generates a QR code containing a JSON pairing payload
  • Scanned by Android using CameraX + ML Kit Barcode Scanning
  • QR payload contains:
{
  "device_id": "uuid",
  "device_name": "DESKTOP-XYZ",
  "public_key": "hex-encoded-ed25519-public-key",
  "x_public_key": "hex-encoded-x25519-public-key",
  "pairing_token": "time-limited-secret-token",
  "expires_at": 1700000000,
  "ip": "192.168.1.100",
  "port": 12716,
  "bluetooth_mac": "AA:BB:CC:DD:EE:FF"
}
  • Pairing tokens are time-limited and single-use

9. VPN Loopback Tunnel (Android Background Persistence)

  • Android creates a local VPN tunnel (ClipSyncVpnService) that routes no real traffic
  • Purpose: keeps the app alive indefinitely without being killed by Android's battery optimizer (Doze mode)
  • The tunnel is a fake local interface — all data stays on the device

Security & Cryptography

Layer Algorithm Library
Key Exchange X25519 Diffie-Hellman lazysodium (Android), x25519-dalek (Rust)
Signing / Identity Ed25519 lazysodium (Android), ed25519-dalek (Rust)
Symmetric Encryption XChaCha20-Poly1305 AEAD lazysodium (Android), chacha20poly1305 (Rust)
Key Storage (Android) AES256-GCM androidx.security.crypto EncryptedSharedPreferences
Clipboard Deduplication SHA-256 Hash Standard library

Android App — Logic & Language

Language & SDK

  • Language: Kotlin
  • Min SDK: 26 (Android 8.0), Target SDK: 34, Compile SDK: 35
  • Java Version: 17
  • UI: Jetpack Compose + Material3
  • Build: Gradle with KSP (Kotlin Symbol Processing)

Key Components

Component File Role
IdentityManager core/security/IdentityManager.kt Generates/stores Ed25519 + X25519 keypairs, device UUID
SecureSession core/security/SecureSession.kt XChaCha20-Poly1305 encrypt/decrypt
SyncManager core/sync/SyncManager.kt Clipboard queue with TCP-first, BLE-fallback retry logic
TcpClient network/TcpClient.kt JSON-RPC 2.0 over encrypted TCP, length-prefixed frames
BluetoothClient network/BluetoothClient.kt BLE GATT communication
Protocol network/Protocol.kt Data classes for all JSON-RPC payloads
ClipSyncVpnService features/vpn/ClipSyncVpnService.kt Fake VPN tunnel for background persistence
ClipboardWatcher features/vpn/ClipboardWatcher.kt Monitors clipboard changes
BleAdvertiserService features/connectivity/discovery/ Advertises phone over BLE
MdnsDiscoveryService features/connectivity/discovery/ Finds Windows PC via mDNS
BootReceiver receivers/BootReceiver.kt Auto-start on device reboot

Android Dependencies

// Cryptography
"com.goterl:lazysodium-android"       // libsodium: Ed25519, X25519, XChaCha20-Poly1305

// Database
"androidx.room:room-runtime"           // Local SQLite ORM
"androidx.room:room-ktx"

// Security
"androidx.security:security-crypto"   // EncryptedSharedPreferences (AES256)

// UI
"androidx.compose.ui:ui"              // Jetpack Compose
"androidx.compose.material3:material3"
"androidx.activity:activity-compose"
"androidx.lifecycle:lifecycle-viewmodel-compose"

// Camera / QR
"androidx.camera:camera-camera2"      // CameraX
"com.google.mlkit:barcode-scanning"   // QR code scanning

// Async
"org.jetbrains.kotlinx:kotlinx-coroutines-android"
"org.jetbrains.kotlinx:kotlinx-serialization-json"

Windows App — Logic & Language

Language & Stack

  • Backend: Rust 2021 edition (via Tauri 2.0)
  • Frontend: React 19.1 + TypeScript 5.8
  • Styling: Tailwind CSS 4.2
  • Animations: Framer Motion
  • Build: Vite 7.0
  • Runtime: Tokio async runtime

Key Components

Component File Role
IdentityManager src-tauri/src/auth.rs Keypair generation, QR payload creation
SecureSession src-tauri/src/crypto.rs XChaCha20-Poly1305 AEAD
ClipboardManager src-tauri/src/clipboard.rs Monitor + inject clipboard, history
TCP Listener src-tauri/src/network.rs Async TCP server, session management, JSON-RPC
BLE Client src-tauri/src/network_bt.rs Bluetooth LE via btleplug
DiscoveryManager src-tauri/src/discovery/mod.rs Coordinates mDNS + BLE discovery
mDNS Broadcaster src-tauri/src/discovery/mdns.rs Advertises PC on local network
Network Watcher src-tauri/src/discovery/network_watcher.rs Detects WiFi changes
DbManager src-tauri/src/db.rs SQLite: trusted devices, clipboard history
Dashboard src/App.tsx Device status, connection info
Pairing Screen src/SetupScreen.tsx QR code display, pairing flow
Settings src/SettingsScreen.tsx Manage trusted devices

Rust Dependencies

tauri = "2"                    # Desktop app framework + system tray
tokio = { version = "1", features = ["full"] }  # Async runtime
serde = "1"                    # Serialization
serde_json = "1"               # JSON handling
mdns-sd = "0.13"               # mDNS service discovery
x25519-dalek = "2.0"           # X25519 key exchange
ed25519-dalek = "2.1"          # Ed25519 signing
chacha20poly1305 = "0.10"      # XChaCha20-Poly1305 AEAD
sqlx = { version = "0.8", features = ["sqlite"] }  # Async SQLite
btleplug = "0.11.8"            # Bluetooth LE
windows = "0.58"               # Windows-specific Bluetooth APIs
uuid = "1"                     # UUID generation
rand = "0.8"                   # Cryptographic randomness
tauri-plugin-notification = "2"
tauri-plugin-autostart = "2"

Step-by-Step: Build the Android APK

Prerequisites

Tool Version Download
Android Studio Hedgehog or later https://developer.android.com/studio
JDK 17 Bundled with Android Studio
Android SDK API 34 Via Android Studio SDK Manager
Android NDK Latest stable Via Android Studio SDK Manager (needed for lazysodium)

Step 1 — Clone the Repository

git clone https://github.com/keshorerode/universal_clipboard.git
cd universal_clipboard/universal_clipboard_working/linksync-android

Step 2 — Open in Android Studio

  1. Launch Android Studio
  2. Click Open (not "New Project")
  3. Navigate to universal_clipboard_working/linksync-android
  4. Click OK and wait for Gradle sync to complete

Step 3 — Install SDK & NDK

In Android Studio:

  1. Go to Tools → SDK Manager
  2. Under SDK Platforms: check Android 14 (API 34)
  3. Under SDK Tools: check NDK (Side by side) and CMake
  4. Click Apply and let it download

Step 4 — Configure local.properties

In the linksync-android folder, open or create local.properties:

sdk.dir=C\:\\Users\\YourName\\AppData\\Local\\Android\\Sdk

Android Studio usually creates this automatically. Check the path matches your actual SDK location.


Step 5 — Sync & Build

Option A — Android Studio (GUI):

  1. Wait for the Gradle sync to finish (bottom status bar)
  2. Go to Build → Make Project (or press Ctrl+F9)
  3. Once built, go to Build → Build Bundle(s)/APK(s) → Build APK(s)
  4. APK will be at:
    app/build/outputs/apk/debug/app-debug.apk
    

Option B — Command Line:

# On Windows (PowerShell)
cd universal_clipboard_working/linksync-android

# Build debug APK
.\gradlew assembleDebug

# APK output location:
# app\build\outputs\apk\debug\app-debug.apk
# Build release APK (requires signing config)
.\gradlew assembleRelease

Step 6 — Install on Phone

Via USB (Recommended):

  1. Enable Developer Options on your phone: Settings → About Phone → tap Build Number 7 times
  2. Enable USB Debugging in Developer Options
  3. Connect phone via USB
  4. In Android Studio click Run ▶ or run:
adb install app\build\outputs\apk\debug\app-debug.apk

Via File Transfer:

  1. Copy the APK to your phone
  2. On the phone: Settings → Install unknown apps → allow your file manager
  3. Tap the APK to install

Step 7 — Grant Permissions on First Launch

When the app opens, grant all requested permissions:

  • Location (required for BLE scanning on Android)
  • Bluetooth (scan, connect, advertise)
  • Camera (QR code scanning)
  • Notifications
  • Accessibility Service (for clipboard detection): Settings → Accessibility → LinkSync
  • VPN (for background persistence): accept the VPN dialog

Step-by-Step: Run the Tauri Windows App

Prerequisites

Tool Version Install
Rust Latest stable https://rustup.rs
Node.js 18 or later https://nodejs.org
npm Bundled with Node.js
Visual Studio Build Tools 2022 https://visualstudio.microsoft.com/visual-cpp-build-tools/
WebView2 Runtime Latest Pre-installed on Windows 11; download for Windows 10

Step 1 — Install Rust

# Download and run rustup installer from https://rustup.rs
# Then verify:
rustc --version
cargo --version

Step 2 — Install Visual Studio Build Tools

  1. Download Visual Studio Build Tools 2022
  2. In the installer, select: Desktop development with C++
  3. This installs the MSVC compiler required by Tauri

Step 3 — Install the Tauri CLI

cargo install tauri-cli --version "^2.0"

# Verify
cargo tauri --version

Step 4 — Clone & Navigate to Windows App

git clone https://github.com/keshorerode/universal_clipboard.git
cd universal_clipboard/universal_clipboard_working/linksync-windows

Step 5 — Install Node Dependencies

npm install

This installs React, Vite, Tailwind CSS, Framer Motion, qrcode.react, and all other frontend dependencies.


Step 6 — Run in Development Mode

cargo tauri dev

This command:

  1. Starts the Vite dev server at http://localhost:1420 (React frontend)
  2. Compiles the Rust backend (src-tauri/)
  3. Opens the Tauri window with hot-reload enabled

First run will take several minutes as Cargo downloads and compiles all Rust crates.


Step 7 — Build for Production (Optional)

cargo tauri build

Output installer will be at:

src-tauri/target/release/bundle/
  ├── msi/linksync-windows_0.1.0_x64_en-US.msi   ← Windows Installer
  └── nsis/linksync-windows_0.1.0_x64-setup.exe   ← NSIS Installer

Step 8 — What Runs on Startup

When the Windows app launches:

  1. IdentityManager loads or creates Ed25519 + X25519 keypairs from local storage
  2. TCP Listener starts on port 12716 and listens for Android connections
  3. mDNS Broadcaster advertises _linksync._tcp.local on the local network
  4. Clipboard Monitor begins watching for clipboard changes
  5. System Tray icon appears — right-click to show/hide window or quit

Common Issues

Problem Fix
cargo: command not found Install Rust from https://rustup.rs and restart terminal
Rust compile error: MSVC not found Install Visual Studio Build Tools with C++ workload
WebView2 error on startup Download WebView2 Runtime from Microsoft
Port 12716 already in use Check for other instances of the app running
Android not discovering PC Ensure both devices are on the same WiFi network
BLE not working on Windows Enable Bluetooth in Windows Settings

Pairing Flow

Android                                        Windows PC
   │                                               │
   │  1. Open app → tap "Pair New Device"          │
   │                                               │
   │                   2. PC shows QR code ────────│
   │                      (contains IP, port,      │
   │                       Ed25519 PK, X25519 PK,  │
   │                       pairing token)          │
   │                                               │
   │  3. Scan QR code ─────────────────────────────│
   │                                               │
   │  4. Send pair_init ──────────────────────────►│
   │     (Ed25519 PK, X25519 PK, token)            │
   │                                               │
   │                   5. PC verifies token ───────│
   │                      saves trusted device     │
   │                                               │
   │◄───────────────── 6. Respond with PC keys ────│
   │                                               │
   │  7. Both derive shared secret via X25519 DH   │
   │                                               │
   │◄══════════════ Encrypted sync starts ════════►│

Project Structure

universal_clipboard_working/
├── linksync-android/                  ← Android (Kotlin)
│   └── app/src/main/java/com/kesho/linksync/
│       ├── core/
│       │   ├── db/                    ← Room database (devices, history)
│       │   ├── model/                 ← Data models
│       │   ├── security/              ← Crypto (identity, sessions)
│       │   └── sync/                  ← SyncManager (queue + retry)
│       ├── features/
│       │   ├── connectivity/          ← BLE + mDNS discovery, QR scanner
│       │   └── vpn/                   ← VPN persistence, clipboard watcher
│       ├── network/                   ← TCP + BLE clients, protocol types
│       ├── services/                  ← Foreground service, accessibility
│       └── receivers/                 ← Boot receiver
│
└── linksync-windows/                  ← Windows (Tauri + Rust + React)
    ├── src/                           ← React frontend
    │   ├── App.tsx                    ← Dashboard
    │   ├── SetupScreen.tsx            ← QR pairing
    │   └── SettingsScreen.tsx         ← Settings
    └── src-tauri/src/                 ← Rust backend
        ├── main.rs                    ← Entry point
        ├── lib.rs                     ← Module wiring, Tauri commands
        ├── auth.rs                    ← Identity + QR payload
        ├── clipboard.rs               ← Clipboard monitor + inject
        ├── crypto.rs                  ← XChaCha20-Poly1305
        ├── db.rs                      ← SQLite (trusted devices)
        ├── network.rs                 ← TCP server + JSON-RPC
        ├── network_bt.rs              ← BLE client
        └── discovery/                 ← mDNS broadcaster + BLE scanner

License

MIT

About

LinkSync is a high-performance, local-first Universal Clipboard that seamlessly bridges the gap between your Windows PC and Android device. Think of it as Apple's Universal Clipboard, but custom-built for the Windows/Android ecosystem with zero dependence on the cloud.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages