442 lines
12 KiB
JavaScript
Executable File
442 lines
12 KiB
JavaScript
Executable File
const WebSocket = require("ws");
|
|
const { authenticator } = require("otplib");
|
|
const { execSync, spawn } = require("child_process");
|
|
|
|
const CONFIG = {
|
|
email: "c-azaw@regoproducts.com",
|
|
password: "Fuckyou4suhail",
|
|
totpSecret: "RZQTQSKDWKHZ6ZYR",
|
|
devtoolsPort: 9222,
|
|
vpnTestIp: "10.35.33.230"
|
|
};
|
|
|
|
let ws;
|
|
let msgId = 1;
|
|
|
|
function log(msg) {
|
|
console.log("[" + new Date().toLocaleTimeString() + "] " + msg);
|
|
}
|
|
|
|
function run(cmd) {
|
|
try { execSync(cmd, { stdio: "ignore", timeout: 10000 }); } catch (e) {}
|
|
}
|
|
|
|
function runOutput(cmd) {
|
|
try {
|
|
return execSync(cmd, { encoding: "utf8", timeout: 10000 });
|
|
} catch (e) {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
async function getPages() {
|
|
const res = await fetch("http://localhost:" + CONFIG.devtoolsPort + "/json");
|
|
return res.json();
|
|
}
|
|
|
|
function send(method, params = {}) {
|
|
return new Promise((resolve, reject) => {
|
|
const id = msgId++;
|
|
const timeout = setTimeout(() => reject(new Error("Timeout: " + method)), 15000);
|
|
const handler = (data) => {
|
|
const msg = JSON.parse(data);
|
|
if (msg.id === id) {
|
|
clearTimeout(timeout);
|
|
ws.off("message", handler);
|
|
resolve(msg.result);
|
|
}
|
|
};
|
|
ws.on("message", handler);
|
|
ws.send(JSON.stringify({ id, method, params }));
|
|
});
|
|
}
|
|
|
|
async function waitForSelector(selector, timeout = 30000) {
|
|
const start = Date.now();
|
|
while (Date.now() - start < timeout) {
|
|
try {
|
|
const result = await send("Runtime.evaluate", {
|
|
expression: "document.querySelector('" + selector + "') !== null",
|
|
returnByValue: true
|
|
});
|
|
if (result.result.value === true) return true;
|
|
} catch (e) {}
|
|
await sleep(500);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
async function typeText(selector, text) {
|
|
await send("Runtime.evaluate", {
|
|
expression: "var el = document.querySelector('" + selector + "'); el.focus(); el.value = '';"
|
|
});
|
|
await sleep(100);
|
|
for (const char of text) {
|
|
await send("Input.dispatchKeyEvent", { type: "char", text: char });
|
|
await sleep(30);
|
|
}
|
|
}
|
|
|
|
async function click(selector) {
|
|
await send("Runtime.evaluate", {
|
|
expression: "document.querySelector('" + selector + "').click()"
|
|
});
|
|
}
|
|
|
|
async function clickSubmit() {
|
|
const methods = [
|
|
"document.querySelector('#submitButton') && document.querySelector('#submitButton').click()",
|
|
"typeof Login !== 'undefined' && Login.submitLoginRequest && Login.submitLoginRequest()",
|
|
"document.querySelector('input[type=\"submit\"]') && document.querySelector('input[type=\"submit\"]').click()",
|
|
"document.querySelector('button[type=\"submit\"]') && document.querySelector('button[type=\"submit\"]').click()",
|
|
"document.querySelector('#idSIButton9') && document.querySelector('#idSIButton9').click()"
|
|
];
|
|
for (const expr of methods) {
|
|
try { await send("Runtime.evaluate", { expression: expr }); } catch (e) {}
|
|
}
|
|
}
|
|
|
|
async function sleep(ms) {
|
|
return new Promise(r => setTimeout(r, ms));
|
|
}
|
|
|
|
async function waitForDevtools(maxWait = 120000) {
|
|
const start = Date.now();
|
|
while (Date.now() - start < maxWait) {
|
|
try {
|
|
const pages = await getPages();
|
|
const page = pages.find(p => p.type === "page");
|
|
if (page) return page;
|
|
} catch (e) {}
|
|
log("Waiting for WebView...");
|
|
await sleep(2000);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// VPN adapter check skipped - IP range is unpredictable
|
|
// We rely solely on connectivity test to target IP
|
|
|
|
// Test connectivity via ping (check for actual reply, not TTL expired)
|
|
function testVpnConnectivity(ip) {
|
|
try {
|
|
const output = execSync(`ping -n 1 -w 3000 ${ip}`, { encoding: "utf8", timeout: 5000 });
|
|
// Must have "Reply from <ip>" - not "TTL expired" or "Request timed out"
|
|
return output.includes(`Reply from ${ip}`);
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Verify VPN is connected with retries (connectivity test only)
|
|
async function verifyVpnConnection(maxRetries = 10, retryDelay = 5000) {
|
|
log("--- VPN VERIFICATION ---");
|
|
|
|
for (let i = 1; i <= maxRetries; i++) {
|
|
log(`Attempt ${i}/${maxRetries}: Pinging ${CONFIG.vpnTestIp}...`);
|
|
const connected = testVpnConnectivity(CONFIG.vpnTestIp);
|
|
|
|
if (connected) {
|
|
log("VPN connectivity confirmed!");
|
|
return true;
|
|
}
|
|
|
|
log("Not reachable yet, waiting...");
|
|
if (i < maxRetries) {
|
|
await sleep(retryDelay);
|
|
}
|
|
}
|
|
|
|
log("VPN verification failed after " + maxRetries + " attempts");
|
|
return false;
|
|
}
|
|
|
|
async function main() {
|
|
console.log("");
|
|
console.log("========================================");
|
|
console.log(" CISCO VPN AUTO-LOGIN");
|
|
console.log("========================================");
|
|
console.log("");
|
|
|
|
// Sync time first (TOTP requires accurate time)
|
|
log("Syncing system time...");
|
|
run("sc config w32time start= auto");
|
|
run("net start w32time");
|
|
run("w32tm /config /manualpeerlist:pool.ntp.org /syncfromflags:manual /update");
|
|
run("w32tm /resync /force");
|
|
await sleep(2000);
|
|
|
|
// Kill everything
|
|
log("Killing Cisco processes...");
|
|
run("taskkill /F /IM csc_ui.exe");
|
|
run("taskkill /F /IM vpnui.exe");
|
|
run("taskkill /F /IM vpnagent.exe");
|
|
run('net stop csc_vpnagent');
|
|
await sleep(2000);
|
|
|
|
// Start agent
|
|
log("Starting Cisco agent...");
|
|
run('net start csc_vpnagent');
|
|
await sleep(3000);
|
|
|
|
// Start UI
|
|
log("Starting Cisco UI...");
|
|
process.env.WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS = "--remote-debugging-port=9222 --remote-debugging-address=0.0.0.0 --remote-allow-origins=*";
|
|
spawn("C:\\Program Files (x86)\\Cisco\\Cisco Secure Client\\UI\\csc_ui.exe", [], {
|
|
detached: true,
|
|
stdio: "ignore"
|
|
}).unref();
|
|
|
|
await sleep(5000);
|
|
|
|
// Wait for WebView
|
|
const page = await waitForDevtools();
|
|
if (!page) {
|
|
log("ERROR: WebView not found - rebooting...");
|
|
run("shutdown /r /t 1");
|
|
process.exit(1);
|
|
}
|
|
|
|
log("WebView: " + page.title);
|
|
ws = new WebSocket(page.webSocketDebuggerUrl);
|
|
await new Promise((resolve, reject) => {
|
|
ws.on("open", resolve);
|
|
ws.on("error", reject);
|
|
});
|
|
|
|
await send("DOM.enable");
|
|
await send("Runtime.enable");
|
|
await send("Input.enable");
|
|
log("Connected to DevTools");
|
|
|
|
const url = page.url || "";
|
|
const isADFS = url.includes("adfs");
|
|
log("Login type: " + (isADFS ? "ADFS" : "Microsoft"));
|
|
|
|
if (isADFS) {
|
|
log("--- ADFS LOGIN ---");
|
|
if (!await waitForSelector("#passwordInput", 15000)) {
|
|
log("Password field not found");
|
|
process.exit(1);
|
|
}
|
|
log("Entering password...");
|
|
await typeText("#passwordInput", CONFIG.password);
|
|
await sleep(500);
|
|
log("Clicking Sign In...");
|
|
await clickSubmit();
|
|
await sleep(3000);
|
|
} else {
|
|
log("--- EMAIL ---");
|
|
if (await waitForSelector('input[type="email"]', 5000)) {
|
|
log("Entering email...");
|
|
await typeText('input[type="email"]', CONFIG.email);
|
|
await sleep(500);
|
|
log("Clicking Next...");
|
|
await clickSubmit();
|
|
await sleep(3000);
|
|
}
|
|
|
|
log("--- PASSWORD ---");
|
|
if (!await waitForSelector('input[type="password"]', 15000)) {
|
|
log("Password field not found");
|
|
process.exit(1);
|
|
}
|
|
log("Entering password...");
|
|
await typeText('input[type="password"]', CONFIG.password);
|
|
await sleep(500);
|
|
log("Clicking Sign In...");
|
|
await clickSubmit();
|
|
await sleep(3000);
|
|
}
|
|
|
|
// TOTP
|
|
log("--- TOTP ---");
|
|
if (await waitForSelector('input[name="otc"]', 15000)) {
|
|
await sleep(500);
|
|
const totp = authenticator.generate(CONFIG.totpSecret);
|
|
log("TOTP: " + totp);
|
|
await typeText('input[name="otc"]', totp);
|
|
await sleep(500);
|
|
log("Submitting...");
|
|
await clickSubmit();
|
|
await sleep(3000);
|
|
} else {
|
|
log("No TOTP field");
|
|
}
|
|
|
|
// Stay signed in
|
|
log("--- STAY SIGNED IN ---");
|
|
if (await waitForSelector("#idBtn_Back", 5000)) {
|
|
log("Clicking No...");
|
|
await click("#idBtn_Back");
|
|
}
|
|
|
|
await sleep(2000);
|
|
ws.close();
|
|
|
|
// Verify VPN connection
|
|
const vpnConnected = await verifyVpnConnection();
|
|
|
|
if (!vpnConnected) {
|
|
log("ERROR: VPN connection could not be verified");
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log("");
|
|
console.log("========================================");
|
|
console.log(" VPN CONNECTED!");
|
|
console.log(" Entering watchdog mode...");
|
|
console.log("========================================");
|
|
console.log("");
|
|
|
|
// Enter watchdog mode - monitor and reconnect if needed
|
|
await watchdogLoop();
|
|
}
|
|
|
|
async function watchdogLoop() {
|
|
const checkInterval = 2 * 60 * 1000; // 2 minutes
|
|
let consecutiveFailures = 0;
|
|
let checkCount = 0;
|
|
|
|
log("Watchdog: Monitoring every 2 minutes...");
|
|
|
|
while (true) {
|
|
await sleep(checkInterval);
|
|
checkCount++;
|
|
|
|
// Force garbage collection every 10 checks (~20 min)
|
|
if (checkCount % 10 === 0 && global.gc) {
|
|
global.gc();
|
|
}
|
|
|
|
// Log memory every 30 checks (~1 hour)
|
|
if (checkCount % 30 === 0) {
|
|
const mem = Math.round(process.memoryUsage().heapUsed / 1024 / 1024);
|
|
log(`Watchdog: Memory ${mem}MB, checks ${checkCount}`);
|
|
}
|
|
|
|
const connected = testVpnConnectivity(CONFIG.vpnTestIp);
|
|
|
|
if (connected) {
|
|
if (consecutiveFailures > 0) {
|
|
log("Watchdog: Connection restored");
|
|
}
|
|
consecutiveFailures = 0;
|
|
} else {
|
|
consecutiveFailures++;
|
|
log(`Watchdog: Connection FAILED (${consecutiveFailures})`);
|
|
|
|
if (consecutiveFailures >= 2) {
|
|
log("Watchdog: Reconnecting...");
|
|
await reconnectVpn();
|
|
consecutiveFailures = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
async function reconnectVpn() {
|
|
// Sync time first (TOTP requires accurate time)
|
|
log("Syncing system time...");
|
|
run("sc config w32time start= auto");
|
|
run("net start w32time");
|
|
run("w32tm /resync /force");
|
|
await sleep(1000);
|
|
|
|
// Kill and restart VPN
|
|
log("Killing Cisco processes...");
|
|
run("taskkill /F /IM csc_ui.exe");
|
|
run("taskkill /F /IM vpnui.exe");
|
|
run("taskkill /F /IM vpnagent.exe");
|
|
run('net stop "Cisco Secure Client Agent"');
|
|
await sleep(2000);
|
|
|
|
log("Starting Cisco agent...");
|
|
run('net start "Cisco Secure Client Agent"');
|
|
await sleep(3000);
|
|
|
|
log("Starting Cisco UI...");
|
|
spawn("C:\\Program Files (x86)\\Cisco\\Cisco Secure Client\\UI\\csc_ui.exe", [], {
|
|
detached: true,
|
|
stdio: "ignore"
|
|
}).unref();
|
|
|
|
await sleep(5000);
|
|
|
|
const page = await waitForDevtools();
|
|
if (!page) {
|
|
log("ERROR: WebView not found - rebooting...");
|
|
run("shutdown /r /t 1");
|
|
return false;
|
|
}
|
|
|
|
ws = new WebSocket(page.webSocketDebuggerUrl);
|
|
await new Promise((resolve, reject) => {
|
|
ws.on("open", resolve);
|
|
ws.on("error", reject);
|
|
});
|
|
|
|
await send("DOM.enable");
|
|
await send("Runtime.enable");
|
|
await send("Input.enable");
|
|
|
|
const url = page.url || "";
|
|
const isADFS = url.includes("adfs");
|
|
|
|
if (isADFS) {
|
|
if (await waitForSelector("#passwordInput", 15000)) {
|
|
await typeText("#passwordInput", CONFIG.password);
|
|
await sleep(500);
|
|
await clickSubmit();
|
|
await sleep(3000);
|
|
}
|
|
} else {
|
|
if (await waitForSelector('input[type="email"]', 5000)) {
|
|
await typeText('input[type="email"]', CONFIG.email);
|
|
await sleep(500);
|
|
await clickSubmit();
|
|
await sleep(3000);
|
|
}
|
|
if (await waitForSelector('input[type="password"]', 15000)) {
|
|
await typeText('input[type="password"]', CONFIG.password);
|
|
await sleep(500);
|
|
await clickSubmit();
|
|
await sleep(3000);
|
|
}
|
|
}
|
|
|
|
// TOTP
|
|
if (await waitForSelector('input[name="otc"]', 15000)) {
|
|
await sleep(500);
|
|
const totp = authenticator.generate(CONFIG.totpSecret);
|
|
log("TOTP: " + totp);
|
|
await typeText('input[name="otc"]', totp);
|
|
await sleep(500);
|
|
await clickSubmit();
|
|
await sleep(3000);
|
|
}
|
|
|
|
// Stay signed in - No
|
|
if (await waitForSelector("#idBtn_Back", 5000)) {
|
|
await click("#idBtn_Back");
|
|
}
|
|
|
|
await sleep(2000);
|
|
ws.close();
|
|
|
|
// Verify reconnection
|
|
const verified = await verifyVpnConnection();
|
|
if (verified) {
|
|
log("Reconnection successful!");
|
|
return true;
|
|
}
|
|
|
|
log("Reconnection failed");
|
|
return false;
|
|
}
|
|
|
|
main().catch(err => {
|
|
log("ERROR: " + err.message);
|
|
process.exit(1);
|
|
});
|