feat: add default nordvpn credential paths

This commit is contained in:
Stefano Fiorini
2026-03-12 00:09:56 -05:00
parent 78be4fc600
commit 045cf6aad2
3 changed files with 51 additions and 14 deletions

View File

@@ -12,6 +12,16 @@ const WG_STATE_DIR = path.join(STATE_DIR, "wireguard");
const WG_CONFIG_PATH = path.join(WG_STATE_DIR, `${MAC_WG_INTERFACE}.conf`);
const AUTH_CACHE_PATH = path.join(STATE_DIR, "auth.json");
const LAST_CONNECTION_PATH = path.join(STATE_DIR, "last-connection.json");
const OPENCLAW_NORDVPN_CREDENTIALS_DIR = path.join(
os.homedir(),
".openclaw",
"workspace",
".clawdbot",
"credentials",
"nordvpn"
);
const DEFAULT_TOKEN_FILE = path.join(OPENCLAW_NORDVPN_CREDENTIALS_DIR, "token.txt");
const DEFAULT_PASSWORD_FILE = path.join(OPENCLAW_NORDVPN_CREDENTIALS_DIR, "password.txt");
const DEFAULT_DNS_IPV4 = "103.86.96.100";
const DEFAULT_DNS_IPV6 = "2400:bb40:4444::100";
const CLIENT_IPV4 = "10.5.0.2";
@@ -39,9 +49,11 @@ function usage() {
env: [
"NORDVPN_TOKEN",
"NORDVPN_TOKEN_FILE",
`default token file: ${DEFAULT_TOKEN_FILE}`,
"NORDVPN_USERNAME",
"NORDVPN_PASSWORD",
"NORDVPN_PASSWORD_FILE",
`default password file: ${DEFAULT_PASSWORD_FILE}`,
],
};
}
@@ -75,13 +87,22 @@ function detectPlatform() {
function readSecret(envName, fileEnvName) {
if (process.env[envName]) return process.env[envName];
const filePath = process.env[fileEnvName];
if (!filePath) return "";
try {
return fs.readFileSync(filePath, "utf8").trim();
} catch {
return "";
const candidates = [];
if (process.env[fileEnvName]) candidates.push(process.env[fileEnvName]);
if (envName === "NORDVPN_TOKEN") candidates.push(DEFAULT_TOKEN_FILE);
if (envName === "NORDVPN_PASSWORD") candidates.push(DEFAULT_PASSWORD_FILE);
for (const candidate of candidates) {
try {
const value = fs.readFileSync(candidate, "utf8").trim();
if (value) return value;
} catch {
// Continue.
}
}
return "";
}
function normalizeLocation(value) {
@@ -370,7 +391,7 @@ function buildStateSummary(installProbe, ipInfo) {
? installProbe.wireguard.sudoReady
? "Use token-based WireGuard automation on macOS."
: "WireGuard tooling and token are available, but connect/disconnect require non-interactive sudo for wg-quick. Authorize sudo for wg-quick, then rerun login/connect."
: "Set NORDVPN_TOKEN or NORDVPN_TOKEN_FILE for automated macOS NordLynx/WireGuard connects.";
: `Set NORDVPN_TOKEN, NORDVPN_TOKEN_FILE, or place the token at ${DEFAULT_TOKEN_FILE} for automated macOS NordLynx/WireGuard connects.`;
} else if (installProbe.platform === "darwin" && installProbe.appInstalled) {
controlMode = "app-manual";
automaticControl = false;
@@ -378,7 +399,7 @@ function buildStateSummary(installProbe, ipInfo) {
connectMode = "app-manual";
recommendedAction = installProbe.tokenAvailable
? "NordVPN.app is installed, but automated macOS connects also require wireguard-go and wireguard-tools. Run 'node scripts/nordvpn-client.js install' to install them with Homebrew."
: "NordVPN.app is installed. For automated macOS connects, run 'node scripts/nordvpn-client.js install' to install wireguard-go and wireguard-tools with Homebrew, then set NORDVPN_TOKEN or NORDVPN_TOKEN_FILE and run login.";
: `NordVPN.app is installed. For automated macOS connects, run 'node scripts/nordvpn-client.js install' to install wireguard-go and wireguard-tools with Homebrew, then set NORDVPN_TOKEN, NORDVPN_TOKEN_FILE, or place the token at ${DEFAULT_TOKEN_FILE} and run login.`;
} else if (installProbe.platform === "darwin" && installProbe.brewPath) {
controlMode = "wireguard-bootstrap";
automaticControl = false;
@@ -759,7 +780,7 @@ async function runSudoWireguard(installProbe, action) {
async function connectViaMacWireguard(installProbe, target) {
const token = readSecret("NORDVPN_TOKEN", "NORDVPN_TOKEN_FILE");
if (!token) {
throw new Error("macOS NordLynx/WireGuard automation requires NORDVPN_TOKEN or NORDVPN_TOKEN_FILE.");
throw new Error(`macOS NordLynx/WireGuard automation requires NORDVPN_TOKEN, NORDVPN_TOKEN_FILE, or a token at ${DEFAULT_TOKEN_FILE}.`);
}
if (!installProbe.wireguard || !installProbe.wireguard.dependenciesReady) {
throw new Error("wireguard-go and wireguard-tools are required on macOS. Run install first.");
@@ -912,7 +933,13 @@ async function loginNordvpn(installProbe) {
backend: "wireguard",
validatedAt: new Date().toISOString(),
hasNordlynxPrivateKey: Boolean(credentials.nordlynx_private_key),
tokenSource: process.env.NORDVPN_TOKEN ? "env:NORDVPN_TOKEN" : process.env.NORDVPN_TOKEN_FILE ? "file:NORDVPN_TOKEN_FILE" : "unknown",
tokenSource: process.env.NORDVPN_TOKEN
? "env:NORDVPN_TOKEN"
: process.env.NORDVPN_TOKEN_FILE
? "file:NORDVPN_TOKEN_FILE"
: fileExists(DEFAULT_TOKEN_FILE)
? `default:${DEFAULT_TOKEN_FILE}`
: "unknown",
};
writeJsonFile(AUTH_CACHE_PATH, cache);
return {
@@ -932,7 +959,7 @@ async function loginNordvpn(installProbe) {
backend: "app-manual",
manualActionRequired: true,
message:
"Opened NordVPN.app. Complete login in the app/browser flow, or set NORDVPN_TOKEN / NORDVPN_TOKEN_FILE to use the automated macOS WireGuard backend.",
`Opened NordVPN.app. Complete login in the app/browser flow, or set NORDVPN_TOKEN, NORDVPN_TOKEN_FILE, or place the token at ${DEFAULT_TOKEN_FILE} to use the automated macOS WireGuard backend.`,
};
}
@@ -1007,7 +1034,7 @@ async function main() {
} else if (platform === "darwin" && installProbe.appInstalled) {
connectResult = await connectViaMacApp(target);
} else if (platform === "darwin" && !installProbe.tokenAvailable) {
throw new Error("macOS automated NordLynx/WireGuard connects require NORDVPN_TOKEN or NORDVPN_TOKEN_FILE.");
throw new Error(`macOS automated NordLynx/WireGuard connects require NORDVPN_TOKEN, NORDVPN_TOKEN_FILE, or a token at ${DEFAULT_TOKEN_FILE}.`);
} else if (platform === "darwin") {
throw new Error("No usable macOS NordVPN backend is ready. Run install to bootstrap WireGuard tooling.");
} else if (!installProbe.installed) {