From 0421a20b4ad34abc18e9ff6a2cf669396ec92af4 Mon Sep 17 00:00:00 2001 From: BhagwanSingh Date: Mon, 8 Dec 2025 15:13:25 +0530 Subject: [PATCH] VPN Update --- package.json | 11 +- .../wireguard-install/wireguard-installer.exe | Bin 0 -> 87360 bytes resources/wireguard/mac/wg0.conf | 10 + resources/wireguard/windows/wg0.conf | 10 + src/electron/ipc/ipcHandler.ts | 9 +- src/electron/main.ts | 37 ++- src/electron/preload.cts | 3 + src/electron/utils/utilityFunctions.ts | 2 +- src/electron/vpn.ts | 223 ++++++++++++++++++ src/ui/layout/DashboardLayout.tsx | 32 ++- types.d.ts | 3 + 11 files changed, 320 insertions(+), 20 deletions(-) create mode 100644 resources/wireguard-install/wireguard-installer.exe create mode 100644 resources/wireguard/mac/wg0.conf create mode 100644 resources/wireguard/windows/wg0.conf create mode 100644 src/electron/vpn.ts diff --git a/package.json b/package.json index aeb2cc7..d4a31c0 100644 --- a/package.json +++ b/package.json @@ -70,6 +70,14 @@ { "from": "src/assets", "to": "assets" + }, + { + "from": "resources/wireguard-install", + "to": "wireguard-install" + }, + { + "from": "resources/wireguard", + "to": "wireguard" } ], "mac": { @@ -83,6 +91,7 @@ } }, "win": { + "requestedExecutionLevel": "requireAdministrator", "target": [ { "target": "nsis", @@ -126,4 +135,4 @@ "vite": "^5.4.7", "vitest": "^2.1.1" } -} +} \ No newline at end of file diff --git a/resources/wireguard-install/wireguard-installer.exe b/resources/wireguard-install/wireguard-installer.exe new file mode 100644 index 0000000000000000000000000000000000000000..032922d273ed4de0c2e2de0b5d1964a68da7ed20 GIT binary patch literal 87360 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 literal 0 HcmV?d00001 diff --git a/resources/wireguard/mac/wg0.conf b/resources/wireguard/mac/wg0.conf new file mode 100644 index 0000000..5053efb --- /dev/null +++ b/resources/wireguard/mac/wg0.conf @@ -0,0 +1,10 @@ +[Interface] +PrivateKey = CEzCd25ufxbOjvRhMqLfkcdP/OziG5i6OkXCfMZrI1I= +Address = 10.0.0.2/24 +DNS = 1.1.1.1 + +[Peer] +PublicKey = jG+7H5thEiNjxY1XqI1R9oyMAMTIegLwE3tZkS1Rj2U= +Endpoint = 35.95.209.161:51820 +AllowedIPs = 10.0.0.0/24 +PersistentKeepalive = 25 diff --git a/resources/wireguard/windows/wg0.conf b/resources/wireguard/windows/wg0.conf new file mode 100644 index 0000000..5053efb --- /dev/null +++ b/resources/wireguard/windows/wg0.conf @@ -0,0 +1,10 @@ +[Interface] +PrivateKey = CEzCd25ufxbOjvRhMqLfkcdP/OziG5i6OkXCfMZrI1I= +Address = 10.0.0.2/24 +DNS = 1.1.1.1 + +[Peer] +PublicKey = jG+7H5thEiNjxY1XqI1R9oyMAMTIegLwE3tZkS1Rj2U= +Endpoint = 35.95.209.161:51820 +AllowedIPs = 10.0.0.0/24 +PersistentKeepalive = 25 diff --git a/src/electron/ipc/ipcHandler.ts b/src/electron/ipc/ipcHandler.ts index edaa1df..5ec569b 100644 --- a/src/electron/ipc/ipcHandler.ts +++ b/src/electron/ipc/ipcHandler.ts @@ -3,6 +3,7 @@ import { getToken, saveToken, clearToken } from "../utils/tokenHelper.js"; import { getActiveApp, handleLogin, takeScreenshot, startWindowPolling, getRunningAppsList, captureSpecificApp } from "../utils/utilityFunctions.js"; import api from "../api/axiosClient.js"; import { getMainWindow } from '../main.js'; +import { startVPN, stopVPN } from "../vpn.js"; @@ -546,4 +547,10 @@ export const sendTokenExpired = () => { }; -; +ipcMain.handle("vpn-connect", async () => { + return startVPN(); +}); + +ipcMain.handle("vpn-disconnect", async () => { + stopVPN(); +}); \ No newline at end of file diff --git a/src/electron/main.ts b/src/electron/main.ts index 2e6f53d..9dbe4d0 100644 --- a/src/electron/main.ts +++ b/src/electron/main.ts @@ -8,6 +8,9 @@ import "./ipc/ipcHandler.js"; import path from "path"; import { fileURLToPath } from "url"; +import * as fs from "fs"; +import { execFile } from "child_process"; + app.setAppUserModelId("com.tracker.app"); const __filename = fileURLToPath(import.meta.url); @@ -52,12 +55,26 @@ app.on("second-instance", () => { } }); + +// CHECKING IF WIREGUARD EXIST - IF NOT INSTALLING IN CLIENT MACHINE +const wgPath = "C:\\Program Files\\WireGuard\\wireguard.exe"; + +if (!fs.existsSync(wgPath)) { + const installer = path.join(process.resourcesPath, "wireguard-install", "wireguard-installer.exe"); + + execFile(installer, ["/quiet"], (err) => { + if (err) console.error("WireGuard install failed:", err); + else console.log("WireGuard installed successfully."); + }); +} +// CHECKING IF WIREGUARD EXIST - IF NOT INSTALLING IN CLIENT MACHINE + + // --------------------------- // MAIN APP READY // --------------------------- app.on("ready", async () => { - splashWindow = new BrowserWindow({ width: 300, height: 300, @@ -90,8 +107,8 @@ app.on("ready", async () => { // alwaysOnTop: true, // skipTaskbar: true, autoHideMenuBar: true, - frame: true, - show: false, + frame: true, + show: false, icon: resolveIcon(), webPreferences: { devTools: true, @@ -102,14 +119,14 @@ app.on("ready", async () => { }); - - // win.setAlwaysOnTop(true, 'screen-saver'); - // win.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true }); - // win.setFullScreenable(false); - + + // win.setAlwaysOnTop(true, 'screen-saver'); + // win.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true }); + // win.setFullScreenable(false); + // Cross-platform safe always-on-top const isMac = process.platform === "darwin"; - + if (isMac) { win.setAlwaysOnTop(true, "floating"); // best for macOS win.setVisibleOnAllWorkspaces(true); // NO fullscreen override @@ -117,7 +134,7 @@ app.on("ready", async () => { win.setAlwaysOnTop(true, "normal"); // safest for Windows + Zoom win.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true }); win.setFullScreenable(false); -} + } mainWindow = win; diff --git a/src/electron/preload.cts b/src/electron/preload.cts index 870cf71..1de0eea 100644 --- a/src/electron/preload.cts +++ b/src/electron/preload.cts @@ -65,6 +65,9 @@ contextBridge.exposeInMainWorld('electron', { getLeaveList: () => ipcRenderer.invoke("get-leave-list"), getAdjustmentsList:(vaId: string) => ipcRenderer.invoke("get-adjustments-list",vaId), + connectVPN: () => ipcRenderer.invoke("vpn-connect"), + disconnectVPN: () => ipcRenderer.invoke("vpn-disconnect"), + } satisfies Window['electron']); // function ipcInvoke( diff --git a/src/electron/utils/utilityFunctions.ts b/src/electron/utils/utilityFunctions.ts index 17d3319..c09a7ab 100644 --- a/src/electron/utils/utilityFunctions.ts +++ b/src/electron/utils/utilityFunctions.ts @@ -68,7 +68,7 @@ export const handleLogin = async (credentials: { email: string, password: string try { console.log("➡️ Calling API..."); const response = await axios.post( - 'quality-friendly-goldfish.ngrok-free.app/api/v1/va/login', + 'https://quality-friendly-goldfish.ngrok-free.app/api/v1/va/login', { userDetails: { ...credentials } }, { headers: { "ngrok-skip-browser-warning": 69420 }, httpsAgent } ); diff --git a/src/electron/vpn.ts b/src/electron/vpn.ts new file mode 100644 index 0000000..19596b9 --- /dev/null +++ b/src/electron/vpn.ts @@ -0,0 +1,223 @@ +import { app } from "electron"; +import { exec, execFile } from "child_process"; +import fs from "fs"; +import os from "os"; +import path from "path"; + +// +// ------------------ HELPERS ------------------ +// + +// Promise wrapper for exec() +function execPromise(cmd: string): Promise { + return new Promise((resolve, reject) => { + exec(cmd, (err, stdout, stderr) => { + if (err) return reject(stderr || err); + resolve(stdout); + }); + }); +} + +// Detect dev vs production +function isDev() { + return !app.isPackaged; +} + +// +// ------------------ PATH RESOLVERS ------------------ +// + +// WireGuard installer path (Windows only) +// function getWireGuardInstallerPath(): string { +// return isDev() +// ? path.join(process.cwd(), "resources", "wireguard-install", "wireguard-installer.exe") +// : path.join(process.resourcesPath, "wireguard-install", "wireguard-installer.exe"); +// } + +function getWireGuardInstallerPath(): string { + const devPath = path.join(process.cwd(), "resources", "wireguard-install", "wireguard-installer.exe"); + + // When running "npm run dev", use devPath ALWAYS + if (!app.isPackaged) { + console.log("DEV MODE Installer Path:", devPath); + return devPath; + } + + // Production build path + const prodPath = path.join(process.resourcesPath, "wireguard-install", "wireguard-installer.exe"); + console.log("PROD MODE Installer Path:", prodPath); + return prodPath; +} + + +// OS-specific wg0.conf +function getConfigPath(): string { + const base = isDev() + ? path.join(process.cwd(), "resources", "wireguard") + : path.join(process.resourcesPath, "wireguard"); + + if (process.platform === "win32") { + return path.join(base, "windows", "wg0.conf"); + } + + if (process.platform === "darwin") { + return path.join(base, "macos", "wg0.conf"); + } + + throw new Error("Unsupported OS"); +} + +// Detect installed WireGuard.exe on Windows +function findWireGuardCLI(): string | null { + const possiblePaths = [ + "C:\\Program Files\\WireGuard\\wireguard.exe", + "C:\\Program Files (x86)\\WireGuard\\wireguard.exe" + ]; + + for (const p of possiblePaths) { + if (fs.existsSync(p)) return p; + } + + return null; +} + +// +// ------------------ WINDOWS INSTALL LOGIC ------------------ +// + +// Install WireGuard silently +async function ensureWireGuardInstalled(): Promise { + let cli = findWireGuardCLI(); + if (cli) return cli; + + // Installer path + const installer = getWireGuardInstallerPath(); + if (!fs.existsSync(installer)) { + throw new Error("WireGuard installer not found in resources."); + } + + console.log("WireGuard not found. Installing silently..."); + await execPromise(`"${installer}" /quiet`); + + cli = findWireGuardCLI(); + if (!cli) throw new Error("WireGuard installation failed."); + + console.log("WireGuard installed successfully:", cli); + return cli; +} + +// +// ------------------ WINDOWS CONNECT/DISCONNECT ------------------ +// + +// async function connectWindows(): Promise { +// const cli = await ensureWireGuardInstalled(); +// const conf = getConfigPath(); + +// // Disable GUI auto popup +// await execPromise( +// `reg add "HKCU\\Software\\WireGuard" /v SuppressTray /t REG_DWORD /d 1 /f` +// ); + +// return new Promise((resolve, reject) => { +// execFile(cli, ["/installtunnelservice", conf], (err) => { +// if (err) return reject("Failed to connect VPN: " + err); +// resolve("Windows VPN connected without GUI"); +// }); +// }); +// } + +// let wgRuntimeProcess: any = null; + +// async function connectWindows(): Promise { +// const cli = await ensureWireGuardInstalled(); +// const conf = getConfigPath(); + +// return new Promise((resolve, reject) => { +// wgRuntimeProcess = execFile(cli, ["/tunnelservice", conf], (err) => { +// if (err) return reject("VPN connection error: " + err); +// }); + +// // Wait a bit for interface to come up +// setTimeout(() => resolve("Windows VPN connected silently"), 800); +// }); +// } + + +async function connectWindows(): Promise { + const cli = await ensureWireGuardInstalled(); + const conf = getConfigPath(); + + // Disable GUI popup and silent mode (ignore errors) + await execPromise(`reg add "HKCU\\Software\\WireGuard" /v HideTrayIcon /t REG_DWORD /d 1 /f`).catch(() => {}); + await execPromise(`reg add "HKCU\\Software\\WireGuard" /v SuppressTray /t REG_DWORD /d 1 /f`).catch(() => {}); + await execPromise(`reg delete "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run" /v WireGuard /f`).catch(() => {}); + + // Start background service + await execPromise(`sc start WireGuardManager`).catch(() => {}); + + return new Promise((resolve, reject) => { + execFile(cli, ["/installtunnelservice", conf], (err) => { + if (err) return reject("VPN connection failed: " + err); + resolve("Windows VPN connected silently"); + }); + }); +} + +// function disconnectWindows(): Promise { +// const cli = findWireGuardCLI(); +// if (!cli) return Promise.reject("WireGuard CLI not found"); + +// return execPromise(`"${cli}" /uninstalltunnelservice wg0`); +// } + +async function disconnectWindows(): Promise { + const cli = findWireGuardCLI(); + if (!cli) throw new Error("WireGuard CLI not found"); + + // 1. Remove the installed tunnel service + await execPromise(`"${cli}" /uninstalltunnelservice wg0`); + + // 2. Ensure background service is still running (optional clean-up) + // Windows sometimes marks the service as "stopped" after uninstall + await execPromise(`sc stop WireGuardTunnel$wg0`).catch(() => { }); + await execPromise(`sc stop WireGuardManager`).catch(() => { }); + + return "Windows VPN disconnected"; +} + + +// +// ------------------ MACOS CONNECT/DISCONNECT ------------------ +// + +function connectMac(): Promise { + const conf = getConfigPath(); + return execPromise(`sudo wg-quick up "${conf}"`).then(() => "macOS VPN connected"); +} + +function disconnectMac(): Promise { + return execPromise(`sudo wg-quick down wg0`).then(() => "macOS VPN disconnected"); +} + +// +// ------------------ PUBLIC API ------------------ +// + +export function startVPN(): Promise { + const platform = os.platform(); + + if (platform === "win32") return connectWindows(); + if (platform === "darwin") return connectMac(); + + return Promise.reject("Unsupported OS"); +} + +export function stopVPN(): Promise { + const platform = os.platform(); + + if (platform === "win32") return disconnectWindows(); + if (platform === "darwin") return disconnectMac(); + + return Promise.reject("Unsupported OS"); +} diff --git a/src/ui/layout/DashboardLayout.tsx b/src/ui/layout/DashboardLayout.tsx index d1142e4..fc02701 100644 --- a/src/ui/layout/DashboardLayout.tsx +++ b/src/ui/layout/DashboardLayout.tsx @@ -260,11 +260,11 @@ const DashboardLayout = () => { ); // STEP 6: Update UI (restore window) - console.log("🪟 STEP 6: Restoring window..."); - await window.electron.toggleCloseBtn(true); - await window.electron.resizeWindow(500, 600); - toggleWindowSize.current = true; - console.log("✅ Window restored"); + console.log("🪟 STEP 6: Restoring window..."); + await window.electron.toggleCloseBtn(true); + await window.electron.resizeWindow(500, 600); + toggleWindowSize.current = true; + console.log("✅ Window restored"); // Allow React to process the state update await new Promise(resolve => setTimeout(resolve, 50)); @@ -331,7 +331,7 @@ const DashboardLayout = () => { } } - + } catch (error) { console.error("❌ Error refreshing project list:", error); @@ -588,7 +588,7 @@ const DashboardLayout = () => { if (!selectedProject?.projectId) return console.log(selectedProject?.projectId, "SelectedProject ID") - socketRef.current = io("quality-friendly-goldfish.ngrok-free.app", { + socketRef.current = io("https://quality-friendly-goldfish.ngrok-free.app", { transports: ["websocket"], secure: true, rejectUnauthorized: false, @@ -727,6 +727,24 @@ const DashboardLayout = () => { return ( <>
+ + + + {/* Header */} {isTracking &&
diff --git a/types.d.ts b/types.d.ts index 8f20363..273cad3 100644 --- a/types.d.ts +++ b/types.d.ts @@ -241,6 +241,9 @@ interface Window { success: boolean; data?: any; }>; + + connectVPN: () => Promise; + disconnectVPN: () => Promise; }; }