A decentralized peer-to-peer chat application with local-first data storage, end-to-end encryption, and permission-based content sharing.
- Decentralized Identity: Ed25519 keypairs for signing, X25519 for key agreement
- Local-First: All data stored locally in SQLite, you own your data
- P2P Networking: Direct peer connections via libp2p (mDNS, Kademlia DHT, NAT traversal)
- End-to-End Encryption: AES-256-GCM with HKDF-derived conversation keys
- Permission System: Signed capability grants for content access (Chat, WallRead, Call)
- Event Sourcing: Append-only logs with lamport clocks for conflict-free sync
- Voice Calling: WebRTC signaling through libp2p (best-effort, works on LAN/most NATs)
- Node.js (v18+)
- Rust (stable)
- Tauri Prerequisites
- Windows: Microsoft Visual Studio C++ Build Tools
- macOS: Xcode Command Line Tools
- Linux:
sudo apt install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev
# Clone the repository
git clone https://github.com/Bakobiibizo/harbor.git
cd harbor
# Install frontend dependencies
npm install
# Run in development mode
npm run tauri dev# Build the application
npm run tauri build
# The executable will be in src-tauri/target/release/- When you first open Harbor, you'll be prompted to create an identity
- Enter a Display Name (how others will see you)
- Optionally add a Bio
- Create a Passphrase (at least 8 characters) - this encrypts your private keys
- Important: Store your passphrase safely! If you lose it, you cannot recover your identity
- On subsequent launches, enter your passphrase to unlock
- Your identity remains encrypted on disk when locked
- Go to the Network tab
- Click Start Network to connect to the P2P network
- Peers on your local network running Harbor will be discovered automatically via mDNS
- The status indicator shows your connection state
- In the Network tab, you'll see discovered peers
- Click the checkmark to add a peer as a contact
- You can search for peers by their Peer ID
- Use the Contacts tab to manage your contact list
- Go to the Messages tab
- Select a contact to open a conversation
- Messages are end-to-end encrypted using derived conversation keys
- Click the phone icon to initiate a voice call (if supported)
- Go to the My Wall tab
- Use the composer at the top to create a post
- You can add images and videos to your posts
- Posts are stored locally and shared with contacts who have permission
- Go to the Feed tab
- See posts from contacts who have granted you WallRead permission
- Like and comment on posts (when implemented)
Access settings to:
- Profile: Update your display name, bio, and avatar
- Security: Change passphrase, export/import identity
- Network: Configure auto-start and mDNS discovery
- Privacy: Control post visibility and read receipts
src/
├── components/
│ ├── common/ # Button, Input, etc.
│ ├── icons/ # SVG icon components
│ ├── layout/ # MainLayout with sidebar
│ └── onboarding/ # CreateIdentity, UnlockIdentity
├── pages/
│ ├── Chat.tsx # Direct messaging
│ ├── Wall.tsx # Your posts
│ ├── Feed.tsx # Posts from contacts
│ ├── Network.tsx # Peer discovery & contacts
│ └── Settings.tsx # App configuration
├── services/ # Tauri command wrappers
│ ├── identity.ts
│ ├── network.ts
│ ├── contacts.ts
│ ├── permissions.ts
│ ├── messaging.ts
│ ├── posts.ts
│ ├── feed.ts
│ └── calling.ts
├── stores/ # Zustand state management
│ ├── identity.ts
│ └── network.ts
├── types/ # TypeScript interfaces
└── styles/
└── design-system.css # CSS custom properties
src-tauri/src/
├── commands/ # Tauri command handlers
│ ├── identity.rs
│ ├── network.rs
│ ├── contacts.rs
│ ├── permissions.rs
│ ├── messaging.rs
│ ├── posts.rs
│ ├── feed.rs
│ └── calling.rs
├── services/ # Business logic
│ ├── identity_service.rs # Key management
│ ├── crypto_service.rs # Encryption/signing
│ ├── contacts_service.rs # Contact management
│ ├── permissions_service.rs # Capability grants
│ ├── messaging_service.rs # Direct messages
│ ├── posts_service.rs # Wall posts
│ ├── feed_service.rs # Feed aggregation
│ ├── content_sync_service.rs # P2P sync
│ └── calling_service.rs # Voice calls
├── db/
│ ├── mod.rs # Database initialization
│ ├── migrations/ # SQL migrations
│ └── repositories/ # Data access layer
├── models/ # Data structures
└── p2p/
├── network.rs # libp2p swarm
└── protocols/ # Request-response protocols
local_identity- Your encrypted keypairs and profilecontacts- Peer information and trust levelspermission_events- Grant/revoke events (event sourced)permissions_current- Materialized permission statemessage_events- Message lifecycle eventsmessages- Materialized messages for UIpost_events- Post lifecycle eventsposts- Materialized postspost_media- Media metadata (files stored on disk)call_history- Voice call recordssync_state- Per-peer sync progresssync_queue- Offline message queuelamport_clock- Logical clock for ordering
| Purpose | Algorithm | Notes |
|---|---|---|
| Identity signing | Ed25519 | All messages signed |
| Key agreement | X25519 | Derived from Ed25519 |
| Conversation encryption | AES-256-GCM | HKDF-derived keys |
| Key encryption | Argon2id + AES-GCM | Passphrase-based |
| Content hashing | SHA-256 | Media content-addressing |
Permissions are signed, portable capability grants:
struct PermissionGrant {
grant_id: Uuid,
issuer_peer_id: PeerId, // Who grants
subject_peer_id: PeerId, // Who receives
capability: Capability, // Chat, WallRead, Call
issued_at: u64,
expires_at: Option<u64>,
signature: Vec<u8>, // Ed25519 signature
}- MITM attacks (Noise protocol transport + E2E encryption)
- Message spoofing (all content signed with Ed25519)
- Replay attacks (nonce tracking, lamport clocks, message IDs)
- Unauthorized access (permission grants verified on every request)
- No forward secrecy (no double-ratchet yet - compromise exposes history)
- No HSM/secure enclave integration
- Connection patterns visible (metadata leakage)
- Voice calls may not work behind strict NATs (no TURN server)
IdentityRequest/IdentityResponse- Exchange peer info
PermissionRequest- Request capability from peerPermissionGrant- Grant capability to peerPermissionRevoke- Revoke previously granted capability
DirectMessage- Encrypted message with signatureMessageAck- Delivery/read receipt
ContentManifestRequest/Response- List available postsContentFetchRequest- Request specific postMediaChunkRequest/Response- Transfer media files
SignalingOffer/Answer- WebRTC SDP exchangeSignalingIce- ICE candidate exchangeSignalingHangup- End call
# Rust tests
cd src-tauri && cargo test
# TypeScript type check
npm run typecheckThe codebase follows these patterns:
- Event Sourcing: All state changes are events with lamport clocks
- CQRS: Events stored separately from materialized views
- Repository Pattern: Data access abstracted behind repositories
- Service Layer: Business logic in services, commands are thin wrappers
- Identity system with encrypted key storage
- P2P networking with libp2p
- Contact management
- Permission grants/revokes
- Direct messaging (encrypted)
- Wall/blog posts with media
- Feed aggregation
- Voice calling (signaling)
- Modern, polished UI
- Double-ratchet for forward secrecy
- Video calling + screen sharing
- Group chats
- Mobile app (iOS/Android via Tauri)
- TURN server for better NAT traversal
- Profile photo uploads
- Read receipts
- Typing indicators
Contributions are welcome! Please open an issue or PR.
MIT License - see LICENSE