VPN Update

This commit is contained in:
BhagwanSingh 2025-12-08 15:13:25 +05:30
parent 586531bdbc
commit 0421a20b4a
11 changed files with 320 additions and 20 deletions

View File

@ -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",

Binary file not shown.

View File

@ -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

View File

@ -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

View File

@ -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();
});

View File

@ -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,

View File

@ -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<Key extends keyof EventPayloadMapping>(

View File

@ -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 }
);

223
src/electron/vpn.ts Normal file
View File

@ -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<string> {
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<string> {
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<string> {
// 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<string> {
// 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<string> {
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<string> {
// const cli = findWireGuardCLI();
// if (!cli) return Promise.reject("WireGuard CLI not found");
// return execPromise(`"${cli}" /uninstalltunnelservice wg0`);
// }
async function disconnectWindows(): Promise<string> {
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<string> {
const conf = getConfigPath();
return execPromise(`sudo wg-quick up "${conf}"`).then(() => "macOS VPN connected");
}
function disconnectMac(): Promise<string> {
return execPromise(`sudo wg-quick down wg0`).then(() => "macOS VPN disconnected");
}
//
// ------------------ PUBLIC API ------------------
//
export function startVPN(): Promise<string> {
const platform = os.platform();
if (platform === "win32") return connectWindows();
if (platform === "darwin") return connectMac();
return Promise.reject("Unsupported OS");
}
export function stopVPN(): Promise<string> {
const platform = os.platform();
if (platform === "win32") return disconnectWindows();
if (platform === "darwin") return disconnectMac();
return Promise.reject("Unsupported OS");
}

View File

@ -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 (
<>
<div className="flex flex-col h-screen overflow-hidden">
<button
onClick={() => {
window.electron.connectVPN().then((msg) => {
console.log(msg);
});
}}
>
Connect VPN
</button>
<button
onClick={() => {
window.electron.disconnectVPN();
}}
>
Disconnect VPN
</button>
{/* Header */}
{isTracking &&
<header className="w-full flex justify-between items-center px-4 py-2 bg-base-100 border-b border-base-300 sticky top-0 z-30">

3
types.d.ts vendored
View File

@ -241,6 +241,9 @@ interface Window {
success: boolean;
data?: any;
}>;
connectVPN: () => Promise<string>;
disconnectVPN: () => Promise<void>;
};
}