windscout 0.5.7 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -2
- package/dist/cli.js +49 -11
- package/dist/config.js +44 -2
- package/dist/docker.js +349 -0
- package/dist/probe.js +10 -10
- package/dist/scan.js +70 -31
- package/dist/tui/docker.js +241 -0
- package/dist/tui/picker.js +68 -18
- package/dist/tui/progress.js +27 -13
- package/dist/worker.js +92 -0
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@ WindScout drives the official `windscribe-cli`: it connects to each country × p
|
|
|
13
13
|
- Linux, macOS or Windows 10/11
|
|
14
14
|
- Node.js 20+
|
|
15
15
|
- The [Windscribe desktop app](https://windscribe.com/download) installed, running and logged in. It includes `windscribe-cli`, which WindScout uses to control the app. Check with `windscribe-cli status`, which should show `Logged in`. On Windows the app doesn't put the CLI on `PATH`, so run `"C:\Program Files\Windscribe\windscribe-cli.exe" status` instead. WindScout finds it there on its own.
|
|
16
|
+
- Optional, for [parallel scans](#parallel-scan-with-docker): Docker. WindScout offers to install it.
|
|
16
17
|
|
|
17
18
|
## Install
|
|
18
19
|
|
|
@@ -52,6 +53,8 @@ Run `windscout` with no arguments to open the interactive picker:
|
|
|
52
53
|
| `1`–`6` | toggle a protocol (`1`–`5` on Linux, which has no IKEv2) |
|
|
53
54
|
| `s` | toggle the speed test (off = connect-only mode) |
|
|
54
55
|
| `f` | toggle "block internet while scanning" (firewall) |
|
|
56
|
+
| `r` | toggle random order: scan the selected countries shuffled, a new order each run |
|
|
57
|
+
| `d` | toggle the [parallel scan in docker containers](#parallel-scan-with-docker) (installs or starts docker first, after asking) |
|
|
55
58
|
| `u` | update to the newer version and restart (only when the picker shows one is out) |
|
|
56
59
|
| `enter` | start scanning |
|
|
57
60
|
| `q` | quit (during a scan: stop and show partial results; press again to force quit) |
|
|
@@ -60,7 +63,7 @@ Run `windscout` with no arguments to open the interactive picker:
|
|
|
60
63
|
|
|
61
64
|
Your selection is saved to `~/.config/windscout/config.json` (`%USERPROFILE%\.config\windscout\config.json` on Windows) and preselected next time.
|
|
62
65
|
|
|
63
|
-
While scanning, WindScout shows a progress bar, elapsed time and remaining time. It also shows what it's doing right now (connecting, measuring latency or measuring speed). The table of working locations refreshes after each country. When the scan finishes, the final report is printed to your normal terminal. It ends with the best connection and the other working ones, each with its `windscribe-cli connect` command
|
|
66
|
+
While scanning, WindScout shows a progress bar, elapsed time and remaining time. It also shows what it's doing right now (connecting, measuring latency or measuring speed). The table of working locations refreshes after each country. When the scan finishes, the final report is printed to your normal terminal. It ends with the best connection and the other working ones, each with its `windscribe-cli connect` command. At the prompt, press enter to connect to the best one, type another one's number to connect to that, or `q` to quit.
|
|
64
67
|
|
|
65
68
|
### Non-interactive
|
|
66
69
|
|
|
@@ -80,6 +83,8 @@ windscout -t 40 -a # longer connect timeout, also list
|
|
|
80
83
|
| `-a, --all` | include failed attempts in the final table | off |
|
|
81
84
|
| `-n, --no-speed` | connect-only mode: skip the download test, rank by latency | picker: saved, or connect-only on first run; with `-c`: speed test on |
|
|
82
85
|
| `-f, --firewall` | block internet while scanning, except through the VPN | picker: saved, or off; with `-c`: off |
|
|
86
|
+
| `-r, --random` | scan the countries in a random order | picker: saved, or off; with `-c`: off |
|
|
87
|
+
| `-d, --docker` | [scan in parallel, in docker containers](#parallel-scan-with-docker) | picker: saved, or off; with `-c`: off |
|
|
83
88
|
| `-v, --version` | print the installed version; if a newer one is on npm, show the update command (with `sudo` when needed) and ask (y/n) to run it | |
|
|
84
89
|
|
|
85
90
|
## Connect-only mode
|
|
@@ -107,6 +112,48 @@ While scanning, press `tab` to switch between the availability grid and the spee
|
|
|
107
112
|
|
|
108
113
|
Between attempts the VPN is disconnected for a moment, and apps on your computer (browser, messengers, updates) can go online over your real connection. Turn on **block internet while scanning** with `f` in the picker or `--firewall`, and WindScout switches on the Windscribe app's firewall for the scan: nothing gets online except through the VPN. When the scan ends or you stop it, the firewall goes back off (if you already had it on, WindScout leaves it on). While a scan is paused, the firewall keeps blocking.
|
|
109
114
|
|
|
115
|
+
## Parallel scan with Docker
|
|
116
|
+
|
|
117
|
+
A normal scan tries one location at a time, because your computer has one VPN connection. Turn on **parallel scan** with `d` in the picker or `--docker`, and each attempt runs in its own docker container instead. Each container has its own Windscribe app (Windscribe's Linux CLI app) and so its own VPN connection, and several locations are tried at once. The results come back to the scan screen, which shows a line per container.
|
|
118
|
+
|
|
119
|
+
**How many containers:** one per attempt, as many as docker's CPUs allow and three quarters of its memory (at 250 MB each), at most 8. The picker shows the number (`8 at a time`) and the estimate that goes with it.
|
|
120
|
+
|
|
121
|
+
**First time:** if docker isn't installed or isn't running, `d` (or a scan with `--docker`) opens a dialog that says what WindScout will do, and does it once you agree:
|
|
122
|
+
|
|
123
|
+
- **macOS:** downloads Docker Desktop from docker.com (about 600 MB), installs it in `/Applications` with its license accepted, and starts it.
|
|
124
|
+
- **Linux:** runs Docker's install script from get.docker.com (or, where docker.com refuses, installs your distribution's own docker package), adds you to the `docker` group and starts docker. The group takes effect in a new login session: log out and back in (or run `newgrp docker`), then start WindScout again. Members of the `docker` group can control docker, which is as good as root.
|
|
125
|
+
- **Windows:** installs Docker Desktop with winget, with its license accepted and its WSL 2 engine, and starts it. Windows asks for permission, and may want a restart. Docker Desktop may also ask to install or update WSL: do what it asks, then try again. If Docker Desktop is set to Windows containers, switch it to Linux containers (right-click its icon by the clock).
|
|
126
|
+
|
|
127
|
+
Steps that need root ask for your password in the dialog. WindScout checks it with `sudo` once, so a typo counts as one failed try. It keeps the password in memory until the steps are done and never saves it. Docker Desktop is free for personal use, education and small businesses; bigger companies need a [paid plan](https://www.docker.com/pricing/).
|
|
128
|
+
|
|
129
|
+
Then the first parallel scan builds a local image, `windscout-worker`, with Node and Windscribe's Linux CLI app (the latest stable release on [GitHub](https://github.com/Windscribe/Desktop-App/releases)). That takes a few minutes. Later scans reuse it until WindScout updates.
|
|
130
|
+
|
|
131
|
+
**In Iran (and other places docker.com refuses):** Docker Hub and docker.com refuse Iranian addresses (US sanctions), so every download falls back to mirrors in Iran when the official source refuses or doesn't answer. Everywhere else, the official sources are used as before:
|
|
132
|
+
|
|
133
|
+
- **The image's base** (`node:22-bookworm-slim`) comes from Docker Hub, else from the first mirror of it that answers: `registry.docker.ir`, `docker.iranserver.com`, `docker.kernel.ir`, `mirror2.chabokan.net`, `docker-mirror.liara.ir`, `hub.hamdocker.ir`, `docker.arvancloud.ir`, `focker.ir`, `docker.mobinhost.com`, `mirror-docker.runflare.com`. It's pinned by digest, so a mirror can only hand over that exact image. To try other mirrors first, list them in `WINDSCOUT_REGISTRY_MIRRORS` (comma-separated hosts).
|
|
134
|
+
- **Debian's packages** in the image come from deb.debian.org, else `mirror.shatel.ir`, `mirror.iranserver.com`, `mirror.mobinhost.com` or `mirror2.chabokan.net`. apt checks Debian's signatures, whichever mirror serves them.
|
|
135
|
+
- **Windscribe's app** in the image comes from GitHub, which Iran can reach.
|
|
136
|
+
- **Docker on Linux:** where get.docker.com refuses, your distribution's own docker package is installed instead, from the mirrors your system already uses.
|
|
137
|
+
- **Docker Desktop on macOS and Windows** has no mirror anywhere: when docker.com refuses the download, the dialog says so. Connect a VPN (Windscribe will do), then press Retry. That's needed once, for the install.
|
|
138
|
+
|
|
139
|
+
The mirrors come from [Mirava](https://github.com/MiravaOrg/Mirava)'s list of mirrors in Iran; they come and go, and that's where to look for new ones.
|
|
140
|
+
|
|
141
|
+
**Kernel check:** each container first checks that docker's Linux kernel gives it what Windscribe needs: a tunnel device (tun) and a firewall (nftables). If not, the scan stops and says so, rather than showing every location as blocked. Windscribe's WireGuard also needs nftables' `fib` in its firewall table, which Docker Desktop's own Linux VM lacks (on macOS, and on Windows without WSL 2). There, WireGuard runs on this computer instead (see below).
|
|
142
|
+
|
|
143
|
+
**Login:** each container's Windscribe app logs in once. WindScout asks for your Windscribe username and password (and a 2FA code or captcha when Windscribe asks for one) and passes them to the containers, one at a time. Each login is kept in that container's docker volume (`windscout-1`, `windscout-2`, …), so later scans don't ask.
|
|
144
|
+
|
|
145
|
+
**Remember username and password** is ticked to start with (tab to it and press space, or click it). Once the login works, WindScout saves both in `~/.config/windscout/login.json`, as plain text that only you can read. Then containers that are new next time (a scan with more attempts) log in by themselves, with no terminal too; a 2FA code is never saved, so with 2FA they still ask. Untick it and nothing is saved, and a login saved before is forgotten. Deleting that file forgets it too. With `-c` and no terminal, only containers that are logged in already, or can log in with the remembered login, take part.
|
|
146
|
+
|
|
147
|
+
**Measuring:** the containers share your internet connection, so they take turns measuring latency and speed while the connecting happens in parallel. Numbers stay comparable with a normal scan. Most of the time saved comes from attempts that hang until the timeout, which overlap now.
|
|
148
|
+
|
|
149
|
+
**Differences from a normal scan:**
|
|
150
|
+
|
|
151
|
+
- IKEv2, and WireGuard when the kernel check finds it can't run in the containers, are tried on this computer once the containers are done, one at a time like a normal scan. The scan screen shows them on a line of their own (`this computer`), and the picker's estimate counts them. Windscribe's Linux app has no IKEv2.
|
|
152
|
+
- This computer's own Windscribe connection is disconnected at the start and stays off while the containers scan, since it would carry their traffic too.
|
|
153
|
+
- No firewall: "block internet while scanning" isn't used, since it would block the containers' traffic too.
|
|
154
|
+
|
|
155
|
+
The containers are removed after the scan. To remove the logins too, run `docker volume rm windscout-1 windscout-2 …`. To remove the image, run `docker rmi windscout-worker`.
|
|
156
|
+
|
|
110
157
|
## Output
|
|
111
158
|
|
|
112
159
|
While scanning:
|
|
@@ -142,7 +189,7 @@ At the end, the results, a per-protocol summary and the best pick are printed to
|
|
|
142
189
|
- **The country list is built in.** On v2.24, `windscribe-cli locations` returns nothing, so WindScout uses a fixed list of country codes. Codes Windscribe doesn't serve are skipped quickly.
|
|
143
190
|
- **A full scan takes a while.** The worst case is countries × protocols × timeout. Narrow it with `-c` and `-p`.
|
|
144
191
|
- **No flags in macOS Terminal.** Terminal.app draws flag emoji wider than their space, which pushes table borders out of line, so WindScout leaves them out there (as on Windows). iTerm2 and other terminals show them.
|
|
145
|
-
- **Your connection changes during the scan.** WindScout connects and disconnects the VPN repeatedly, so don't run it while you need a stable connection.
|
|
192
|
+
- **Your connection changes during the scan.** WindScout connects and disconnects the VPN repeatedly, so don't run it while you need a stable connection. A [parallel scan](#parallel-scan-with-docker) does that inside its containers instead, and your computer's own VPN stays off.
|
|
146
193
|
|
|
147
194
|
## Development
|
|
148
195
|
|
|
@@ -151,6 +198,7 @@ The source is TypeScript in `src/`. It compiles to `dist/`, which is what gets p
|
|
|
151
198
|
```sh
|
|
152
199
|
npm install
|
|
153
200
|
npm run build # compile src/ to dist/ (the windscout command is dist/cli.js)
|
|
201
|
+
npm test # build, then check the scan's scheduling (no VPN, no docker)
|
|
154
202
|
node dist/cli.js # run your build; takes the same options as windscout
|
|
155
203
|
./publish.sh # build, install the packed tarball to check it runs, publish to npm (bump the version first)
|
|
156
204
|
```
|
package/dist/cli.js
CHANGED
|
@@ -5,8 +5,11 @@
|
|
|
5
5
|
import { createInterface } from "node:readline";
|
|
6
6
|
import { spawnSync } from "node:child_process";
|
|
7
7
|
import { parseArgs } from "node:util";
|
|
8
|
-
import { CONFIG, DEFAULT_TIMEOUT, loadConfig, MIN_TIMEOUT } from "./config.js";
|
|
8
|
+
import { CONFIG, DEFAULT_TIMEOUT, loadConfig, loadDockerWireGuard, MIN_TIMEOUT, saveDockerWireGuard } from "./config.js";
|
|
9
|
+
import { notInContainers, stopWorkers } from "./docker.js";
|
|
10
|
+
import { probe } from "./probe.js";
|
|
9
11
|
import { Scan } from "./scan.js";
|
|
12
|
+
import { startParallel } from "./tui/docker.js";
|
|
10
13
|
import { pick } from "./tui/picker.js";
|
|
11
14
|
import { logProgress, showProgress } from "./tui/progress.js";
|
|
12
15
|
import { command, report, target } from "./tui/report.js";
|
|
@@ -15,6 +18,7 @@ import { cyan, green, yellow } from "./tui/text.js";
|
|
|
15
18
|
import { now, sleep } from "./time.js";
|
|
16
19
|
import { canUpdate, checkUpdate, runUpdate, updateNotice, versionLines } from "./update.js";
|
|
17
20
|
import { blockInternet, CLI, connectState, isFirewallOn, PROTOCOLS, restoreFirewall, waitForLogin, windscribe } from "./windscribe.js";
|
|
21
|
+
import { worker } from "./worker.js";
|
|
18
22
|
const HELP = `Usage: windscout [options]
|
|
19
23
|
|
|
20
24
|
Find which Windscribe locations and protocols work from your network, ranked by speed.
|
|
@@ -27,6 +31,8 @@ Options:
|
|
|
27
31
|
-a, --all also show failed attempts in the final table
|
|
28
32
|
-n, --no-speed connect-only: skip the download test, rank by latency (faster scan)
|
|
29
33
|
-f, --firewall block internet while scanning, except through the VPN (turned back off afterwards)
|
|
34
|
+
-r, --random scan the countries in a random order
|
|
35
|
+
-d, --docker scan in parallel, in docker containers (as many as docker's CPUs and memory allow, up to 8)
|
|
30
36
|
-v, --version show the installed version (and offer to update if a newer one is out)
|
|
31
37
|
-h, --help show this help
|
|
32
38
|
|
|
@@ -36,18 +42,18 @@ Example: windscout -c DE,NL,TR -p stealth,tcp:443`;
|
|
|
36
42
|
const list = (s) => s.split(",").map((x) => x.trim()).filter(Boolean);
|
|
37
43
|
const ask = (question) => new Promise((resolve) => {
|
|
38
44
|
const rl = createInterface({ input: process.stdin, output: out });
|
|
39
|
-
rl.on("SIGINT", () => rl.close()); // Ctrl-C / Ctrl-D:
|
|
40
|
-
rl.on("close", () => resolve(
|
|
45
|
+
rl.on("SIGINT", () => rl.close()); // Ctrl-C / Ctrl-D: no answer, null
|
|
46
|
+
rl.on("close", () => resolve(null));
|
|
41
47
|
rl.question(question, (a) => (resolve(a.trim()), rl.close()));
|
|
42
48
|
});
|
|
43
|
-
/** Asks which numbered connection to make, then runs its command and waits for it to connect */
|
|
49
|
+
/** Asks which numbered connection to make (enter: the best), then runs its command and waits for it to connect */
|
|
44
50
|
async function offerConnect(choices, timeout) {
|
|
45
|
-
const others = choices.length >
|
|
51
|
+
const others = choices.length > 2 ? `, 1-${choices.length - 1} = other` : choices.length > 1 ? ", 1 = other" : "";
|
|
46
52
|
for (;;) {
|
|
47
|
-
const a = await ask(`\nconnect to # (0 = best${others},
|
|
48
|
-
if (
|
|
53
|
+
const a = await ask(`\nconnect to # (enter or 0 = best${others}, q = quit): `);
|
|
54
|
+
if (a === null || /^q(uit)?$/i.test(a))
|
|
49
55
|
return;
|
|
50
|
-
const r = /^\d+$/.test(a) ? choices[Number(a)] : undefined;
|
|
56
|
+
const r = a === "" ? choices[0] : /^\d+$/.test(a) ? choices[Number(a)] : undefined;
|
|
51
57
|
if (!r) {
|
|
52
58
|
console.log(yellow(`no #${a} in the tables`));
|
|
53
59
|
continue;
|
|
@@ -83,15 +89,22 @@ async function main() {
|
|
|
83
89
|
version: { type: "boolean", short: "v", default: false },
|
|
84
90
|
"no-speed": { type: "boolean", short: "n", default: false },
|
|
85
91
|
firewall: { type: "boolean", short: "f", default: false },
|
|
92
|
+
random: { type: "boolean", short: "r", default: false },
|
|
93
|
+
docker: { type: "boolean", short: "d", default: false },
|
|
94
|
+
worker: { type: "boolean", default: false }, // in a parallel scan's container
|
|
86
95
|
},
|
|
87
96
|
});
|
|
97
|
+
if (a.worker) {
|
|
98
|
+
await worker();
|
|
99
|
+
process.exit(); // its stdin may still be open: it has no login to scan with
|
|
100
|
+
}
|
|
88
101
|
if (a.help)
|
|
89
102
|
return console.log(HELP);
|
|
90
103
|
checkUpdate(); // runs while the app starts and the user picks, before the VPN starts switching
|
|
91
104
|
if (a.version) {
|
|
92
105
|
await checkUpdate();
|
|
93
106
|
console.log(versionLines().join("\n"));
|
|
94
|
-
if (canUpdate() && process.stdin.isTTY && out.isTTY && /^y(es)?$/i.test(await ask("update now? (y/n) ")))
|
|
107
|
+
if (canUpdate() && process.stdin.isTTY && out.isTTY && /^y(es)?$/i.test((await ask("update now? (y/n) ")) ?? ""))
|
|
95
108
|
process.exitCode = runUpdate();
|
|
96
109
|
return;
|
|
97
110
|
}
|
|
@@ -104,6 +117,8 @@ async function main() {
|
|
|
104
117
|
let protocols = a.protocols ? list(a.protocols) : undefined;
|
|
105
118
|
let speedTest = !a["no-speed"];
|
|
106
119
|
let firewall = a.firewall;
|
|
120
|
+
let random = a.random;
|
|
121
|
+
let docker = a.docker;
|
|
107
122
|
if (!countries) {
|
|
108
123
|
if (!tty)
|
|
109
124
|
throw new Error("no terminal for the picker: pass countries with -c");
|
|
@@ -115,6 +130,8 @@ async function main() {
|
|
|
115
130
|
speedTest: speedTest && (saved?.speed ?? false), // first run: connect-only
|
|
116
131
|
// already on in the app: show it on, since the scan won't turn it off
|
|
117
132
|
firewall: firewall || isFirewallOn(status) || (saved?.firewall ?? false),
|
|
133
|
+
random: random || (saved?.random ?? false),
|
|
134
|
+
docker: docker || (saved?.docker ?? false),
|
|
118
135
|
});
|
|
119
136
|
if (!choice)
|
|
120
137
|
return;
|
|
@@ -124,16 +141,37 @@ async function main() {
|
|
|
124
141
|
protocols ??= choice.protocols;
|
|
125
142
|
speedTest = choice.speed;
|
|
126
143
|
firewall = choice.firewall;
|
|
144
|
+
random = choice.random;
|
|
127
145
|
timeout = choice.timeout;
|
|
146
|
+
docker = choice.docker;
|
|
128
147
|
}
|
|
129
148
|
protocols ??= PROTOCOLS;
|
|
130
149
|
timeout ??= DEFAULT_TIMEOUT;
|
|
131
|
-
|
|
132
|
-
|
|
150
|
+
if (random)
|
|
151
|
+
countries = countries.map((c) => [Math.random(), c]).sort(([x], [y]) => x - y).map(([, c]) => c);
|
|
152
|
+
let probers = [probe], after; // after: what runs here once the containers are done
|
|
153
|
+
const later = notInContainers(protocols, loadDockerWireGuard()); // as far as the last parallel scan knows
|
|
154
|
+
const inContainers = countries.length * protocols.filter((p) => !later.has(p)).length;
|
|
155
|
+
if (docker && inContainers) {
|
|
156
|
+
const started = await startParallel(inContainers);
|
|
157
|
+
if (!started)
|
|
158
|
+
return leaveScreen();
|
|
159
|
+
saveDockerWireGuard(started.wireguard);
|
|
160
|
+
probers = started.probers;
|
|
161
|
+
after = { prober: probe, protocols: notInContainers(protocols, started.wireguard), name: "this computer" };
|
|
162
|
+
await windscribe("disconnect"); // a VPN connection here would carry the containers' traffic too
|
|
163
|
+
}
|
|
164
|
+
const scan = new Scan(countries, protocols, { timeout, speedTest }, probers, after);
|
|
165
|
+
// not with containers: their traffic goes out through this computer, and the firewall would block it
|
|
166
|
+
const blocking = firewall && !after && (await blockInternet());
|
|
133
167
|
const view = tty ? showProgress(scan, blocking) : logProgress(scan);
|
|
134
168
|
await scan.run(view);
|
|
169
|
+
if (after)
|
|
170
|
+
await stopWorkers();
|
|
135
171
|
await restoreFirewall();
|
|
136
172
|
view.close();
|
|
173
|
+
for (const e of new Set(scan.errors))
|
|
174
|
+
console.error(yellow(e));
|
|
137
175
|
if (scan.stopping)
|
|
138
176
|
console.log(yellow("interrupted, showing partial results"));
|
|
139
177
|
const choices = report(scan.results, protocols, { all: a.all, speedTest });
|
package/dist/config.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
// The picker's selection, remembered between runs.
|
|
2
|
-
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
1
|
+
// The picker's selection, and the docker containers' Windscribe login if wanted, remembered between runs.
|
|
2
|
+
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { dirname, join } from "node:path";
|
|
5
5
|
import { COUNTRIES, PROTOCOLS } from "./windscribe.js";
|
|
6
6
|
export const DEFAULT_TIMEOUT = 15;
|
|
7
7
|
export const MIN_TIMEOUT = 10; // seconds; shorter cuts off connections that would have worked
|
|
8
8
|
export const CONFIG = join(process.env.XDG_CONFIG_HOME || join(homedir(), ".config"), "windscout", "config.json");
|
|
9
|
+
// ponytail: plain text that only this user can read, like git's credential store; the OS keychain if that's not enough
|
|
10
|
+
export const LOGIN_FILE = join(dirname(CONFIG), "login.json");
|
|
11
|
+
const DOCKER_FILE = join(dirname(CONFIG), "docker.json"); // what the last parallel scan found its containers can do
|
|
9
12
|
/** The saved choice, minus anything this version doesn't offer; null on first run or an unreadable file */
|
|
10
13
|
export function loadConfig() {
|
|
11
14
|
try {
|
|
@@ -15,7 +18,9 @@ export function loadConfig() {
|
|
|
15
18
|
protocols: (c.protocols ?? []).filter((x) => PROTOCOLS.includes(x)),
|
|
16
19
|
speed: c.speed !== false,
|
|
17
20
|
firewall: c.firewall === true,
|
|
21
|
+
random: c.random === true,
|
|
18
22
|
timeout: c.timeout >= MIN_TIMEOUT ? c.timeout : DEFAULT_TIMEOUT,
|
|
23
|
+
docker: c.docker === true,
|
|
19
24
|
};
|
|
20
25
|
}
|
|
21
26
|
catch {
|
|
@@ -29,3 +34,40 @@ export function saveConfig(c) {
|
|
|
29
34
|
}
|
|
30
35
|
catch { } // not being able to remember isn't worth failing the scan
|
|
31
36
|
}
|
|
37
|
+
/** Whether WireGuard worked in the docker containers last time (yes until a scan finds otherwise), for the picker's estimate */
|
|
38
|
+
export function loadDockerWireGuard() {
|
|
39
|
+
try {
|
|
40
|
+
return JSON.parse(readFileSync(DOCKER_FILE, "utf8")).wireguard !== false;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export function saveDockerWireGuard(wireguard) {
|
|
47
|
+
try {
|
|
48
|
+
mkdirSync(dirname(DOCKER_FILE), { recursive: true });
|
|
49
|
+
writeFileSync(DOCKER_FILE, JSON.stringify({ wireguard }) + "\n");
|
|
50
|
+
}
|
|
51
|
+
catch { } // not being able to remember isn't worth failing the scan
|
|
52
|
+
}
|
|
53
|
+
/** The Windscribe login remembered for the docker containers; null when there's none */
|
|
54
|
+
export function loadLogin() {
|
|
55
|
+
try {
|
|
56
|
+
const { username, password } = JSON.parse(readFileSync(LOGIN_FILE, "utf8"));
|
|
57
|
+
return typeof username === "string" && typeof password === "string" ? { username, password } : null;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/** Remembers the login, or forgets it (null) */
|
|
64
|
+
export function saveLogin(c) {
|
|
65
|
+
try {
|
|
66
|
+
rmSync(LOGIN_FILE, { force: true }); // a new file gets the mode below; an old one would keep its own
|
|
67
|
+
if (!c)
|
|
68
|
+
return;
|
|
69
|
+
mkdirSync(dirname(LOGIN_FILE), { recursive: true });
|
|
70
|
+
writeFileSync(LOGIN_FILE, JSON.stringify(c) + "\n", { mode: 0o600 });
|
|
71
|
+
}
|
|
72
|
+
catch { } // not being able to remember isn't worth failing the scan
|
|
73
|
+
}
|