windscout 0.5.7 → 0.5.8

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 CHANGED
@@ -52,6 +52,7 @@ Run `windscout` with no arguments to open the interactive picker:
52
52
  | `1`–`6` | toggle a protocol (`1`–`5` on Linux, which has no IKEv2) |
53
53
  | `s` | toggle the speed test (off = connect-only mode) |
54
54
  | `f` | toggle "block internet while scanning" (firewall) |
55
+ | `r` | toggle random order: scan the selected countries shuffled, a new order each run |
55
56
  | `u` | update to the newer version and restart (only when the picker shows one is out) |
56
57
  | `enter` | start scanning |
57
58
  | `q` | quit (during a scan: stop and show partial results; press again to force quit) |
@@ -80,6 +81,7 @@ windscout -t 40 -a # longer connect timeout, also list
80
81
  | `-a, --all` | include failed attempts in the final table | off |
81
82
  | `-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
83
  | `-f, --firewall` | block internet while scanning, except through the VPN | picker: saved, or off; with `-c`: off |
84
+ | `-r, --random` | scan the countries in a random order | picker: saved, or off; with `-c`: off |
83
85
  | `-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
86
 
85
87
  ## Connect-only mode
package/dist/cli.js CHANGED
@@ -27,6 +27,7 @@ Options:
27
27
  -a, --all also show failed attempts in the final table
28
28
  -n, --no-speed connect-only: skip the download test, rank by latency (faster scan)
29
29
  -f, --firewall block internet while scanning, except through the VPN (turned back off afterwards)
30
+ -r, --random scan the countries in a random order
30
31
  -v, --version show the installed version (and offer to update if a newer one is out)
31
32
  -h, --help show this help
32
33
 
@@ -83,6 +84,7 @@ async function main() {
83
84
  version: { type: "boolean", short: "v", default: false },
84
85
  "no-speed": { type: "boolean", short: "n", default: false },
85
86
  firewall: { type: "boolean", short: "f", default: false },
87
+ random: { type: "boolean", short: "r", default: false },
86
88
  },
87
89
  });
88
90
  if (a.help)
@@ -104,6 +106,7 @@ async function main() {
104
106
  let protocols = a.protocols ? list(a.protocols) : undefined;
105
107
  let speedTest = !a["no-speed"];
106
108
  let firewall = a.firewall;
109
+ let random = a.random;
107
110
  if (!countries) {
108
111
  if (!tty)
109
112
  throw new Error("no terminal for the picker: pass countries with -c");
@@ -115,6 +118,7 @@ async function main() {
115
118
  speedTest: speedTest && (saved?.speed ?? false), // first run: connect-only
116
119
  // already on in the app: show it on, since the scan won't turn it off
117
120
  firewall: firewall || isFirewallOn(status) || (saved?.firewall ?? false),
121
+ random: random || (saved?.random ?? false),
118
122
  });
119
123
  if (!choice)
120
124
  return;
@@ -124,10 +128,13 @@ async function main() {
124
128
  protocols ??= choice.protocols;
125
129
  speedTest = choice.speed;
126
130
  firewall = choice.firewall;
131
+ random = choice.random;
127
132
  timeout = choice.timeout;
128
133
  }
129
134
  protocols ??= PROTOCOLS;
130
135
  timeout ??= DEFAULT_TIMEOUT;
136
+ if (random)
137
+ countries = countries.map((c) => [Math.random(), c]).sort(([x], [y]) => x - y).map(([, c]) => c);
131
138
  const scan = new Scan(countries, protocols, { timeout, speedTest });
132
139
  const blocking = firewall && (await blockInternet());
133
140
  const view = tty ? showProgress(scan, blocking) : logProgress(scan);
package/dist/config.js CHANGED
@@ -15,6 +15,7 @@ export function loadConfig() {
15
15
  protocols: (c.protocols ?? []).filter((x) => PROTOCOLS.includes(x)),
16
16
  speed: c.speed !== false,
17
17
  firewall: c.firewall === true,
18
+ random: c.random === true,
18
19
  timeout: c.timeout >= MIN_TIMEOUT ? c.timeout : DEFAULT_TIMEOUT,
19
20
  };
20
21
  }
@@ -9,7 +9,7 @@ import { bold, cyan, dim, green, under, vw, yellow } from "./text.js";
9
9
  import { box, centerIn, grid } from "./widgets.js";
10
10
  const flip = (set, value) => (set.has(value) ? set.delete(value) : set.add(value));
11
11
  /** Resolves to the choice (also saved for next time), null when the user quits, or "update" for u */
12
- export function pick(saved, { timeout, speedTest, firewall }) {
12
+ export function pick(saved, { timeout, speedTest, firewall, random }) {
13
13
  const selected = new Set(saved?.countries ?? []);
14
14
  const protos = new Set(saved?.protocols.length ? saved.protocols : PROTOCOLS);
15
15
  let cursor = 0, top = 0, message = "", query = "", searching = false;
@@ -25,7 +25,7 @@ export function pick(saved, { timeout, speedTest, firewall }) {
25
25
  const rows = out.rows || 24;
26
26
  const version = versionLines(true);
27
27
  const matches = visible();
28
- const height = Math.max(3, rows - 21 - version.length);
28
+ const height = Math.max(3, rows - 22 - version.length);
29
29
  cursor = Math.max(0, Math.min(cursor, matches.length - 1));
30
30
  if (cursor < top)
31
31
  top = cursor;
@@ -40,6 +40,9 @@ export function pick(saved, { timeout, speedTest, firewall }) {
40
40
  const fwLine = `${dim(under("f"))} ${firewall ? green("● " + fwLabel) : dim("○ " + fwLabel)} ${dim(firewall
41
41
  ? "only VPN traffic gets through"
42
42
  : "off: apps may leak in between")}`;
43
+ const randomLine = `${dim(under("r"))} ${random ? green("● random order") : dim("○ random order")} ${dim(random
44
+ ? "scans the countries shuffled, a new order each run"
45
+ : "off: scans in list order")}`;
43
46
  timeout = Number(seconds);
44
47
  const short = timeout < MIN_TIMEOUT;
45
48
  const timeoutLine = `${dim(under("t"))} timeout ${editing ? bold(seconds) + cyan("▏") : (short ? yellow : bold)(seconds || "?")} s ${dim(`per connection · at least ${MIN_TIMEOUT}`)}`;
@@ -63,9 +66,9 @@ export function pick(saved, { timeout, speedTest, firewall }) {
63
66
  ["quit", under("Q") + "uit"],
64
67
  ];
65
68
  const buttonLine = buttons.map(([id, label]) => (id === "start" ? bold(cyan(`[ ${label} ]`)) : dim(`[ ${label} ]`))).join(" ");
66
- const table = grid([{ title: "" }, { title: "Code" }, { title: "Country" }], body, { caption: search, captionRight: dim(range), minWidth: Math.max(vw(protoLine), vw(speedLine), vw(fwLine), vw(timeoutLine)) + 4 });
69
+ const table = grid([{ title: "" }, { title: "Code" }, { title: "Country" }], body, { caption: search, captionRight: dim(range), minWidth: Math.max(vw(protoLine), vw(speedLine), vw(fwLine), vw(randomLine), vw(timeoutLine)) + 4 });
67
70
  const width = vw(table[0]);
68
- const head = box([protoLine, speedLine, fwLine, timeoutLine], {
71
+ const head = box([protoLine, speedLine, fwLine, randomLine, timeoutLine], {
69
72
  title: bold(cyan("WindScout")),
70
73
  right: `${bold(String(selected.size))}${dim(`/${COUNTRIES.length} selected`)}`,
71
74
  width: width - 4,
@@ -85,7 +88,7 @@ export function pick(saved, { timeout, speedTest, firewall }) {
85
88
  : searching
86
89
  ? "type to filter · ↑↓ move · enter/esc done"
87
90
  : `↑↓ move · space select · a/n ${query ? "all/none shown" : "all/none"} · / search`), width),
88
- centerIn(dim(searching || editing ? "" : `1-${PROTOCOLS.length} protocols · s speed test · f firewall · t timeout · enter start · ${query ? "esc clear · " : ""}q quit`), width),
91
+ centerIn(dim(searching || editing ? "" : `1-${PROTOCOLS.length} protocols · s speed test · f firewall · r random · t timeout · enter start · ${query ? "esc clear · " : ""}q quit`), width),
89
92
  ];
90
93
  if (message)
91
94
  lines.push(centerIn(yellow(message), width));
@@ -107,7 +110,7 @@ export function pick(saved, { timeout, speedTest, firewall }) {
107
110
  return range;
108
111
  });
109
112
  hit = {
110
- protoRow: at.top + 1, protoHits, speedRow: at.top + 2, firewallRow: at.top + 3, timeoutRow: at.top + 4,
113
+ protoRow: at.top + 1, protoHits, speedRow: at.top + 2, firewallRow: at.top + 3, randomRow: at.top + 4, timeoutRow: at.top + 5,
111
114
  searchRow: at.top + head.length + 1,
112
115
  firstRow: at.top + head.length + 5, shown: shown.length,
113
116
  buttonRow: at.top + head.length + table.length + 1, buttonHits,
@@ -139,6 +142,7 @@ export function pick(saved, { timeout, speedTest, firewall }) {
139
142
  protocols: PROTOCOLS.filter((p) => protos.has(p)),
140
143
  speed: speedTest,
141
144
  firewall,
145
+ random,
142
146
  timeout,
143
147
  };
144
148
  saveConfig(choice);
@@ -178,6 +182,8 @@ export function pick(saved, { timeout, speedTest, firewall }) {
178
182
  speedTest = !speedTest;
179
183
  else if (y === hit.firewallRow)
180
184
  firewall = !firewall;
185
+ else if (y === hit.randomRow)
186
+ random = !random;
181
187
  else if (y === hit.buttonRow) {
182
188
  const id = hit.buttonHits.find(([, a, b]) => x >= a && x < b)?.[0];
183
189
  if (id === "start" && start())
@@ -253,6 +259,8 @@ export function pick(saved, { timeout, speedTest, firewall }) {
253
259
  speedTest = !speedTest;
254
260
  else if (k === "f")
255
261
  firewall = !firewall;
262
+ else if (k === "r")
263
+ random = !random;
256
264
  else if (k === "t")
257
265
  editing = true, seconds = "";
258
266
  else if (k === "u" && canUpdate())
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "windscout",
3
- "version": "0.5.7",
3
+ "version": "0.5.8",
4
4
  "description": "Find which Windscribe locations and protocols work from your network, ranked by speed (unofficial)",
5
5
  "type": "module",
6
6
  "bin": {