From 67af7df83ce9f9204e822e8f072381d7dbdd454f Mon Sep 17 00:00:00 2001 From: =bhagwanSingh Date: Mon, 15 Dec 2025 16:26:26 +0530 Subject: [PATCH] Added VPN Disconnect --- src/routes/v1/index.js | 34 +++++++++++++++++++++++---- src/vpnHandler/vpn.js | 53 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 5 deletions(-) diff --git a/src/routes/v1/index.js b/src/routes/v1/index.js index 59d34d0..89c7e90 100644 --- a/src/routes/v1/index.js +++ b/src/routes/v1/index.js @@ -13,14 +13,14 @@ import { project_add_sf } from "../../controllers/project/projectAddSf.controlle import { update_project_sf } from "../../controllers/project/projectUpdateSf.controller.js" import { authValidator } from "../../middlewares/auth.middleware.js"; import { delete_project_sf } from "../../controllers/project/deleteProjectSf.controller.js" -import { createWireGuardConnection } from '../../vpnHandler/vpn.js'; +import { createWireGuardConnection, disconnectWireGuardConnection } from '../../vpnHandler/vpn.js'; const v1Routes = express.Router() const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); -v1Routes.get("/auth", function(req, res) { +v1Routes.get("/auth", function (req, res) { res.sendFile(path.join(__dirname, '/auth.html')); }); @@ -35,9 +35,9 @@ v1Routes.delete("/project/:projectId", authValidator, delete_project_sf); v1Routes.post("/password/reset", process_reset); -v1Routes.get("/", function(req, res) { - res.json({"connected": true}) -}) +v1Routes.get("/", function (req, res) { + res.json({ "connected": true }) +}) v1Routes.post("/vpn/connect", (req, res) => { try { @@ -55,6 +55,30 @@ v1Routes.post("/vpn/connect", (req, res) => { } }); +v1Routes.post("/vpn/disconnect", (req, res) => { + try { + const { ip } = req.body; + if (!ip) { + return res.status(400).json({ + success: false, + error: "IP address is required" + }); + } + + const result = disconnectWireGuardConnection(ip); + if (result && result.success) { + return res.status(200).json(result); + } + + return res.status(400).json({success: false, error: result.message}); + } catch (err) { + res.status(500).json({ + success: false, + error: err.message + }); + } +}); + // v1Routes.use("/form_submit", authValidator, formRoutes); export default v1Routes; \ No newline at end of file diff --git a/src/vpnHandler/vpn.js b/src/vpnHandler/vpn.js index 3c8efc3..6bf6d80 100644 --- a/src/vpnHandler/vpn.js +++ b/src/vpnHandler/vpn.js @@ -98,3 +98,56 @@ export function createWireGuardConnection() { // 6. return to Electron app return { ip, publicKey, clientConf }; } + + +// -------- Disconnect VPN PART START ----------- +const removePeerFromConf = (publicKey) => { + const conf = fs.readFileSync(WG_CONF, "utf8"); + + const peerRegex = new RegExp( + `\\n\\[Peer\\][\\s\\S]*?PublicKey = ${publicKey}[\\s\\S]*?(?=\\n\\[Peer\\]|$)`, + "g" + ); + + const updated = conf.replace(peerRegex, "\n"); + + fs.writeFileSync(WG_CONF, updated); +} + +function syncWireGuard() { + execSync("wg-quick strip wg0 > /tmp/wg0.tmp"); + execSync("wg syncconf wg0 /tmp/wg0.tmp"); + execSync("rm -f /tmp/wg0.tmp"); +} + +export function disconnectWireGuardConnection(ip) { + const db = loadDb(); + + const publicKey = db.active[ip]; + if (!db.active[ip]) { + return { success: false, message: "VPN already disconnected" }; + } + + // 1️⃣ Remove peer from live kernel + execSync(`wg set wg0 peer ${publicKey} remove`); + + // 2️⃣ Remove from config file + removePeerFromConf(publicKey); + + // 3️⃣ Sync config + syncWireGuard(); + + // 4️⃣ Update DB (free IP) + delete db.active[ip]; + db.free.push(ip); + saveDb(db); + + return { + success: true, + message: "VPN disconnected", + ip + }; +} + + +