@termpod/protocol
WebSocket protocol definitions, binary frame encoding, E2E encryption, and compression.
The packages/protocol/ package contains all WebSocket protocol definitions, binary frame encoding/decoding, and E2E encryption for the desktop app.
Files
packages/protocol/src/
├── index.ts # Main exports
├── constants.ts # Channel IDs, frame sizes, limits
├── messages.ts # Control message TypeScript interfaces
├── binary.ts # Binary frame encoding/decoding
├── crypto.ts # ECDH P-256 + AES-256-GCM (Web Crypto API)
├── share-crypto.ts # Share token encryption (symmetric AES-256-GCM)
├── compression.ts # Deflate compression for large frames
└── *.test.ts # TestsMessage Types
All control messages are defined as TypeScript interfaces in messages.ts:
HelloMessage,HelloOkMessageAuthMessage,AuthOkMessageKeyExchangeMessage,KeyExchangeAckMessageSessionInfoMessage,ReadyMessageClientJoinedMessage,ClientLeftMessageListSessionsMessage,SessionsListMessageCreateSessionRequestMessage,SessionCreatedMessageWebRTCOfferMessage,WebRTCAnswerMessage,WebRTCIceMessageErrorMessage,PingMessage,PongMessage
Binary Encoding
binary.ts provides functions for encoding and decoding binary frames:
Channel Constants
const CHANNEL_DATA = 0x00; // Terminal data (deprecated on relay)
const CHANNEL_RESIZE = 0x01; // Terminal resize
const CHANNEL_SCROLLBACK = 0x02; // Scrollback chunk
const CHANNEL_ENCRYPTED = 0xe0; // E2E encrypted
const CHANNEL_SHARE = 0xe1; // Share encryptedMultiplexed Frame Encoding
// Encode
function encodeMuxFrame(channel: number, sessionId: string, payload: Uint8Array): Uint8Array
// Decode
function decodeMuxFrame(data: Uint8Array): { channel: number; sessionId: string; payload: Uint8Array }Crypto
crypto.ts implements E2E encryption using the Web Crypto API:
// Generate ECDH P-256 key pair
async function generateKeyPair(): Promise<CryptoKeyPair>
// Export public key to JWK
async function exportPublicKey(key: CryptoKey): Promise<JsonWebKey>
// Import peer's public key from JWK
async function importPublicKey(jwk: JsonWebKey): Promise<CryptoKey>
// Derive session key via ECDH + HKDF-SHA256
async function deriveSessionKey(
privateKey: CryptoKey,
peerPublicKey: CryptoKey,
sessionId: string
): Promise<E2ESession>
// Encrypt a frame
async function encryptFrame(session: E2ESession, data: Uint8Array): Promise<Uint8Array>
// Decrypt a frame
async function decryptFrame(session: E2ESession, data: Uint8Array): Promise<Uint8Array>Share Crypto
share-crypto.ts implements symmetric encryption for session sharing:
// Generate random AES-256-GCM key
async function generateShareKey(): Promise<CryptoKey>
// Export key to base64 (for URL fragment)
async function exportShareKey(key: CryptoKey): Promise<string>
// Import key from base64
async function importShareKey(keyBase64: string): Promise<CryptoKey>
// Encrypt/decrypt share frames
async function encryptShareFrame(key: CryptoKey, data: Uint8Array): Promise<Uint8Array>
async function decryptShareFrame(key: CryptoKey, data: Uint8Array): Promise<Uint8Array>Compression
compression.ts provides raw deflate compression for multiplexed frames:
- Used when payload is >= 256 bytes
- Compressed mux frames use channel
0x12 - Automatic decompression on receive