DEV Community

VaultKeepR
VaultKeepR

Posted on

Cross-Device Sync Without Cloud: P2P Identity Management

Cover

The Cloud Dependency Problem

Your password manager syncs seamlessly across all your devices—until it doesn't. Last month, 1Password experienced a sync outage affecting millions of users. LastPass had their breach. And don't get started on the NSA's cloud surveillance programs. Yet 73% of developers still rely on cloud-based sync for their most sensitive data.

What if you could achieve the same seamless experience without ever touching a centralized server?

Why P2P Sync Matters in 2024

The traditional client-server model creates single points of failure. When Dropbox goes down, your encrypted vault becomes inaccessible. When Google Drive changes their API, your sync breaks. When governments demand backdoors, your privacy evaporates.

Meanwhile, the decentralized web is maturing. WebRTC enables direct browser-to-browser communication. Local network protocols like mDNS make device discovery trivial. Modern devices pack enough storage and processing power to handle cryptographic operations locally.

The convergence creates an opportunity: true peer-to-peer synchronization that's both secure and user-friendly.

Technical Deep Dive: P2P Sync Architecture

Device Discovery

Cross-device sync without cloud starts with finding your other devices. Modern implementations use a multi-layered approach:

class DeviceDiscovery {
  async discoverDevices(): Promise<Device[]> {
    const devices: Device[] = [];

    // Layer 1: Local network (mDNS/Bonjour)
    const localDevices = await this.discoverLocalDevices();
    devices.push(...localDevices);

    // Layer 2: Bluetooth Low Energy
    const bleDevices = await this.discoverBLEDevices();
    devices.push(...bleDevices);

    // Layer 3: WebRTC signaling (no data through server)
    const webrtcDevices = await this.discoverWebRTCPeers();
    devices.push(...webrtcDevices);

    return this.deduplicateDevices(devices);
  }

  private async discoverLocalDevices(): Promise<Device[]> {
    // Use mDNS to find devices advertising on local network
    const services = await this.mdns.browse('_vaultkeepr._tcp');
    return services.map(service => ({
      id: service.txt.deviceId,
      name: service.txt.deviceName,
      address: service.address,
      transport: 'local'
    }));
  }
}
Enter fullscreen mode Exit fullscreen mode

Cryptographic Identity

Each device maintains a cryptographic identity derived from the user's master seed:

class DeviceIdentity {
  constructor(private masterSeed: Uint8Array) {}

  async generateDeviceKeyPair(): Promise<CryptoKeyPair> {
    // Derive device-specific key from master seed
    const devicePath = "m/44'/0'/0'/0/device_index";
    const deviceSeed = await this.deriveKey(this.masterSeed, devicePath);

    return await crypto.subtle.generateKey(
      { name: 'ECDSA', namedCurve: 'P-256' },
      true,
      ['sign', 'verify']
    );
  }

  async authenticateDevice(remoteDevice: Device): Promise<boolean> {
    // Challenge-response authentication
    const challenge = crypto.getRandomValues(new Uint8Array(32));
    const signature = await remoteDevice.sign(challenge);

    return await this.verifySignature(
      signature, 
      challenge, 
      remoteDevice.publicKey
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Conflict-Free Replication

The hardest part isn't discovery or crypto—it's handling concurrent edits across devices. Conflict-Free Replicated Data Types (CRDTs) solve this elegantly:

interface VaultEntry {
  id: string;
  value: EncryptedData;
  vector_clock: VectorClock;
  tombstone?: boolean;
}

class VaultCRDT {
  private entries: Map<string, VaultEntry> = new Map();
  private deviceId: string;
  private clock: number = 0;

  addEntry(id: string, value: EncryptedData): void {
    this.clock++;
    const vectorClock = new Map([[this.deviceId, this.clock]]);

    this.entries.set(id, {
      id,
      value,
      vector_clock: vectorClock
    });
  }

  merge(remoteEntries: VaultEntry[]): ConflictResolution[] {
    const conflicts: ConflictResolution[] = [];

    for (const remoteEntry of remoteEntries) {
      const localEntry = this.entries.get(remoteEntry.id);

      if (!localEntry) {
        // New entry from remote
        this.entries.set(remoteEntry.id, remoteEntry);
      } else {
        // Resolve conflict using vector clocks
        const resolution = this.resolveConflict(localEntry, remoteEntry);
        conflicts.push(resolution);
      }
    }

    return conflicts;
  }
}
Enter fullscreen mode Exit fullscreen mode

How VaultKeepR Implements Cloudless Sync

VaultKeepR's approach combines the best of local networking with WebRTC fallbacks. When you add a password on your laptop, here's what happens:

  1. Local Discovery: Your phone detects the laptop on the same WiFi network using mDNS
  2. Authentication: Devices verify each other using ECDSA keys derived from your seed phrase
  3. Encrypted Transfer: The new password is encrypted with AES-256-GCM and sent directly device-to-device
  4. CRDT Merge: Your phone merges the update using vector clocks to handle any conflicts
  5. Persistence: Both devices update their local SQLite databases

No data ever hits a server. No API keys to manage. No subscription fees for sync.

The real innovation is the fallback system. When devices aren't on the same network, VaultKeepR uses WebRTC with a minimal signaling server that never sees your data—only connection metadata.

// VaultKeepR's sync implementation
class VaultKeeprSync {
  async sync(): Promise<SyncResult> {
    const availableDevices = await this.discovery.findTrustedDevices();

    for (const device of availableDevices) {
      try {
        const connection = await this.connectToDevice(device);
        const delta = await this.computeDelta(device.lastSyncHash);
        await this.exchangeEncryptedDelta(connection, delta);
      } catch (error) {
        console.warn(`Sync failed with ${device.name}:`, error);
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Implementing P2P Sync: Your Action Plan

Step 1: Choose Your Stack

For web apps, start with WebRTC for cross-network sync:

// Basic WebRTC data channel setup
const peerConnection = new RTCPeerConnection({
  iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
});

const dataChannel = peerConnection.createDataChannel('sync', {
  ordered: true,
  maxRetransmits: 3
});

dataChannel.onmessage = (event) => {
  const syncMessage = JSON.parse(event.data);
  this.processIncomingSyncData(syncMessage);
};
Enter fullscreen mode Exit fullscreen mode

For native apps, leverage Bluetooth LE or local WiFi:

// React Native Bluetooth discovery
import BluetoothSerial from 'react-native-bluetooth-serial-next';

const discoverNearbyDevices = async () => {
  const devices = await BluetoothSerial.discoverUnpairedDevices();
  return devices.filter(device => 
    device.name?.startsWith('VaultKeepR-')
  );
};
Enter fullscreen mode Exit fullscreen mode

Step 2: Design Your CRDT

Choose the right CRDT for your data structure:

  • Last-Write-Wins (LWW): Simple, works for most password managers
  • Multi-Value Register: Better for handling true conflicts
  • OR-Set: Perfect for tag-based systems

Step 3: Handle Network Partitions

Plan for the offline scenario:

class OfflineSync {
  private pendingChanges: Change[] = [];

  onNetworkReconnect() {
    if (this.pendingChanges.length > 0) {
      this.sync(this.pendingChanges);
      this.pendingChanges = [];
    }
  }

  addChange(change: Change) {
    this.pendingChanges.push(change);
    this.persistToLocal(change);
  }
}
Enter fullscreen mode Exit fullscreen mode

The Future of Decentralized Sync

P2P sync is entering mainstream adoption. Apple's AirDrop proves users love device-to-device transfers. Signal's recent P2P features show encrypted messaging is ready for decentralization.

The next wave brings:

  • Mesh networking: Devices form self-healing networks
  • Homomorphic encryption: Compute on encrypted data during sync
  • Quantum-resistant algorithms: Future-proof your crypto
  • IPFS integration: Content-addressed sync with built-in deduplication

Companies building proprietary sync infrastructure today will struggle to compete with open, decentralized alternatives that give users true data ownership.

Cross-device sync without cloud isn't just possible—it's inevitable. The question isn't whether you'll implement it, but whether you'll be early enough to benefit from the competitive advantage.

Start building your P2P sync today. Your users' privacy and your platform's resilience depend on it.

Top comments (0)