evo-cli 0.35.0__tar.gz → 0.35.2__tar.gz
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.
- {evo_cli-0.35.0 → evo_cli-0.35.2}/PKG-INFO +1 -1
- evo_cli-0.35.2/evo_cli/VERSION +1 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/route/_spoofdpi.py +3 -60
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/openvpn.py +0 -16
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli.egg-info/PKG-INFO +1 -1
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_openvpn.py +1 -11
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_route.py +0 -30
- evo_cli-0.35.0/evo_cli/VERSION +0 -1
- {evo_cli-0.35.0 → evo_cli-0.35.2}/Containerfile +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/HISTORY.md +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/LICENSE +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/MANIFEST.in +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/README.md +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/__init__.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/__main__.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/base.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/cli.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/__init__.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/agent_toy.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/claude_code.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/cloudflare.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/cred.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/download.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/fix_claude.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/gdrive.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/gh.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/__init__.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/_dag.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/_git.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/_hub.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/_mirror.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/_model.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/_mutate.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/_paths.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/_render.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/_server.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/check.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/clone.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/edit.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/pull.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/serve.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/show.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/views.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/web/assets/index-Cs7hXRPJ.css +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/web/assets/index-CuNOlaH7.js +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/web/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/web/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/web/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/web/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/web/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/web/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/web/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/web/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/web/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/web/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/web/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/web/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/harness/web/index.html +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/hwid.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/hwid_reset.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/image.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/localproxy.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/mcp.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/miniconda.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/netcheck.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/ngrok.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/opencode.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/openvpn.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/plantuml.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/route/__init__.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/route/_dns.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/route/_dpi.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/route/_hosts.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/route/_page.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/route/_probe.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/route/check.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/route/fix.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/route/probe.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/route/status.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/serp.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/site2s.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/ssh.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/storage.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/sysmon.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/tts.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/update.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/commands/wifi.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/console.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/credentials/__init__.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/credentials/doctor.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/credentials/google_oauth.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/credentials/migrate.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/credentials/oauth_flow.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/credentials/registry.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/credentials/store.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/credentials/sync.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/imaging/__init__.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/imaging/align.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/imaging/core.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/imaging/creds.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/imaging/errors.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/imaging/gemini.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/imaging/ncnn.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/mcp_registry.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/serp/__init__.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/serp/client.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/serp/creds.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/serp/errors.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/serp/install.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/serp/render.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/tts/__init__.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/tts/chunking.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/tts/core.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/tts/creds.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/tts/errors.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/tts/gemini.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/tts/http.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/tts/openai.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/tts/player.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli/tts/vbee.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli.egg-info/SOURCES.txt +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli.egg-info/dependency_links.txt +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli.egg-info/entry_points.txt +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli.egg-info/requires.txt +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/evo_cli.egg-info/top_level.txt +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/pyproject.toml +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/setup.cfg +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/__init__.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/fake_evo_agents.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/fixtures/hub/contract-0.2.0.json +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/fixtures/hub/mirror-demo.yaml +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_agent_toy.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_claude_code.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_cli.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_console.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_cred.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_download.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_fix_claude.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_gdrive.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_gh.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_harness.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_harness_clone.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_harness_dag.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_harness_hub.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_harness_show.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_image.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_mcp.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_ngrok.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_opencode.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_plantuml.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_serp.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_storage.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_sysmon.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_tts.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_update.py +0 -0
- {evo_cli-0.35.0 → evo_cli-0.35.2}/tests/test_wifi.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.35.2
|
|
@@ -3,10 +3,9 @@
|
|
|
3
3
|
GoodbyeDPI has no macOS build. SpoofDPI is a local HTTP proxy that splits the
|
|
4
4
|
TLS ClientHello, so the filter never reads the server name in one piece. It only
|
|
5
5
|
does that for the hosts `evo route open` named: every other name passes through
|
|
6
|
-
untouched and resolves with the system's DNS server
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
resolves through split DNS skip the proxy altogether (`sync_vpn_bypass`).
|
|
6
|
+
untouched and resolves with the system's DNS server (SpoofDPI's own resolver,
|
|
7
|
+
which does not read /etc/resolver). The named hosts resolve over DoH instead,
|
|
8
|
+
because a name the filter blocks usually has its DNS answer poisoned too.
|
|
10
9
|
"""
|
|
11
10
|
|
|
12
11
|
from __future__ import annotations
|
|
@@ -47,10 +46,6 @@ dns = {{ mode = "https", cache = true }}
|
|
|
47
46
|
https = {{ skip = false, split-mode = "{SPLIT_MODE}" }}
|
|
48
47
|
"""
|
|
49
48
|
|
|
50
|
-
# The evo openvpn DNS hook starts each /etc/resolver file it writes with this tag.
|
|
51
|
-
RESOLVER = Path("/etc/resolver")
|
|
52
|
-
VPN_TAG = "# evo openvpn "
|
|
53
|
-
|
|
54
49
|
# networksetup names both proxies by these words: -getwebproxy, -setsecurewebproxystate, ...
|
|
55
50
|
PROXY_KINDS = ("webproxy", "securewebproxy")
|
|
56
51
|
|
|
@@ -263,56 +258,6 @@ def clear_system_proxy():
|
|
|
263
258
|
return cleared
|
|
264
259
|
|
|
265
260
|
|
|
266
|
-
def vpn_domains():
|
|
267
|
-
"""Domains a connected evo VPN resolves with its own DNS: its tagged files under /etc/resolver."""
|
|
268
|
-
domains = []
|
|
269
|
-
for path in sorted(RESOLVER.glob("*")):
|
|
270
|
-
try:
|
|
271
|
-
with path.open(encoding="utf-8") as handle:
|
|
272
|
-
tagged = handle.readline().startswith(VPN_TAG)
|
|
273
|
-
except (OSError, UnicodeDecodeError):
|
|
274
|
-
continue
|
|
275
|
-
if tagged:
|
|
276
|
-
domains.append(path.name)
|
|
277
|
-
return domains
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
def _bypass(service):
|
|
281
|
-
lines = _networksetup("-getproxybypassdomains", service).stdout.splitlines()
|
|
282
|
-
return [line.strip() for line in lines if line.strip() and not line.startswith("There aren't any")]
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
def sync_vpn_bypass():
|
|
286
|
-
"""Let the names a connected evo VPN resolves skip the proxy, and take them out again once it is down.
|
|
287
|
-
|
|
288
|
-
SpoofDPI would ask the system's DNS server for them and fail. Each service whose proxy is ours bypasses those
|
|
289
|
-
domains; what this added is recorded per service, so only that comes out again and a user's entries stay.
|
|
290
|
-
"""
|
|
291
|
-
record = home() / "vpn-bypass.json"
|
|
292
|
-
try:
|
|
293
|
-
added = json.loads(record.read_text())
|
|
294
|
-
except (OSError, ValueError):
|
|
295
|
-
added = {}
|
|
296
|
-
wanted = [entry for domain in vpn_domains() for entry in (domain, f"*.{domain}")]
|
|
297
|
-
proxied = proxied_services()
|
|
298
|
-
now = {}
|
|
299
|
-
for service in network_services():
|
|
300
|
-
mine = added.get(service, [])
|
|
301
|
-
if not mine and service not in proxied:
|
|
302
|
-
continue
|
|
303
|
-
current = _bypass(service)
|
|
304
|
-
kept = [entry for entry in current if entry not in mine]
|
|
305
|
-
new = [entry for entry in wanted if entry not in kept] if service in proxied else []
|
|
306
|
-
if kept + new != current:
|
|
307
|
-
_networksetup("-setproxybypassdomains", service, *(kept + new or ["Empty"]))
|
|
308
|
-
if new:
|
|
309
|
-
now[service] = new
|
|
310
|
-
if now or added:
|
|
311
|
-
home().mkdir(parents=True, exist_ok=True)
|
|
312
|
-
record.write_text(json.dumps(now))
|
|
313
|
-
return now
|
|
314
|
-
|
|
315
|
-
|
|
316
261
|
def _extension_name(profile, ext_id):
|
|
317
262
|
for path in sorted((profile / "Extensions" / ext_id).glob("*/manifest.json")):
|
|
318
263
|
try:
|
|
@@ -378,7 +323,6 @@ def ensure(*hosts):
|
|
|
378
323
|
if not _start(reload=_write_agent(exe)):
|
|
379
324
|
return service_state()
|
|
380
325
|
set_system_proxy()
|
|
381
|
-
sync_vpn_bypass()
|
|
382
326
|
return service_state()
|
|
383
327
|
|
|
384
328
|
|
|
@@ -395,7 +339,6 @@ def forget(host):
|
|
|
395
339
|
def remove():
|
|
396
340
|
"""Clear the system proxy first, so nothing points at a proxy that is gone, then stop and drop the agent."""
|
|
397
341
|
clear_system_proxy()
|
|
398
|
-
sync_vpn_bypass()
|
|
399
342
|
_launchctl("bootout", f"{_domain()}/{LABEL}")
|
|
400
343
|
agent_path().unlink(missing_ok=True)
|
|
401
344
|
hosts_path().unlink(missing_ok=True)
|
|
@@ -355,18 +355,6 @@ def split_dns(command, name, hooks=Path("/var/run"), resolver=Path("/etc/resolve
|
|
|
355
355
|
return ["sh", "-c", wrapper, "sh", script, *hooked]
|
|
356
356
|
|
|
357
357
|
|
|
358
|
-
def sync_proxy_bypass():
|
|
359
|
-
"""On macOS, let the names this VPN resolves skip evo route's proxy; never fatal to the connection."""
|
|
360
|
-
if sys.platform != "darwin":
|
|
361
|
-
return
|
|
362
|
-
try:
|
|
363
|
-
from evo_cli.commands.route import _spoofdpi
|
|
364
|
-
|
|
365
|
-
_spoofdpi.sync_vpn_bypass()
|
|
366
|
-
except Exception:
|
|
367
|
-
pass
|
|
368
|
-
|
|
369
|
-
|
|
370
358
|
def parse_totp(value):
|
|
371
359
|
value = value.strip()
|
|
372
360
|
settings = {"secret": value, "algorithm": "SHA1", "digits": 6, "period": 30}
|
|
@@ -823,8 +811,6 @@ def worker(name, timeout):
|
|
|
823
811
|
state["since"] = time.time()
|
|
824
812
|
state.pop("auth_url", None)
|
|
825
813
|
state.pop("auth_expires", None)
|
|
826
|
-
# The DNS hook ran before CONNECTED (route-up); its domains now exist.
|
|
827
|
-
sync_proxy_bypass()
|
|
828
814
|
# Once up, let OpenVPN retry for as long as the network is gone.
|
|
829
815
|
deadline = float("inf")
|
|
830
816
|
elif fields[1] != "CONNECTED":
|
|
@@ -876,8 +862,6 @@ def worker(name, timeout):
|
|
|
876
862
|
"error": "OpenVPN did not exit; inspect processes manually.",
|
|
877
863
|
}
|
|
878
864
|
publish()
|
|
879
|
-
# OpenVPN has exited and its DNS hook has removed the domains; the proxy takes them back.
|
|
880
|
-
sync_proxy_bypass()
|
|
881
865
|
selector.close()
|
|
882
866
|
control.close()
|
|
883
867
|
listener.close()
|
|
@@ -18,14 +18,6 @@ CONFIG = "client\ndev tun\nremote vpn.example 1194 udp\nauth-user-pass\n<ca>\nte
|
|
|
18
18
|
SECRET = base64.b32encode(b"12345678901234567890").decode()
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
@pytest.fixture(autouse=True)
|
|
22
|
-
def no_proxy_sync(monkeypatch):
|
|
23
|
-
"""The worker would otherwise change this machine's proxy bypass list."""
|
|
24
|
-
synced = []
|
|
25
|
-
monkeypatch.setattr(vpn, "sync_proxy_bypass", lambda: synced.append(True))
|
|
26
|
-
return synced
|
|
27
|
-
|
|
28
|
-
|
|
29
21
|
@pytest.fixture
|
|
30
22
|
def store(tmp_path, monkeypatch):
|
|
31
23
|
if sys.platform == "win32":
|
|
@@ -651,7 +643,7 @@ with socket.socket(socket.AF_UNIX) as s:
|
|
|
651
643
|
|
|
652
644
|
|
|
653
645
|
@pytest.mark.parametrize("mode", ["ok", "fail", "reconnect", "webauth"])
|
|
654
|
-
def test_worker_real_sockets_auth_status_shutdown_without_root(store, monkeypatch, mode
|
|
646
|
+
def test_worker_real_sockets_auth_status_shutdown_without_root(store, monkeypatch, mode):
|
|
655
647
|
fail, webauth = mode == "fail", mode == "webauth"
|
|
656
648
|
config = CERT_ONLY if webauth else CONFIG
|
|
657
649
|
vpn.save_profile(
|
|
@@ -698,8 +690,6 @@ def test_worker_real_sockets_auth_status_shutdown_without_root(store, monkeypatc
|
|
|
698
690
|
thread.join(5)
|
|
699
691
|
assert not thread.is_alive()
|
|
700
692
|
assert opened == (["https://vpn.example/auth/1"] if webauth else [])
|
|
701
|
-
# The proxy bypass follows the DNS hook: on each CONNECTED, and once more after OpenVPN exits.
|
|
702
|
-
assert len(no_proxy_sync) == {"fail": 1, "reconnect": 3}.get(mode, 2)
|
|
703
693
|
assert vpn.request("m1")["state"] == "STOPPED"
|
|
704
694
|
base = vpn.session_path("m1")
|
|
705
695
|
state = json.loads(Path(str(base) + ".json").read_text())
|
|
@@ -254,36 +254,6 @@ def _fake_networksetup(proxies, calls):
|
|
|
254
254
|
return run
|
|
255
255
|
|
|
256
256
|
|
|
257
|
-
def test_vpn_split_dns_domains_skip_the_proxy_and_only_ours_come_out(tmp_path, monkeypatch):
|
|
258
|
-
monkeypatch.setenv("EVO_ROUTE_HOME", str(tmp_path / "route"))
|
|
259
|
-
resolver = tmp_path / "resolver"
|
|
260
|
-
resolver.mkdir()
|
|
261
|
-
monkeypatch.setattr(_spoofdpi, "RESOLVER", resolver)
|
|
262
|
-
(resolver / "corp.example").write_text("# evo openvpn m1\nnameserver 10.0.0.1\n")
|
|
263
|
-
(resolver / "mine.example").write_text("nameserver 192.0.2.1\n")
|
|
264
|
-
ours = (True, _spoofdpi.LISTEN_HOST, str(_spoofdpi.LISTEN_PORT))
|
|
265
|
-
proxies = {("Wi-Fi", "webproxy"): ours, ("Wi-Fi", "securewebproxy"): ours}
|
|
266
|
-
bypass = {"Wi-Fi": ["*.local", "*.corp.example"], "USB LAN": ["*.local"]}
|
|
267
|
-
fake = _fake_networksetup(proxies, [])
|
|
268
|
-
|
|
269
|
-
def run(*args):
|
|
270
|
-
if args[0] == "-getproxybypassdomains":
|
|
271
|
-
out = "\n".join(bypass[args[1]]) or f"There aren't any bypass domains set on {args[1]}."
|
|
272
|
-
return subprocess.CompletedProcess(args, 0, out + "\n", "")
|
|
273
|
-
if args[0] == "-setproxybypassdomains":
|
|
274
|
-
bypass[args[1]] = [] if args[2:] == ("Empty",) else list(args[2:])
|
|
275
|
-
return subprocess.CompletedProcess(args, 0, "", "")
|
|
276
|
-
return fake(*args)
|
|
277
|
-
|
|
278
|
-
monkeypatch.setattr(_spoofdpi, "_networksetup", run)
|
|
279
|
-
# Only the tagged domain, only on the proxied service; the user's own *.corp.example is not added twice.
|
|
280
|
-
assert _spoofdpi.sync_vpn_bypass() == {"Wi-Fi": ["corp.example"]}
|
|
281
|
-
assert bypass == {"Wi-Fi": ["*.local", "*.corp.example", "corp.example"], "USB LAN": ["*.local"]}
|
|
282
|
-
(resolver / "corp.example").unlink() # the VPN is down
|
|
283
|
-
assert _spoofdpi.sync_vpn_bypass() == {}
|
|
284
|
-
assert bypass == {"Wi-Fi": ["*.local", "*.corp.example"], "USB LAN": ["*.local"]}
|
|
285
|
-
|
|
286
|
-
|
|
287
257
|
def test_spoofdpi_host_list_round_trips_with_subdomains(tmp_path, monkeypatch):
|
|
288
258
|
monkeypatch.setenv("EVO_ROUTE_HOME", str(tmp_path))
|
|
289
259
|
_spoofdpi._write_hosts(["medium.com", "x.com", "medium.com"])
|
evo_cli-0.35.0/evo_cli/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0.35.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|