polaris-vpn 1.1.1 → 1.1.2

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/CHANGELOG.md CHANGED
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.1.2] - 2026-07-22
9
+
10
+ ### Fixed
11
+
12
+ - **Start Command**: Fixed `ReferenceError: config is not defined` crash when invoking `polaris start` without `--server` argument.
13
+ - **WireGuard & AmneziaWG Status**: Fixed `polaris status` and `polaris check` reporting false proxy failures for system-wide VPN interfaces.
14
+ - **AmneziaWG Bandwidth Monitoring**: Updated `polaris monitor`, `dashboard`, `status`, and TUI components to query `awg` interface statistics and accept `--mode amneziawg`.
15
+ - **Deploy Local Auto-Connect**: Updated `polaris deploy` to automatically trigger local connection passing correct server and mode arguments upon provisioning completion.
16
+ - **Status Table Formatting**: Replaced invalid SOCKS5 proxy port display (`socks5://127.0.0.1:0`) with clear `System-wide (All OS traffic)` label for WireGuard and AmneziaWG connections.
17
+
8
18
  ## [1.0.0] - 2026-07-15
9
19
 
10
20
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polaris-vpn",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "Your True North in Digital Privacy. A self-hosted VPN CLI.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -22,12 +22,13 @@ export default async (options) => {
22
22
  if (spinner) spinner.text = 'Checking IP address...';
23
23
  if (info) {
24
24
  try {
25
- const tunnelIp = await getProxiedIp(info.port);
25
+ const isSystemWide = info.mode === 'wireguard' || info.mode === 'amneziawg';
26
+ const tunnelIp = isSystemWide ? await getPublicIp() : await getProxiedIp(info.port);
26
27
  results.ip = true;
27
28
  details.ip = `Tunnel active (${(info.mode || 'ssh').toUpperCase()}): ${tunnelIp}`;
28
29
  } catch (e) {
29
30
  results.ip = false;
30
- details.ip = `Tunnel process running but proxy failed: ${e.message}`;
31
+ details.ip = `Tunnel active but IP check failed: ${e.message}`;
31
32
  }
32
33
  } else {
33
34
  const pubIp = await getPublicIp();
@@ -1,7 +1,7 @@
1
1
  import blessed from 'blessed';
2
2
  import contrib from 'blessed-contrib';
3
3
  import { getActiveTunnel } from '../core/tunnel-service.js';
4
- import { getProxiedIp } from '../net/ip-check.js';
4
+ import { getProxiedIp, getPublicIp } from '../net/ip-check.js';
5
5
  import fetch from 'node-fetch';
6
6
  import { spawnSync } from 'child_process';
7
7
  import os from 'os';
@@ -67,8 +67,12 @@ const formatBytes = (bytes) => {
67
67
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
68
68
  };
69
69
 
70
- const getWgStats = () => {
71
- const dumpRes = spawnSync('sudo', ['wg', 'show', 'all', 'dump'], { encoding: 'utf-8' });
70
+ const getWgStats = (isAwg = false) => {
71
+ const cmd = isAwg ? 'awg' : 'wg';
72
+ let dumpRes = spawnSync('sudo', [cmd, 'show', 'all', 'dump'], { encoding: 'utf-8' });
73
+ if (dumpRes.status !== 0 && isAwg) {
74
+ dumpRes = spawnSync('sudo', ['wg', 'show', 'all', 'dump'], { encoding: 'utf-8' });
75
+ }
72
76
  if (dumpRes.status !== 0) return null;
73
77
  const lines = dumpRes.stdout.trim().split('\n');
74
78
  if (lines.length <= 1) return null;
@@ -201,7 +205,8 @@ export default async () => {
201
205
  if (!geoFetched) {
202
206
  geoFetched = true;
203
207
  try {
204
- currentIp = await getProxiedIp(info.port);
208
+ const isSystemWide = info.mode === 'wireguard' || info.mode === 'amneziawg';
209
+ currentIp = isSystemWide ? await getPublicIp() : await getProxiedIp(info.port);
205
210
  geoData = await getGeoIp(currentIp);
206
211
  if (geoData) {
207
212
  mapWidget.addMarker({ lat: geoData.lat, lon: geoData.lon, color: 'red', char: 'X' });
@@ -227,7 +232,7 @@ export default async () => {
227
232
 
228
233
  // 4. Update WG Stats & Chart
229
234
  if (info.mode === 'wireguard' || info.mode === 'amneziawg' || info.mode === 'auto') {
230
- const stats = getWgStats();
235
+ const stats = getWgStats(info.mode === 'amneziawg');
231
236
  if (stats) {
232
237
  if (!hasInitWg) {
233
238
  prevRx = stats.totalRx;
@@ -36,7 +36,8 @@ export default async (options) => {
36
36
  }
37
37
 
38
38
  // Automatically trigger local connection
39
- await startCommand({ mode: 'wireguard', json: isJson });
39
+ const mode = options.mode || 'wireguard';
40
+ await startCommand({ server, mode, json: isJson });
40
41
 
41
42
  } catch (err) {
42
43
  if (spinner) spinner.fail('Deployment failed');
@@ -49,7 +49,7 @@ export default async (options) => {
49
49
  const isJson = options.json;
50
50
  const info = getActiveTunnel();
51
51
 
52
- if (!info || info.mode !== 'wireguard') {
52
+ if (!info || (info.mode !== 'wireguard' && info.mode !== 'amneziawg')) {
53
53
  if (isJson) {
54
54
  console.log(JSON.stringify({ error: 'WireGuard tunnel is not active' }));
55
55
  } else {
@@ -51,8 +51,7 @@ export default async (options) => {
51
51
  const requestedMode = options.mode || 'auto';
52
52
 
53
53
  if (!server) {
54
- const active = config.get('activeProfile');
55
- const profiles = config.get('profiles') || {};
54
+ const { profiles, active } = getProfiles();
56
55
 
57
56
  if (active && profiles[active]) {
58
57
  server = profiles[active];
@@ -1,5 +1,5 @@
1
1
  import { getActiveTunnel } from '../core/tunnel-service.js';
2
- import { getProxiedIp } from '../net/ip-check.js';
2
+ import { getProxiedIp, getPublicIp } from '../net/ip-check.js';
3
3
  import { createTable, createSpinner, printError } from '../utils/display.js';
4
4
  import chalk from 'chalk';
5
5
  import fetch from 'node-fetch';
@@ -41,8 +41,12 @@ const formatBytes = (bytes) => {
41
41
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
42
42
  };
43
43
 
44
- const getWgStats = () => {
45
- const dumpRes = spawnSync('sudo', ['wg', 'show', 'all', 'dump'], { encoding: 'utf-8' });
44
+ const getWgStats = (isAwg = false) => {
45
+ const cmd = isAwg ? 'awg' : 'wg';
46
+ let dumpRes = spawnSync('sudo', [cmd, 'show', 'all', 'dump'], { encoding: 'utf-8' });
47
+ if (dumpRes.status !== 0 && isAwg) {
48
+ dumpRes = spawnSync('sudo', ['wg', 'show', 'all', 'dump'], { encoding: 'utf-8' });
49
+ }
46
50
  if (dumpRes.status !== 0) return null;
47
51
  const lines = dumpRes.stdout.trim().split('\n');
48
52
  if (lines.length <= 1) return null;
@@ -72,10 +76,11 @@ export default async (options) => {
72
76
  }
73
77
 
74
78
  let currentIp = 'Unknown';
75
- const spinner = isJson ? null : createSpinner('Checking proxy status...').start();
79
+ const isSystemWide = info.mode === 'wireguard' || info.mode === 'amneziawg';
80
+ const spinner = isJson ? null : createSpinner(isSystemWide ? 'Checking public IP...' : 'Checking proxy status...').start();
76
81
 
77
82
  try {
78
- currentIp = await getProxiedIp(info.port);
83
+ currentIp = isSystemWide ? await getPublicIp() : await getProxiedIp(info.port);
79
84
  if (spinner) spinner.stop();
80
85
 
81
86
  let geo = 'N/A';
@@ -92,8 +97,8 @@ export default async (options) => {
92
97
  latency = pingServer(serverIp);
93
98
  geo = await getGeoIp(currentIp);
94
99
 
95
- if (info.mode === 'wireguard') {
96
- const stats = getWgStats();
100
+ if (isSystemWide) {
101
+ const stats = getWgStats(info.mode === 'amneziawg');
97
102
  if (stats) {
98
103
  dataUsage = `${formatBytes(stats.totalRx)} / ${formatBytes(stats.totalTx)}`;
99
104
  }
@@ -128,8 +133,16 @@ export default async (options) => {
128
133
  table.push(
129
134
  ['Status', chalk.green('Connected')],
130
135
  ['Mode', (info.mode || 'ssh').toUpperCase()],
131
- ['Server', info.server],
132
- ['Proxy', `socks5://127.0.0.1:${info.port}`],
136
+ ['Server', info.server]
137
+ );
138
+
139
+ if (isSystemWide) {
140
+ table.push(['Connection', chalk.cyan('System-wide (All OS traffic)')]);
141
+ } else {
142
+ table.push(['Proxy', `socks5://127.0.0.1:${info.port}`]);
143
+ }
144
+
145
+ table.push(
133
146
  ['Current IP', chalk.cyan(currentIp)],
134
147
  ['Uptime', `${uptimeMin} minutes`],
135
148
  ['PID', info.pid.toString()]
@@ -87,8 +87,12 @@ const fmtBytes = (n) => {
87
87
  return `${(n / Math.pow(k, i)).toFixed(1)} ${s[i]}`;
88
88
  };
89
89
 
90
- const wgStats = () => {
91
- const r = spawnSync('sudo', ['wg', 'show', 'all', 'dump'], { encoding: 'utf-8' });
90
+ const wgStats = (isAwg = false) => {
91
+ const cmd = isAwg ? 'awg' : 'wg';
92
+ let r = spawnSync('sudo', [cmd, 'show', 'all', 'dump'], { encoding: 'utf-8' });
93
+ if (r.status !== 0 && isAwg) {
94
+ r = spawnSync('sudo', ['wg', 'show', 'all', 'dump'], { encoding: 'utf-8' });
95
+ }
92
96
  if (r.status !== 0) return null;
93
97
  const lines = r.stdout.trim().split('\n');
94
98
  if (lines.length <= 1) return null;
@@ -293,7 +297,7 @@ export default async () => {
293
297
  if (info) {
294
298
  const upMin = Math.floor((Date.now() - new Date(info.startTime).getTime()) / 60000);
295
299
  const ping = pingServer(info.server.split('@').pop());
296
- const wg = wgStats();
300
+ const wg = wgStats(info.mode === 'amneziawg');
297
301
  L.push(`${t(D.accent, b('◈ Tunnel Status'))} ${t(D.success, '⬤ ACTIVE')}`);
298
302
  L.push(hr()); L.push('');
299
303
  L.push(` ${mu('Server ')} ${b(info.server)}`);
@@ -391,7 +395,13 @@ export default async () => {
391
395
  const renderPeers = () => {
392
396
  const L = [];
393
397
  L.push(`${t(D.accent, b('≡ WireGuard Peers'))}`); L.push(hr()); L.push('');
394
- const r = spawnSync('sudo', ['wg', 'show', 'all', 'dump'], { encoding: 'utf-8' });
398
+ const info = getActiveTunnel();
399
+ const isAwg = info && info.mode === 'amneziawg';
400
+ const cmd = isAwg ? 'awg' : 'wg';
401
+ let r = spawnSync('sudo', [cmd, 'show', 'all', 'dump'], { encoding: 'utf-8' });
402
+ if (r.status !== 0 && isAwg) {
403
+ r = spawnSync('sudo', ['wg', 'show', 'all', 'dump'], { encoding: 'utf-8' });
404
+ }
395
405
  if (r.status !== 0 || !r.stdout.trim()) {
396
406
  L.push(` ${t(D.warning, '⚠')} No WireGuard interface found.`);
397
407
  L.push(` ${mu('Start a WireGuard tunnel first.')}`);