mirror of
https://github.com/therealaleph/MasterHttpRelayVPN-RUST.git
synced 2026-05-18 06:34:41 +03:00
v0.8.5: Check-CA actually checks Windows now (follow-up to #13)
User on issue #13 reported that even after installing the CA (and seeing it in the Windows cert manager UI), our 'Check CA' button still said 'NOT trusted'. Root cause: is_ca_trusted() on Windows was just returning false unconditionally — Check-CA has never worked on Windows. Fix: is_trusted_windows() now shells out to certutil: certutil -user -store Root 'MasterHttpRelayVPN' certutil -store Root 'MasterHttpRelayVPN' Checks both the user store (where our install_windows puts it by default) and the machine store (fallback path when user-store install is blocked). Requires certutil to print the cert name in stdout AND exit 0 — belt-and-suspenders against locales where certutil exits 0 even on an empty match. Also made the Check-CA UI message point users at the CA file path for cross-device install — the same user reported their Android V2rayNG client getting cert errors on our MITM-signed TLS leaves, which is the expected 'the phone doesn't trust our CA' scenario. The message now calls out the ca.crt path explicitly, and notes the Android 7+ user-CA restriction (Firefox Android works, Chrome and most apps don't trust user-installed CAs regardless). Not addressed (by design): - Replacing our CA keypair with Python-generated PEM fails to parse via rcgen. User tried this as a workaround before reporting. rcgen expects PKCS#8 PEM; Python's cryptography commonly emits PKCS#1 ('BEGIN RSA PRIVATE KEY'). Even if parsing worked, mixing an external CA with our leaf-issuing code would break the key match. Users should stick with our generated CA — that's the supported flow. The Python cross-contamination experiment is expected to fail; we don't document it as supported.
This commit is contained in:
Generated
+1
-1
@@ -1317,7 +1317,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mhrv-rs"
|
name = "mhrv-rs"
|
||||||
version = "0.8.4"
|
version = "0.8.5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mhrv-rs"
|
name = "mhrv-rs"
|
||||||
version = "0.8.4"
|
version = "0.8.5"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "Rust port of MasterHttpRelayVPN -- DPI bypass via Google Apps Script relay with domain fronting"
|
description = "Rust port of MasterHttpRelayVPN -- DPI bypass via Google Apps Script relay with domain fronting"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|||||||
+22
-3
@@ -772,9 +772,28 @@ impl eframe::App for App {
|
|||||||
ui.small(last_test_msg);
|
ui.small(last_test_msg);
|
||||||
}
|
}
|
||||||
match ca_trusted {
|
match ca_trusted {
|
||||||
Some(true) => { ui.small("CA appears trusted."); },
|
Some(true) => {
|
||||||
Some(false) => { ui.small("CA is NOT trusted in the system store. Click 'Install CA' (may require admin)."); },
|
ui.small("CA appears trusted on this machine.");
|
||||||
None => {},
|
}
|
||||||
|
Some(false) => {
|
||||||
|
ui.small(
|
||||||
|
"CA is NOT trusted in the system store. Click 'Install CA' \
|
||||||
|
(may require admin). If you already installed it and this \
|
||||||
|
still says NO, you may be on an older build — v0.8.5+ \
|
||||||
|
checks the Windows store correctly.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
if ca_trusted.is_some() {
|
||||||
|
let ca_path = data_dir::data_dir().join("ca").join("ca.crt");
|
||||||
|
ui.small(format!(
|
||||||
|
"For other devices (Android, other PCs) connecting through this proxy: \
|
||||||
|
copy {} and install as a trusted root on that device. On Android 7+ \
|
||||||
|
most apps ignore user-installed CAs — Firefox Android works; Chrome \
|
||||||
|
and many others don't.",
|
||||||
|
ca_path.display()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|||||||
+28
-1
@@ -55,7 +55,7 @@ pub fn is_ca_trusted(path: &Path) -> bool {
|
|||||||
match std::env::consts::OS {
|
match std::env::consts::OS {
|
||||||
"macos" => is_trusted_macos(),
|
"macos" => is_trusted_macos(),
|
||||||
"linux" => is_trusted_linux(),
|
"linux" => is_trusted_linux(),
|
||||||
"windows" => false,
|
"windows" => is_trusted_windows(),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -303,6 +303,33 @@ fn is_trusted_linux() -> bool {
|
|||||||
|
|
||||||
// ---------- Windows ----------
|
// ---------- Windows ----------
|
||||||
|
|
||||||
|
/// Check whether our CA is present in the Windows Trusted Root store.
|
||||||
|
/// Looks in both the user store (no admin required to install) and the
|
||||||
|
/// machine store. Returns true if `certutil -store ... MasterHttpRelayVPN`
|
||||||
|
/// finds a match. Issue #13 follow-up: previously this always returned
|
||||||
|
/// false on Windows, so the Check-CA button was misleading users into
|
||||||
|
/// reinstalling a cert that was already trusted.
|
||||||
|
fn is_trusted_windows() -> bool {
|
||||||
|
// `certutil -user -store Root <name>` prints the matching cert entries
|
||||||
|
// on success (stdout), and exits with a non-zero code plus a "Not
|
||||||
|
// found" message if nothing matches. We also check stdout for the
|
||||||
|
// cert name because certutil in some locales returns 0 even on no-
|
||||||
|
// match, just with empty output.
|
||||||
|
for args in [
|
||||||
|
vec!["-user", "-store", "Root", CERT_NAME],
|
||||||
|
vec!["-store", "Root", CERT_NAME],
|
||||||
|
] {
|
||||||
|
let out = Command::new("certutil").args(&args).output();
|
||||||
|
if let Ok(o) = out {
|
||||||
|
let stdout = String::from_utf8_lossy(&o.stdout);
|
||||||
|
if o.status.success() && stdout.to_ascii_lowercase().contains(&CERT_NAME.to_ascii_lowercase()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
fn install_windows(cert_path: &str) -> bool {
|
fn install_windows(cert_path: &str) -> bool {
|
||||||
// Per-user Root store (no admin required).
|
// Per-user Root store (no admin required).
|
||||||
let res = Command::new("certutil")
|
let res = Command::new("certutil")
|
||||||
|
|||||||
Reference in New Issue
Block a user