Here’s a secure Node.js-based relay server that does the following:
- Allows desktop servers (behind NAT) to register.
- Allows mobile clients to connect via WebSocket using a QR code-based pairing system.
- Forwards messages securely only between matched client-server pairs.
- Supports LAN fallback (users can skip relay and connect directly in trusted networks).
🔐 Pairing Strategy (QR-based)
- When the desktop app (server) starts, it generates a unique pairing code (UUID or short code).
- It opens a WebSocket to the relay and registers itself with that code.
- The mobile app (client) scans a QR code from the desktop and uses the same code to connect to the relay.
- The relay pairs the two sockets and relays messages securely between them.
🧠 Tech Stack
Node.js
ws for WebSocket
uuid for secure unique IDs
📦 Dependencies
🌐 relay-server.js
const WebSocket = require('ws');
const { v4: uuidv4 } = require('uuid');
const wss = new WebSocket.Server({ port: 8080 });
console.log("Relay server listening on port 8080");
const servers = new Map(); // pairingCode -> ws
const clients = new Map(); // clientWs -> serverWs
wss.on('connection', (ws) => {
ws.isAlive = true;
ws.on('pong', () => ws.isAlive = true);
ws.on('message', (msg) => {
try {
const data = JSON.parse(msg);
if (data.type === 'register-server') {
// Register a server with a unique pairing code
const code = data.code || uuidv4(); // can be random short string
ws.role = 'server';
ws.pairingCode = code;
servers.set(code, ws);
ws.send(JSON.stringify({ type: 'registered', code }));
console.log(`Server registered with code: ${code}`);
} else if (data.type === 'connect-client') {
const serverWs = servers.get(data.code);
if (!serverWs) {
ws.send(JSON.stringify({ type: 'error', message: 'Invalid code' }));
return;
}
ws.role = 'client';
ws.serverWs = serverWs;
serverWs.clientWs = ws;
clients.set(ws, serverWs);
clients.set(serverWs, ws);
ws.send(JSON.stringify({ type: 'connected' }));
serverWs.send(JSON.stringify({ type: 'client-connected' }));
console.log(`Client connected to server with code: ${data.code}`);
} else if (data.type === 'message') {
// Relay message to paired client/server
const target = clients.get(ws);
if (target) {
target.send(JSON.stringify({ type: 'message', payload: data.payload }));
}
}
} catch (err) {
console.error("Error parsing message", err);
}
});
ws.on('close', () => {
if (ws.role === 'server') {
servers.delete(ws.pairingCode);
if (ws.clientWs) {
ws.clientWs.close();
clients.delete(ws.clientWs);
}
} else if (ws.role === 'client' && ws.serverWs) {
ws.serverWs.send(JSON.stringify({ type: 'client-disconnected' }));
ws.serverWs.clientWs = null;
clients.delete(ws.serverWs);
}
clients.delete(ws);
});
});
// Optional: ping-pong to clean up dead sockets
setInterval(() => {
wss.clients.forEach(ws => {
if (!ws.isAlive) return ws.terminate();
ws.isAlive = false;
ws.ping();
});
}, 10000);
🖥️ Desktop App (server) Example
const ws = new WebSocket('wss://yourrelayserver.com');
ws.onopen = () => {
const code = 'ABCD1234'; // generate or reuse
ws.send(JSON.stringify({ type: 'register-server', code }));
};
ws.onmessage = (msg) => {
const data = JSON.parse(msg.data);
if (data.type === 'client-connected') {
console.log('Client connected!');
} else if (data.type === 'message') {
console.log('Received from client:', data.payload);
}
};
// To send message:
function sendToClient(payload) {
ws.send(JSON.stringify({ type: 'message', payload }));
}
📱 Mobile App (client) Example
const ws = new WebSocket('wss://yourrelayserver.com');
ws.onopen = () => {
const code = scannedFromQRCode; // user scans QR
ws.send(JSON.stringify({ type: 'connect-client', code }));
};
ws.onmessage = (msg) => {
const data = JSON.parse(msg.data);
if (data.type === 'message') {
console.log('Received from server:', data.payload);
}
};
// To send message:
function sendToServer(payload) {
ws.send(JSON.stringify({ type: 'message', payload }));
}
🧾 Security Recommendations
- Use TLS (wss://) — Cloud relay must use HTTPS/WSS only.
- Expire pairing codes — Limit to 10 minutes or until first connection.
- Add JWT or shared secret — For more secure client-server handshakes.
- Rate limit and firewall — Protect against abuse and DDoS.
Would you like:
- A QR code generator snippet for the desktop app?
- A React Native or Ionic QR scanner example for the mobile app?
- A production-ready Docker setup for the relay?
Let me know how far you want to take it and I’ll build it out for you.
https://chatgpt.com/c/67e13278-29f0-8012-a5ae-515186fcc004
Here’s a secure Node.js-based relay server that does the following:
🔐 Pairing Strategy (QR-based)
🧠 Tech Stack
Node.jswsfor WebSocketuuidfor secure unique IDs📦 Dependencies
🌐
relay-server.js🖥️ Desktop App (server) Example
📱 Mobile App (client) Example
🧾 Security Recommendations
Would you like:
Let me know how far you want to take it and I’ll build it out for you.
https://chatgpt.com/c/67e13278-29f0-8012-a5ae-515186fcc004