bypass-vpn 1.0.1 → 1.2.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 +20 -2
- package/bin/bypass-vpn.js +55 -2
- package/package.json +1 -1
- package/src/config.js +35 -0
- package/src/resolver.js +27 -1
- package/src/services.js +8 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# bypass-vpn
|
|
2
2
|
|
|
3
|
-
Route AI service traffic (Claude, ChatGPT, Firebase, Google Auth) through your Wi-Fi gateway to bypass VPN routing.
|
|
3
|
+
Route AI and work service traffic (Claude, ChatGPT, Atlassian, Firebase, Google Auth) through your Wi-Fi gateway to bypass VPN routing.
|
|
4
4
|
|
|
5
5
|
Works on **macOS** and **Windows**. Zero dependencies.
|
|
6
6
|
|
|
@@ -23,7 +23,7 @@ npx bypass-vpn
|
|
|
23
23
|
## Usage
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
# Route all
|
|
26
|
+
# Route all services through Wi-Fi
|
|
27
27
|
sudo bypass-vpn
|
|
28
28
|
|
|
29
29
|
# Route specific services only
|
|
@@ -39,6 +39,23 @@ sudo bypass-vpn --dry-run
|
|
|
39
39
|
bypass-vpn --list
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
+
### Custom Domains
|
|
43
|
+
|
|
44
|
+
Save your own domains (e.g., your company's Jira instance) so they're automatically routed on every run:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# One-time setup
|
|
48
|
+
bypass-vpn --add-domain mycompany.atlassian.net
|
|
49
|
+
|
|
50
|
+
# Now just run normally — saved domains are included automatically
|
|
51
|
+
sudo bypass-vpn
|
|
52
|
+
|
|
53
|
+
# Remove a saved domain
|
|
54
|
+
bypass-vpn --remove-domain mycompany.atlassian.net
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Custom domains are persisted in `~/.bypass-vpn.json`.
|
|
58
|
+
|
|
42
59
|
## Supported Services
|
|
43
60
|
|
|
44
61
|
| Service | Domains |
|
|
@@ -47,6 +64,7 @@ bypass-vpn --list
|
|
|
47
64
|
| ChatGPT | chatgpt.com, chat.openai.com, api.openai.com, + 5 more |
|
|
48
65
|
| Firebase | firestore.googleapis.com, securetoken.googleapis.com, + 3 more |
|
|
49
66
|
| Google Auth | accounts.google.com, oauth2.googleapis.com, + 2 more |
|
|
67
|
+
| Atlassian | api.atlassian.com, auth.atlassian.com, id.atlassian.com |
|
|
50
68
|
|
|
51
69
|
Run `bypass-vpn --list` for the full domain list.
|
|
52
70
|
|
package/bin/bypass-vpn.js
CHANGED
|
@@ -6,6 +6,7 @@ const { detect } = require('../src/gateway');
|
|
|
6
6
|
const { resolveAll } = require('../src/resolver');
|
|
7
7
|
const { addRoute, removeRoute } = require('../src/router');
|
|
8
8
|
const services = require('../src/services');
|
|
9
|
+
const { loadConfig, addDomain, removeDomain } = require('../src/config');
|
|
9
10
|
const { version } = require('../package.json');
|
|
10
11
|
|
|
11
12
|
// ── Arg parsing ────────────────────────────────────────────────
|
|
@@ -18,12 +19,20 @@ const flags = {
|
|
|
18
19
|
dryRun: args.includes('--dry-run'),
|
|
19
20
|
list: args.includes('--list'),
|
|
20
21
|
services: [],
|
|
22
|
+
addDomain: null,
|
|
23
|
+
removeDomain: null,
|
|
21
24
|
};
|
|
22
25
|
|
|
23
26
|
for (let i = 0; i < args.length; i++) {
|
|
24
27
|
if (args[i] === '--service' && args[i + 1]) {
|
|
25
28
|
flags.services.push(args[i + 1].toLowerCase());
|
|
26
29
|
i++;
|
|
30
|
+
} else if (args[i] === '--add-domain' && args[i + 1]) {
|
|
31
|
+
flags.addDomain = args[i + 1];
|
|
32
|
+
i++;
|
|
33
|
+
} else if (args[i] === '--remove-domain' && args[i + 1]) {
|
|
34
|
+
flags.removeDomain = args[i + 1];
|
|
35
|
+
i++;
|
|
27
36
|
}
|
|
28
37
|
}
|
|
29
38
|
|
|
@@ -41,6 +50,8 @@ if (flags.help) {
|
|
|
41
50
|
bypass-vpn ${c.dim('--dry-run')} Show commands without executing
|
|
42
51
|
bypass-vpn ${c.dim('--service claude')} Route specific service(s) only
|
|
43
52
|
bypass-vpn ${c.dim('--list')} List available services
|
|
53
|
+
bypass-vpn ${c.dim('--add-domain')} h Save a custom domain for routing
|
|
54
|
+
bypass-vpn ${c.dim('--remove-domain')} h Remove a saved custom domain
|
|
44
55
|
|
|
45
56
|
${c.bold('Flags:')}
|
|
46
57
|
-h, --help Show this help
|
|
@@ -49,12 +60,16 @@ if (flags.help) {
|
|
|
49
60
|
--dry-run Print route commands without executing
|
|
50
61
|
--service <name> Route only specified service (repeatable)
|
|
51
62
|
--list List services and their domains
|
|
63
|
+
--add-domain <host> Save a custom domain (persisted in ~/.bypass-vpn.json)
|
|
64
|
+
--remove-domain <h> Remove a saved custom domain
|
|
52
65
|
|
|
53
|
-
${c.bold('Services:')} claude, chatgpt, firebase, googleauth
|
|
66
|
+
${c.bold('Services:')} claude, chatgpt, firebase, googleauth, atlassian
|
|
54
67
|
|
|
55
68
|
${c.bold('Examples:')}
|
|
56
69
|
sudo npx bypass-vpn
|
|
57
70
|
sudo bypass-vpn --service claude --service chatgpt
|
|
71
|
+
bypass-vpn --add-domain mycompany.atlassian.net
|
|
72
|
+
sudo bypass-vpn
|
|
58
73
|
sudo bypass-vpn --remove
|
|
59
74
|
`);
|
|
60
75
|
process.exit(0);
|
|
@@ -67,6 +82,27 @@ if (flags.version) {
|
|
|
67
82
|
process.exit(0);
|
|
68
83
|
}
|
|
69
84
|
|
|
85
|
+
// ── Add / Remove domain ───────────────────────────────────────
|
|
86
|
+
|
|
87
|
+
const DOMAIN_RE = /^[a-zA-Z0-9.-]+$/;
|
|
88
|
+
|
|
89
|
+
if (flags.addDomain) {
|
|
90
|
+
if (!DOMAIN_RE.test(flags.addDomain)) {
|
|
91
|
+
console.error(c.red(` Invalid domain: ${flags.addDomain}`));
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
addDomain(flags.addDomain);
|
|
95
|
+
console.log(` ${c.green('Saved:')} ${flags.addDomain}`);
|
|
96
|
+
console.log(` ${c.dim('This domain will be routed on every run.')}`);
|
|
97
|
+
process.exit(0);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (flags.removeDomain) {
|
|
101
|
+
removeDomain(flags.removeDomain);
|
|
102
|
+
console.log(` ${c.green('Removed:')} ${flags.removeDomain}`);
|
|
103
|
+
process.exit(0);
|
|
104
|
+
}
|
|
105
|
+
|
|
70
106
|
// ── List ───────────────────────────────────────────────────────
|
|
71
107
|
|
|
72
108
|
if (flags.list) {
|
|
@@ -78,6 +114,14 @@ if (flags.list) {
|
|
|
78
114
|
}
|
|
79
115
|
console.log('');
|
|
80
116
|
}
|
|
117
|
+
const config = loadConfig();
|
|
118
|
+
if (config.domains.length > 0) {
|
|
119
|
+
console.log(` ${c.bold('Custom Domains')} ${c.dim('(saved via --add-domain)')}`);
|
|
120
|
+
for (const d of config.domains) {
|
|
121
|
+
console.log(` ${c.dim('-')} ${d}`);
|
|
122
|
+
}
|
|
123
|
+
console.log('');
|
|
124
|
+
}
|
|
81
125
|
process.exit(0);
|
|
82
126
|
}
|
|
83
127
|
|
|
@@ -114,7 +158,16 @@ async function main() {
|
|
|
114
158
|
selectedServices[key] = services[key];
|
|
115
159
|
}
|
|
116
160
|
} else {
|
|
117
|
-
selectedServices = services;
|
|
161
|
+
selectedServices = { ...services };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Inject saved custom domains
|
|
165
|
+
const config = loadConfig();
|
|
166
|
+
if (config.domains.length > 0) {
|
|
167
|
+
selectedServices.custom = {
|
|
168
|
+
name: 'Custom Domains',
|
|
169
|
+
domains: config.domains,
|
|
170
|
+
};
|
|
118
171
|
}
|
|
119
172
|
|
|
120
173
|
// Process each service
|
package/package.json
CHANGED
package/src/config.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
|
|
5
|
+
const CONFIG_PATH = path.join(os.homedir(), '.bypass-vpn.json');
|
|
6
|
+
|
|
7
|
+
function loadConfig() {
|
|
8
|
+
try {
|
|
9
|
+
const data = fs.readFileSync(CONFIG_PATH, 'utf8');
|
|
10
|
+
const config = JSON.parse(data);
|
|
11
|
+
return { domains: Array.isArray(config.domains) ? config.domains : [] };
|
|
12
|
+
} catch {
|
|
13
|
+
return { domains: [] };
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function saveConfig(config) {
|
|
18
|
+
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2) + '\n');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function addDomain(domain) {
|
|
22
|
+
const config = loadConfig();
|
|
23
|
+
if (!config.domains.includes(domain)) {
|
|
24
|
+
config.domains.push(domain);
|
|
25
|
+
saveConfig(config);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function removeDomain(domain) {
|
|
30
|
+
const config = loadConfig();
|
|
31
|
+
config.domains = config.domains.filter((d) => d !== domain);
|
|
32
|
+
saveConfig(config);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = { loadConfig, addDomain, removeDomain };
|
package/src/resolver.js
CHANGED
|
@@ -1,12 +1,39 @@
|
|
|
1
|
+
const { execSync } = require('child_process');
|
|
1
2
|
const dns = require('dns');
|
|
2
3
|
const dnsPromises = dns.promises;
|
|
3
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Resolve a domain using `dig` — works outside VPN tunnel.
|
|
7
|
+
* Falls back to Node.js DNS if `dig` is unavailable.
|
|
8
|
+
*/
|
|
9
|
+
function resolveDomain(domain) {
|
|
10
|
+
try {
|
|
11
|
+
const output = execSync(`dig +short +time=3 "${domain}"`, {
|
|
12
|
+
timeout: 5000,
|
|
13
|
+
encoding: 'utf8',
|
|
14
|
+
});
|
|
15
|
+
const ips = output
|
|
16
|
+
.split('\n')
|
|
17
|
+
.map((line) => line.trim())
|
|
18
|
+
.filter((line) => /^\d+\.\d+\.\d+\.\d+$/.test(line));
|
|
19
|
+
if (ips.length > 0) return ips;
|
|
20
|
+
} catch {
|
|
21
|
+
// dig not available or failed — fall through to Node DNS
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
4
26
|
async function resolveAll(domains) {
|
|
5
27
|
const resolved = new Map();
|
|
6
28
|
const failed = [];
|
|
7
29
|
|
|
8
30
|
const results = await Promise.allSettled(
|
|
9
31
|
domains.map(async (domain) => {
|
|
32
|
+
// Try dig first (bypasses VPN DNS interception)
|
|
33
|
+
const digIps = resolveDomain(domain);
|
|
34
|
+
if (digIps) return { domain, ips: digIps };
|
|
35
|
+
|
|
36
|
+
// Fallback to Node.js built-in DNS
|
|
10
37
|
const ips = await withTimeout(dnsPromises.resolve4(domain), 5000);
|
|
11
38
|
return { domain, ips };
|
|
12
39
|
})
|
|
@@ -21,7 +48,6 @@ async function resolveAll(domains) {
|
|
|
21
48
|
failed.push(domain);
|
|
22
49
|
}
|
|
23
50
|
} else {
|
|
24
|
-
// Extract domain from the original array by index
|
|
25
51
|
const idx = results.indexOf(result);
|
|
26
52
|
failed.push(domains[idx]);
|
|
27
53
|
}
|