From e43af71392dbff39334dda4a2e1d7dcdd1c2c300 Mon Sep 17 00:00:00 2001 From: Kibi Kelburton Date: Mon, 23 Feb 2026 03:21:50 +0100 Subject: [PATCH] feat: Add password-based authentication for broadcasters and restrict WebRTC offers to authenticated users. --- public/app.js | 17 ++++++++++++++++- public/index.html | 3 +++ server.js | 12 +++++++++++- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/public/app.js b/public/app.js index 13baca4..f9f1e91 100644 --- a/public/app.js +++ b/public/app.js @@ -4,6 +4,8 @@ const startBtn = document.getElementById('startBtn'); const localVideo = document.getElementById('localVideo'); const statusDot = document.getElementById('statusDot'); const statusText = document.getElementById('statusText'); +const passwordInput = document.getElementById('broadcasterPassword'); +const authContainer = document.getElementById('authContainer'); let activeStream; @@ -18,6 +20,11 @@ const config = { ] }; +socket.on('authError', (msg) => { + alert(msg); + stopSharing(); +}); + socket.on('viewer', id => { if (!activeStream) return; @@ -97,6 +104,12 @@ socket.on('disconnectPeer', id => { }); startBtn.addEventListener('click', async () => { + const password = passwordInput.value; + if (!password) { + alert("Please enter the stream password to broadcast."); + return; + } + try { const stream = await navigator.mediaDevices.getDisplayMedia({ video: { @@ -112,10 +125,11 @@ startBtn.addEventListener('click', async () => { localVideo.classList.add('active'); startBtn.style.display = 'none'; + authContainer.style.display = 'none'; statusDot.classList.add('active'); statusText.innerText = 'Sharing Screen (1080p60)'; - socket.emit('broadcaster'); + socket.emit('broadcaster', password); stream.getVideoTracks()[0].onended = () => { stopSharing(); @@ -130,6 +144,7 @@ startBtn.addEventListener('click', async () => { function stopSharing() { startBtn.style.display = 'inline-block'; + authContainer.style.display = 'block'; localVideo.classList.remove('active'); statusDot.classList.remove('active'); statusText.innerText = 'Not Sharing'; diff --git a/public/index.html b/public/index.html index 86e2e3d..c273323 100644 --- a/public/index.html +++ b/public/index.html @@ -14,6 +14,9 @@

Share Your Screen

Broadcast your screen at 1080p 60fps to viewers.

+
+ +
diff --git a/server.js b/server.js index 1eca1ed..7d87abd 100644 --- a/server.js +++ b/server.js @@ -5,13 +5,22 @@ const server = http.createServer(app); const { Server } = require("socket.io"); const io = new Server(server); +// Password setting via environment variable, defaulting to "secret" +const BROADCASTER_PASSWORD = process.env.BROADCASTER_PASSWORD; +let broadcasterSocketId = null; + app.use(express.static("public")); io.on("connection", (socket) => { console.log("a user connected:", socket.id); // When the broadcaster starts sharing - socket.on("broadcaster", () => { + socket.on("broadcaster", (password) => { + if (password !== BROADCASTER_PASSWORD) { + socket.emit("authError", "Invalid broadcaster password."); + return; + } + broadcasterSocketId = socket.id; socket.broadcast.emit("broadcaster"); }); @@ -22,6 +31,7 @@ io.on("connection", (socket) => { // WebRTC Signaling socket.on("offer", (id, message) => { + if (socket.id !== broadcasterSocketId) return; // Prevent hijacking socket.to(id).emit("offer", socket.id, message); });