Add full dockurr/windows source with rego customizations
Some checks failed
Test / test (push) Has been cancelled
Some checks failed
Test / test (push) Has been cancelled
- Includes complete dockurr/windows source (not just FROM image) - Added openssh-client and sshpass to Dockerfile - Added SSH key for Windows VM access - Added VPN automation scripts (vpn-login.js, socks5.js, vpn.bat) - Added Windows setup scripts (install-nodejs.ps1, setup-autologin-sshd.ps1, setup-ssh-keys.ps1) - Added rego-startup.sh for script deployment and network setup - Scripts auto-copy to shared folder on container start 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
459
apps/rego-tunnel/build/rego/vpn-login.js
Normal file
459
apps/rego-tunnel/build/rego/vpn-login.js
Normal file
@@ -0,0 +1,459 @@
|
||||
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 before starting SOCKS5
|
||||
const vpnConnected = await verifyVpnConnection();
|
||||
|
||||
if (!vpnConnected) {
|
||||
log("ERROR: VPN connection could not be verified");
|
||||
log("SOCKS5 proxy NOT started");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Start SOCKS5 proxy only after VPN verified
|
||||
log("Starting SOCKS5 proxy on port 1080...");
|
||||
run("taskkill /F /IM node.exe /FI \"WINDOWTITLE eq socks5\"");
|
||||
spawn("node", ["C:\\Users\\alexz\\vpn_scripts\\socks5.js"], {
|
||||
detached: true,
|
||||
stdio: "ignore",
|
||||
windowsHide: true
|
||||
}).unref();
|
||||
|
||||
console.log("");
|
||||
console.log("========================================");
|
||||
console.log(" CONNECTED!");
|
||||
console.log(" SOCKS5 proxy: 172.30.0.16:1080");
|
||||
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!");
|
||||
// Restart socks5
|
||||
run("taskkill /F /IM node.exe /FI \"WINDOWTITLE eq socks5\"");
|
||||
spawn("node", ["C:\\Users\\alexz\\vpn_scripts\\socks5.js"], {
|
||||
detached: true,
|
||||
stdio: "ignore",
|
||||
windowsHide: true
|
||||
}).unref();
|
||||
return true;
|
||||
}
|
||||
|
||||
log("Reconnection failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
main().catch(err => {
|
||||
log("ERROR: " + err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user