mirror of
https://code.gri.mw/GUI/grim.git
synced 2026-07-04 05:57:29 +00:00
tor: webtunnel support
- Add webtunnel bridge - Build from https://code.gri.mw/ardocrat/webtunnel to include binary into the build - Build and run webtunnel for Android Reviewed-on: https://code.gri.mw/GUI/grim/pulls/44
This commit is contained in:
@@ -367,7 +367,7 @@ jobs:
|
|||||||
- name: Release Windows x86
|
- name: Release Windows x86
|
||||||
run: |
|
run: |
|
||||||
cargo build --release --target x86_64-pc-windows-gnu
|
cargo build --release --target x86_64-pc-windows-gnu
|
||||||
zip grim-${{ needs.version.outputs.v }}-win-x86_64.zip target/x86_64-pc-windows-gnu/release/grim.exe
|
zip -j grim-${{ needs.version.outputs.v }}-win-x86_64.zip target/x86_64-pc-windows-gnu/release/grim.exe
|
||||||
mv grim-${{ needs.version.outputs.v }}-win-x86_64.zip release/
|
mv grim-${{ needs.version.outputs.v }}-win-x86_64.zip release/
|
||||||
- name: Save cargo cache
|
- name: Save cargo cache
|
||||||
uses: actions/cache/save@v5
|
uses: actions/cache/save@v5
|
||||||
@@ -389,7 +389,7 @@ jobs:
|
|||||||
|
|
||||||
release:
|
release:
|
||||||
if: ${{ forgejo.ref_type == 'branch' || needs.version.outputs.exists == 'false' }}
|
if: ${{ forgejo.ref_type == 'branch' || needs.version.outputs.exists == 'false' }}
|
||||||
runs-on: ubuntu
|
runs-on: debian-release
|
||||||
needs: [version, android_release, linux, linux_x86, macos, windows]
|
needs: [version, android_release, linux, linux_x86, macos, windows]
|
||||||
steps:
|
steps:
|
||||||
- name: Download All Artifacts
|
- name: Download All Artifacts
|
||||||
|
|||||||
+5
-1
@@ -4,4 +4,8 @@
|
|||||||
[submodule "wallet"]
|
[submodule "wallet"]
|
||||||
path = wallet
|
path = wallet
|
||||||
url = https://code.gri.mw/ardocrat/wallet
|
url = https://code.gri.mw/ardocrat/wallet
|
||||||
branch = grim
|
branch = grim
|
||||||
|
[submodule "tor/webtunnel"]
|
||||||
|
path = tor/webtunnel
|
||||||
|
url = https://code.gri.mw/WEB/webtunnel
|
||||||
|
branch = grim
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ license = "Apache-2.0"
|
|||||||
repository = "https://code.gri.mw/GUI/grim"
|
repository = "https://code.gri.mw/GUI/grim"
|
||||||
keywords = [ "crypto", "grin", "mimblewimble" ]
|
keywords = [ "crypto", "grin", "mimblewimble" ]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "grim"
|
name = "grim"
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:theme="@style/Theme.Main"
|
android:theme="@style/Theme.Main"
|
||||||
android:enableOnBackInvokedCallback="false"
|
android:enableOnBackInvokedCallback="false"
|
||||||
|
android:extractNativeLibs="true"
|
||||||
tools:ignore="UnusedAttribute">
|
tools:ignore="UnusedAttribute">
|
||||||
|
|
||||||
<receiver android:name=".NotificationActionsReceiver"/>
|
<receiver android:name=".NotificationActionsReceiver"/>
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ public class MainActivity extends GameActivity {
|
|||||||
Os.setenv("HOME", Objects.requireNonNull(getExternalFilesDir("")).getPath(), true);
|
Os.setenv("HOME", Objects.requireNonNull(getExternalFilesDir("")).getPath(), true);
|
||||||
Os.setenv("XDG_CACHE_HOME", Objects.requireNonNull(getExternalCacheDir()).getPath(), true);
|
Os.setenv("XDG_CACHE_HOME", Objects.requireNonNull(getExternalCacheDir()).getPath(), true);
|
||||||
Os.setenv("ARTI_FS_DISABLE_PERMISSION_CHECKS", "true", true);
|
Os.setenv("ARTI_FS_DISABLE_PERMISSION_CHECKS", "true", true);
|
||||||
|
Os.setenv("NATIVE_LIBS_DIR", getApplicationInfo().nativeLibraryDir, true);
|
||||||
} catch (ErrnoException e) {
|
} catch (ErrnoException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
use std::process::Command;
|
||||||
|
use std::{env, fs};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let out_dir = env::var("OUT_DIR").unwrap();
|
||||||
|
let tor_out_dir = format!("{}/tor", out_dir);
|
||||||
|
let mut webtunnel_file = format!("{}/webtunnel", tor_out_dir);
|
||||||
|
let exists = fs::exists(&webtunnel_file).unwrap();
|
||||||
|
if !exists {
|
||||||
|
// Create empty webtunnel file to allow build with include_bytes! macro.
|
||||||
|
fs::create_dir(&tor_out_dir).unwrap_or_default();
|
||||||
|
fs::File::create(&webtunnel_file).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let target = env::var("TARGET").unwrap();
|
||||||
|
let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
|
||||||
|
|
||||||
|
let is_android = target_os == "android";
|
||||||
|
if is_android {
|
||||||
|
// Set a path to Android Webtunnel binary.
|
||||||
|
let arch = if target.contains("aarch64") {
|
||||||
|
"arm64-v8a"
|
||||||
|
} else if target.contains("arm") {
|
||||||
|
"armeabi-v7a"
|
||||||
|
} else {
|
||||||
|
"x86_64"
|
||||||
|
};
|
||||||
|
let root = env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||||
|
webtunnel_file = format!("{}/android/app/src/main/jniLibs/{}/libwebtunnel.so", root, arch);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build if Webtunnel binary is empty or not exists.
|
||||||
|
let empty = match fs::File::open(&webtunnel_file) {
|
||||||
|
Ok(file) => file.metadata().unwrap().len() != 0,
|
||||||
|
Err(_) => true
|
||||||
|
};
|
||||||
|
let build = !exists || empty;
|
||||||
|
if build {
|
||||||
|
// Setup GOOS env variable.
|
||||||
|
let go_os = if target_os == "macos" {
|
||||||
|
"darwin"
|
||||||
|
} else {
|
||||||
|
target_os.as_str()
|
||||||
|
};
|
||||||
|
// Setup GOARCH env variable.
|
||||||
|
let go_arch = if target.contains("aarch64") {
|
||||||
|
"arm64"
|
||||||
|
} else if target.contains("arm") {
|
||||||
|
"arm"
|
||||||
|
} else {
|
||||||
|
"amd64"
|
||||||
|
};
|
||||||
|
// Run Webtunnel Go build.
|
||||||
|
if let Ok(out) = Command::new("bash")
|
||||||
|
.arg("./scripts/webtunnel.sh")
|
||||||
|
.arg(go_os)
|
||||||
|
.arg(go_arch)
|
||||||
|
.arg(webtunnel_file)
|
||||||
|
.output() {
|
||||||
|
if out.status.code().is_none() || out.status.code().unwrap() != 0 {
|
||||||
|
panic!("webtunnel go build failed:\n{:?}", out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+51
@@ -0,0 +1,51 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
|
# Skip if Go not found.
|
||||||
|
if ! command -v go >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
echo "Go could not be found"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
go_os=$1
|
||||||
|
go_arch=$2
|
||||||
|
|
||||||
|
echo "Go build for os: $go_os, arch: $go_arch"
|
||||||
|
|
||||||
|
# Setup vars for Android.
|
||||||
|
if [[ "$go_os" == "android" ]]; then
|
||||||
|
# Setup NDK root path env.
|
||||||
|
if [[ -z "$ANDROID_NDK_HOME" ]]; then
|
||||||
|
NDK_VERSION=$(cat ../android/app/build.gradle | grep 'ndkVersion' | cut -d \' -f 2)
|
||||||
|
ANDROID_NDK_HOME=$ANDROID_HOME/ndk/$NDK_VERSION
|
||||||
|
fi
|
||||||
|
# Setup NDK host path.
|
||||||
|
if [[ "$(uname)" == "Darwin" ]]; then
|
||||||
|
arch_host=darwin-x86_64
|
||||||
|
else
|
||||||
|
if [[ "$(uname -m)" == "aarch64" ]]; then
|
||||||
|
arch_host=linux-arm64
|
||||||
|
else
|
||||||
|
arch_host=linux-x86_64
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
# Setup NDK target arch.
|
||||||
|
if [[ "$go_arch" == "arm64" ]]; then
|
||||||
|
arch_bin_prefix=aarch64-linux-android
|
||||||
|
elif [[ "$go_arch" == "arm" ]]; then
|
||||||
|
arch_bin_prefix=armv7a-linux-androideabi
|
||||||
|
else
|
||||||
|
arch_bin_prefix=x86_64-linux-android
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build for current target.
|
||||||
|
CGO_ENABLED=1 GOOS=$1 GOARCH=$2 CC="${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/${arch_host}/bin/${arch_bin_prefix}35-clang" CXX="${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/${arch_path}/bin/${arch_bin_prefix}35-clang++" go build -C "../tor/webtunnel" -ldflags="-s -w" -o "$3" code.gri.mw/WEB/webtunnel/main/client
|
||||||
|
else
|
||||||
|
if [[ "$go_os" == "windows" ]]; then
|
||||||
|
extra_flag="-H=windowsgui"
|
||||||
|
fi
|
||||||
|
GOOS=$1 GOARCH=$2 go build -C "../tor/webtunnel" -ldflags="-s -w ${extra_flag}" -o "$3" code.gri.mw/WEB/webtunnel/main/client
|
||||||
|
fi
|
||||||
|
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use egui::{Align, Id, Layout, RichText, StrokeKind};
|
use egui::{Align, Id, Layout, RichText, StrokeKind};
|
||||||
|
use egui::os::OperatingSystem;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use crate::gui::icons::{CLOUD_CHECK, NOTCHES, PENCIL, SCAN, TERMINAL};
|
use crate::gui::icons::{CLOUD_CHECK, NOTCHES, PENCIL, SCAN, TERMINAL};
|
||||||
@@ -52,6 +53,29 @@ const BRIDGE_CONN_LINE_EDIT_MODAL: &'static str = "bridge_conn_line_edit_modal";
|
|||||||
/// Identifier for [`Modal`] to scan bridge line from QR code.
|
/// Identifier for [`Modal`] to scan bridge line from QR code.
|
||||||
const SCAN_BRIDGE_CONN_LINE_MODAL: &'static str = "scan_bridge_conn_line_modal";
|
const SCAN_BRIDGE_CONN_LINE_MODAL: &'static str = "scan_bridge_conn_line_modal";
|
||||||
|
|
||||||
|
impl Default for TorSettingsContent {
|
||||||
|
fn default() -> Self {
|
||||||
|
// Setup Tor bridge binary path edit text.
|
||||||
|
let bridge = TorConfig::get_bridge();
|
||||||
|
let (bin_path, conn_line) = if let Some(b) = bridge {
|
||||||
|
(b.binary_path(), b.connection_line())
|
||||||
|
} else {
|
||||||
|
("".to_string(), "".to_string())
|
||||||
|
};
|
||||||
|
Self {
|
||||||
|
settings_changed: false,
|
||||||
|
proxy_url_edit: "".to_string(),
|
||||||
|
proxy_url_error: false,
|
||||||
|
bridge_bin_path_edit: bin_path,
|
||||||
|
bridge_bin_pick_file: FilePickContent::new(
|
||||||
|
FilePickContentType::ItemButton(View::item_rounding(0, 1, true))
|
||||||
|
).no_parse(),
|
||||||
|
bridge_conn_line_edit: conn_line,
|
||||||
|
bridge_qr_scan_content: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ContentContainer for TorSettingsContent {
|
impl ContentContainer for TorSettingsContent {
|
||||||
fn modal_ids(&self) -> Vec<&'static str> {
|
fn modal_ids(&self) -> Vec<&'static str> {
|
||||||
vec![
|
vec![
|
||||||
@@ -71,11 +95,13 @@ impl ContentContainer for TorSettingsContent {
|
|||||||
if let Some(content) = self.bridge_qr_scan_content.as_mut() {
|
if let Some(content) = self.bridge_qr_scan_content.as_mut() {
|
||||||
let mut close = false;
|
let mut close = false;
|
||||||
content.modal_ui(ui, cb, |res| {
|
content.modal_ui(ui, cb, |res| {
|
||||||
let line = res.text();
|
|
||||||
// Save connection line after scanning.
|
// Save connection line after scanning.
|
||||||
|
let line = res.text();
|
||||||
let bridge = TorConfig::get_bridge().unwrap();
|
let bridge = TorConfig::get_bridge().unwrap();
|
||||||
TorBridge::save_bridge_conn_line(&bridge, line);
|
if bridge.connection_line() != line {
|
||||||
self.settings_changed = true;
|
TorBridge::save_bridge_conn_line(&bridge, line);
|
||||||
|
self.settings_changed = true;
|
||||||
|
}
|
||||||
close = true;
|
close = true;
|
||||||
});
|
});
|
||||||
if close {
|
if close {
|
||||||
@@ -155,7 +181,7 @@ impl ContentContainer for TorSettingsContent {
|
|||||||
let value = if bridge.is_some() {
|
let value = if bridge.is_some() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
let default_bridge = TorConfig::get_obfs4();
|
let default_bridge = TorConfig::get_webtunnel();
|
||||||
self.bridge_bin_path_edit = default_bridge.binary_path();
|
self.bridge_bin_path_edit = default_bridge.binary_path();
|
||||||
self.bridge_conn_line_edit = default_bridge.connection_line();
|
self.bridge_conn_line_edit = default_bridge.connection_line();
|
||||||
Some(default_bridge)
|
Some(default_bridge)
|
||||||
@@ -165,42 +191,53 @@ impl ContentContainer for TorSettingsContent {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Draw bridges selection and path.
|
|
||||||
if bridge.is_some() {
|
if bridge.is_some() {
|
||||||
let current_bridge = bridge.unwrap();
|
|
||||||
let mut bridge = current_bridge.clone();
|
|
||||||
|
|
||||||
ui.add_space(6.0);
|
ui.add_space(6.0);
|
||||||
ui.columns(2, |columns| {
|
// Show bridge selection for non-Android.
|
||||||
columns[0].vertical_centered(|ui| {
|
let is_android = OperatingSystem::from_target_os() == OperatingSystem::Android;
|
||||||
// Show Obfs4 bridge selector.
|
if !is_android {
|
||||||
let obfs4 = TorConfig::get_obfs4();
|
let current_bridge = bridge.unwrap();
|
||||||
let name = obfs4.protocol_name().to_uppercase();
|
let mut bridge = current_bridge.clone();
|
||||||
View::radio_value(ui, &mut bridge, obfs4, name);
|
|
||||||
|
ui.columns(2, |columns| {
|
||||||
|
columns[0].vertical_centered(|ui| {
|
||||||
|
// Show Webtunnel bridge selector.
|
||||||
|
let webtunnel = TorConfig::get_webtunnel();
|
||||||
|
let name = webtunnel.protocol_name().to_uppercase();
|
||||||
|
View::radio_value(ui, &mut bridge, webtunnel, name);
|
||||||
|
|
||||||
|
});
|
||||||
|
columns[1].vertical_centered(|ui| {
|
||||||
|
// Show Obfs4 bridge selector.
|
||||||
|
let obfs4 = TorConfig::get_obfs4();
|
||||||
|
let name = obfs4.protocol_name().to_uppercase();
|
||||||
|
View::radio_value(ui, &mut bridge, obfs4, name);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
columns[1].vertical_centered(|ui| {
|
ui.add_space(10.0);
|
||||||
|
ui.vertical_centered(|ui| {
|
||||||
// Show Snowflake bridge selector.
|
// Show Snowflake bridge selector.
|
||||||
let snowflake = TorConfig::get_snowflake();
|
let snowflake = TorConfig::get_snowflake();
|
||||||
let name = snowflake.protocol_name().to_uppercase();
|
let name = snowflake.protocol_name().to_uppercase();
|
||||||
View::radio_value(ui, &mut bridge, snowflake, name);
|
View::radio_value(ui, &mut bridge, snowflake, name);
|
||||||
});
|
});
|
||||||
});
|
ui.add_space(16.0);
|
||||||
ui.add_space(14.0);
|
|
||||||
|
|
||||||
// Check if bridge type was changed to save.
|
// Check if bridge type was changed to save.
|
||||||
if current_bridge != bridge {
|
if current_bridge != bridge {
|
||||||
TorConfig::save_bridge(Some(bridge.clone()));
|
TorConfig::save_bridge(Some(bridge.clone()));
|
||||||
self.bridge_bin_path_edit = bridge.binary_path();
|
self.bridge_bin_path_edit = bridge.binary_path();
|
||||||
self.bridge_conn_line_edit = bridge.connection_line();
|
self.bridge_conn_line_edit = bridge.connection_line();
|
||||||
self.settings_changed = true;
|
self.settings_changed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(br) = TorConfig::get_bridge().as_ref() {
|
if let Some(br) = TorConfig::get_bridge().as_ref() {
|
||||||
// Show bridge binary setup.
|
// Show bridge binary setup for non-Android.
|
||||||
self.bridge_bin_ui(ui, br, cb);
|
if !is_android {
|
||||||
|
self.bridge_bin_ui(ui, br, cb);
|
||||||
ui.add_space(10.0);
|
ui.add_space(10.0);
|
||||||
|
}
|
||||||
// Show bridge connection line setup.
|
// Show bridge connection line setup.
|
||||||
self.bridge_conn_line_ui(ui, br, cb);
|
self.bridge_conn_line_ui(ui, br, cb);
|
||||||
}
|
}
|
||||||
@@ -210,29 +247,6 @@ impl ContentContainer for TorSettingsContent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TorSettingsContent {
|
|
||||||
fn default() -> Self {
|
|
||||||
// Setup Tor bridge binary path edit text.
|
|
||||||
let bridge = TorConfig::get_bridge();
|
|
||||||
let (bin_path, conn_line) = if let Some(b) = bridge {
|
|
||||||
(b.binary_path(), b.connection_line())
|
|
||||||
} else {
|
|
||||||
("".to_string(), "".to_string())
|
|
||||||
};
|
|
||||||
Self {
|
|
||||||
settings_changed: false,
|
|
||||||
proxy_url_edit: "".to_string(),
|
|
||||||
proxy_url_error: false,
|
|
||||||
bridge_bin_path_edit: bin_path,
|
|
||||||
bridge_bin_pick_file: FilePickContent::new(
|
|
||||||
FilePickContentType::ItemButton(View::item_rounding(0, 1, true))
|
|
||||||
).no_parse(),
|
|
||||||
bridge_conn_line_edit: conn_line,
|
|
||||||
bridge_qr_scan_content: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TorSettingsContent {
|
impl TorSettingsContent {
|
||||||
/// Draw proxy edit modal content.
|
/// Draw proxy edit modal content.
|
||||||
fn proxy_modal_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) {
|
fn proxy_modal_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) {
|
||||||
@@ -363,8 +377,10 @@ impl TorSettingsContent {
|
|||||||
|
|
||||||
ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| {
|
ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| {
|
||||||
self.bridge_bin_pick_file.ui(ui, cb, |path| {
|
self.bridge_bin_pick_file.ui(ui, cb, |path| {
|
||||||
TorBridge::save_bridge_bin_path(bridge, path);
|
if bridge.binary_path() != path {
|
||||||
self.settings_changed = true;
|
TorBridge::save_bridge_bin_path(bridge, path);
|
||||||
|
self.settings_changed = true;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
View::item_button(ui, View::item_rounding(1, 3, true), PENCIL, None, || {
|
View::item_button(ui, View::item_rounding(1, 3, true), PENCIL, None, || {
|
||||||
self.bridge_bin_path_edit = bridge.binary_path();
|
self.bridge_bin_path_edit = bridge.binary_path();
|
||||||
@@ -396,7 +412,10 @@ impl TorSettingsContent {
|
|||||||
fn bridge_bin_edit_modal_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) {
|
fn bridge_bin_edit_modal_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) {
|
||||||
let on_save = |c: &mut TorSettingsContent| {
|
let on_save = |c: &mut TorSettingsContent| {
|
||||||
let bridge = TorConfig::get_bridge().unwrap();
|
let bridge = TorConfig::get_bridge().unwrap();
|
||||||
TorBridge::save_bridge_bin_path(&bridge, c.bridge_bin_path_edit.clone());
|
if bridge.binary_path() != c.bridge_bin_path_edit {
|
||||||
|
TorBridge::save_bridge_bin_path(&bridge, c.bridge_bin_path_edit.clone());
|
||||||
|
c.settings_changed = true;
|
||||||
|
}
|
||||||
Modal::close();
|
Modal::close();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -502,7 +521,10 @@ impl TorSettingsContent {
|
|||||||
fn bridge_conn_line_edit_modal_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) {
|
fn bridge_conn_line_edit_modal_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) {
|
||||||
let on_save = |c: &mut TorSettingsContent| {
|
let on_save = |c: &mut TorSettingsContent| {
|
||||||
let bridge = TorConfig::get_bridge().unwrap();
|
let bridge = TorConfig::get_bridge().unwrap();
|
||||||
TorBridge::save_bridge_conn_line(&bridge, c.bridge_conn_line_edit.clone());
|
if bridge.connection_line() != c.bridge_conn_line_edit {
|
||||||
|
TorBridge::save_bridge_conn_line(&bridge, c.bridge_conn_line_edit.clone());
|
||||||
|
c.settings_changed = true;
|
||||||
|
}
|
||||||
Modal::close();
|
Modal::close();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -157,14 +157,14 @@ impl WalletTransportContent {
|
|||||||
|
|
||||||
let is_running = Tor::is_service_running(service_id);
|
let is_running = Tor::is_service_running(service_id);
|
||||||
let has_error = Tor::is_service_failed(service_id);
|
let has_error = Tor::is_service_failed(service_id);
|
||||||
let address_color = if is_running {
|
let is_starting = Tor::is_service_starting(service_id);
|
||||||
|
let address_color = if is_running && !is_starting {
|
||||||
Colors::green()
|
Colors::green()
|
||||||
} else if has_error {
|
} else if has_error {
|
||||||
Colors::red()
|
Colors::red()
|
||||||
} else {
|
} else {
|
||||||
Colors::inactive_text()
|
Colors::inactive_text()
|
||||||
};
|
};
|
||||||
let is_starting = Tor::is_service_starting(service_id);
|
|
||||||
// Show slatepack address text.
|
// Show slatepack address text.
|
||||||
View::animate_text(ui, addr.clone(), 17.0, address_color, is_starting);
|
View::animate_text(ui, addr.clone(), 17.0, address_color, is_starting);
|
||||||
ui.add_space(1.0);
|
ui.add_space(1.0);
|
||||||
|
|||||||
@@ -12,22 +12,18 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use egui::os::OperatingSystem;
|
|
||||||
use egui::RichText;
|
use egui::RichText;
|
||||||
|
|
||||||
use crate::gui::Colors;
|
|
||||||
use crate::gui::platform::PlatformCallbacks;
|
use crate::gui::platform::PlatformCallbacks;
|
||||||
use crate::gui::views::settings::TorSettingsContent;
|
use crate::gui::views::settings::TorSettingsContent;
|
||||||
use crate::gui::views::types::ContentContainer;
|
use crate::gui::views::types::ContentContainer;
|
||||||
use crate::gui::views::View;
|
use crate::gui::views::View;
|
||||||
|
use crate::gui::Colors;
|
||||||
use crate::tor::Tor;
|
use crate::tor::Tor;
|
||||||
use crate::wallet::Wallet;
|
use crate::wallet::Wallet;
|
||||||
|
|
||||||
/// Wallet transport settings content.
|
/// Wallet transport settings content.
|
||||||
pub struct WalletTransportSettingsContent {
|
pub struct WalletTransportSettingsContent {
|
||||||
/// Flag to check if settings were changed to restart Tor service.
|
|
||||||
settings_changed: bool,
|
|
||||||
|
|
||||||
/// Tor transport content settings.
|
/// Tor transport content settings.
|
||||||
tor_settings_content: TorSettingsContent,
|
tor_settings_content: TorSettingsContent,
|
||||||
}
|
}
|
||||||
@@ -35,7 +31,6 @@ pub struct WalletTransportSettingsContent {
|
|||||||
impl Default for WalletTransportSettingsContent {
|
impl Default for WalletTransportSettingsContent {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
settings_changed: false,
|
|
||||||
tor_settings_content: TorSettingsContent::default(),
|
tor_settings_content: TorSettingsContent::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,18 +45,11 @@ impl WalletTransportSettingsContent {
|
|||||||
on_close: impl FnOnce()) {
|
on_close: impl FnOnce()) {
|
||||||
ui.add_space(8.0);
|
ui.add_space(8.0);
|
||||||
ui.vertical_centered(|ui| {
|
ui.vertical_centered(|ui| {
|
||||||
// Do not show bridges settings on Android.
|
// Show Tor settings.
|
||||||
let os = OperatingSystem::from_target_os();
|
self.tor_settings_content.ui(ui, cb);
|
||||||
if os != OperatingSystem::Android {
|
ui.add_space(4.0);
|
||||||
// Show Tor settings.
|
View::horizontal_line(ui, Colors::item_stroke());
|
||||||
self.tor_settings_content.ui(ui, cb);
|
ui.add_space(8.0);
|
||||||
if !self.tor_settings_content.settings_changed {
|
|
||||||
self.settings_changed = true;
|
|
||||||
}
|
|
||||||
ui.add_space(4.0);
|
|
||||||
View::horizontal_line(ui, Colors::item_stroke());
|
|
||||||
ui.add_space(8.0);
|
|
||||||
}
|
|
||||||
ui.label(RichText::new(t!("transport.tor_autorun_desc"))
|
ui.label(RichText::new(t!("transport.tor_autorun_desc"))
|
||||||
.size(17.0)
|
.size(17.0)
|
||||||
.color(Colors::inactive_text()));
|
.color(Colors::inactive_text()));
|
||||||
@@ -69,14 +57,12 @@ impl WalletTransportSettingsContent {
|
|||||||
let autorun = wallet.auto_start_tor_listener();
|
let autorun = wallet.auto_start_tor_listener();
|
||||||
View::checkbox(ui, autorun, t!("network.autorun"), || {
|
View::checkbox(ui, autorun, t!("network.autorun"), || {
|
||||||
wallet.update_auto_start_tor_listener(!autorun);
|
wallet.update_auto_start_tor_listener(!autorun);
|
||||||
self.settings_changed = true;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
ui.add_space(8.0);
|
ui.add_space(8.0);
|
||||||
ui.vertical_centered_justified(|ui| {
|
ui.vertical_centered_justified(|ui| {
|
||||||
View::button(ui, t!("close"), Colors::white_or_black(false), || {
|
View::button(ui, t!("close"), Colors::white_or_black(false), || {
|
||||||
if self.settings_changed {
|
if self.tor_settings_content.settings_changed {
|
||||||
self.settings_changed = false;
|
|
||||||
// Restart running service or rebuild client.
|
// Restart running service or rebuild client.
|
||||||
let service_id = &wallet.identifier();
|
let service_id = &wallet.identifier();
|
||||||
if Tor::is_service_running(service_id) {
|
if Tor::is_service_running(service_id) {
|
||||||
|
|||||||
+1
-1
@@ -52,7 +52,7 @@ fn android_main(app: AndroidApp) {
|
|||||||
{
|
{
|
||||||
std::env::set_var("RUST_BACKTRACE", "full");
|
std::env::set_var("RUST_BACKTRACE", "full");
|
||||||
let log_config = android_logger::Config::default()
|
let log_config = android_logger::Config::default()
|
||||||
.with_max_level(log::LevelFilter::Debug)
|
.with_max_level(log::LevelFilter::Info)
|
||||||
.with_tag("grim");
|
.with_tag("grim");
|
||||||
android_logger::init_once(log_config);
|
android_logger::init_once(log_config);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,16 +12,16 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use std::fs::{self, File};
|
use grin_config::ConfigError;
|
||||||
use std::io::Write;
|
use grin_core::global;
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use grin_config::ConfigError;
|
use std::fs::{self, File};
|
||||||
use grin_core::global;
|
use std::io::Write;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::node::NodeConfig;
|
use crate::node::NodeConfig;
|
||||||
use crate::settings::AppConfig;
|
use crate::settings::AppConfig;
|
||||||
@@ -61,7 +61,8 @@ impl Settings {
|
|||||||
|
|
||||||
// Initialize tor config.
|
// Initialize tor config.
|
||||||
let tor_config_path = Settings::config_path(TorConfig::FILE_NAME, None);
|
let tor_config_path = Settings::config_path(TorConfig::FILE_NAME, None);
|
||||||
let tor_config = Self::init_config::<TorConfig>(tor_config_path);
|
let mut tor_config = Self::init_config::<TorConfig>(tor_config_path);
|
||||||
|
tor_config.migrate();
|
||||||
|
|
||||||
// Setup chain type.
|
// Setup chain type.
|
||||||
let chain_type = &app_config.chain_type;
|
let chain_type = &app_config.chain_type;
|
||||||
@@ -183,10 +184,10 @@ impl Settings {
|
|||||||
match parsed {
|
match parsed {
|
||||||
Ok(cfg) => Ok(cfg),
|
Ok(cfg) => Ok(cfg),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Err(ConfigError::ParseError(
|
Err(ConfigError::ParseError(
|
||||||
config_path.to_str().unwrap().to_string(),
|
config_path.to_str().unwrap().to_string(),
|
||||||
format!("{}", e),
|
format!("{}", e),
|
||||||
));
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+75
-8
@@ -18,6 +18,8 @@ use serde_derive::{Deserialize, Serialize};
|
|||||||
use crate::Settings;
|
use crate::Settings;
|
||||||
use crate::tor::{TorBridge, TorProxy};
|
use crate::tor::{TorBridge, TorProxy};
|
||||||
|
|
||||||
|
const TOR_CONFIG_VERSION: i32 = 1;
|
||||||
|
|
||||||
/// Tor configuration.
|
/// Tor configuration.
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
pub struct TorConfig {
|
pub struct TorConfig {
|
||||||
@@ -30,19 +32,26 @@ pub struct TorConfig {
|
|||||||
|
|
||||||
/// Selected bridge type.
|
/// Selected bridge type.
|
||||||
bridge: Option<TorBridge>,
|
bridge: Option<TorBridge>,
|
||||||
|
/// Webtunnel bridge type.
|
||||||
|
webtunnel: TorBridge,
|
||||||
/// Obfs4 bridge type.
|
/// Obfs4 bridge type.
|
||||||
obfs4: TorBridge,
|
obfs4: TorBridge,
|
||||||
/// Snowflake bridge type.
|
/// Snowflake bridge type.
|
||||||
snowflake: TorBridge,
|
snowflake: TorBridge,
|
||||||
|
|
||||||
|
/// Config version.
|
||||||
|
ver: Option<i32>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TorConfig {
|
impl Default for TorConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
let webtunnel = Self::default_webtunnel_bridge();
|
||||||
Self {
|
Self {
|
||||||
proxy: None,
|
proxy: None,
|
||||||
proxy_socks5: TorProxy::HTTP(TorProxy::DEFAULT_SOCKS5_URL.to_string()),
|
proxy_socks5: TorProxy::HTTP(TorProxy::DEFAULT_SOCKS5_URL.to_string()),
|
||||||
proxy_http: TorProxy::HTTP(TorProxy::DEFAULT_HTTP_URL.to_string()),
|
proxy_http: TorProxy::HTTP(TorProxy::DEFAULT_HTTP_URL.to_string()),
|
||||||
bridge: None,
|
bridge: Some(webtunnel.clone()),
|
||||||
|
webtunnel,
|
||||||
obfs4: TorBridge::Obfs4(
|
obfs4: TorBridge::Obfs4(
|
||||||
TorBridge::DEFAULT_OBFS4_BIN_PATH.to_string(),
|
TorBridge::DEFAULT_OBFS4_BIN_PATH.to_string(),
|
||||||
TorBridge::DEFAULT_OBFS4_CONN_LINE.to_string()
|
TorBridge::DEFAULT_OBFS4_CONN_LINE.to_string()
|
||||||
@@ -51,6 +60,7 @@ impl Default for TorConfig {
|
|||||||
TorBridge::DEFAULT_SNOWFLAKE_BIN_PATH.to_string(),
|
TorBridge::DEFAULT_SNOWFLAKE_BIN_PATH.to_string(),
|
||||||
TorBridge::DEFAULT_SNOWFLAKE_CONN_LINE.to_string()
|
TorBridge::DEFAULT_SNOWFLAKE_CONN_LINE.to_string()
|
||||||
),
|
),
|
||||||
|
ver: Some(TOR_CONFIG_VERSION),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,14 +79,24 @@ impl TorConfig {
|
|||||||
/// Subdirectory name for Tor keystore.
|
/// Subdirectory name for Tor keystore.
|
||||||
const KEYSTORE_DIR: &'static str = "keystore";
|
const KEYSTORE_DIR: &'static str = "keystore";
|
||||||
|
|
||||||
|
/// Webtunnel binary name.
|
||||||
|
pub const WEBTUNNEL_BIN: &'static str = "webtunnel";
|
||||||
|
/// Webtunnel Android binary name.
|
||||||
|
pub const WEBTUNNEL_ANDROID_BIN: &'static str = "libwebtunnel.so";
|
||||||
|
|
||||||
/// Save application configuration to the file.
|
/// Save application configuration to the file.
|
||||||
pub fn save(&self) {
|
pub fn save(&self) {
|
||||||
Settings::write_to_file(self, Settings::config_path(Self::FILE_NAME, None));
|
Settings::write_to_file(self, Settings::config_path(Self::FILE_NAME, None));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get base Tor directory path.
|
||||||
|
fn base_path() -> PathBuf {
|
||||||
|
Settings::base_path(Some(Self::DIR_NAME.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
/// Get path from subdirectory name.
|
/// Get path from subdirectory name.
|
||||||
fn sub_dir_path(name: &str) -> String {
|
fn sub_dir_path(name: &str) -> String {
|
||||||
let mut base = Settings::base_path(Some(Self::DIR_NAME.to_string()));
|
let mut base = Self::base_path();
|
||||||
base.push(name);
|
base.push(name);
|
||||||
base.to_str().unwrap().to_string()
|
base.to_str().unwrap().to_string()
|
||||||
}
|
}
|
||||||
@@ -98,6 +118,31 @@ impl TorConfig {
|
|||||||
base.to_str().unwrap().to_string()
|
base.to_str().unwrap().to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get default webtunnel bridge.
|
||||||
|
pub fn default_webtunnel_bridge() -> TorBridge {
|
||||||
|
TorBridge::Webtunnel(
|
||||||
|
if egui::os::OperatingSystem::from_target_os() == egui::os::OperatingSystem::Android {
|
||||||
|
"".to_string()
|
||||||
|
} else {
|
||||||
|
TorConfig::webtunnel_path()
|
||||||
|
},
|
||||||
|
TorBridge::DEFAULT_WEBTUNNEL_CONN_LINE.to_string()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Webtunnel binary path.
|
||||||
|
pub fn webtunnel_path() -> String {
|
||||||
|
let os = egui::os::OperatingSystem::from_target_os();
|
||||||
|
if os == egui::os::OperatingSystem::Android {
|
||||||
|
let base = std::env::var("NATIVE_LIBS_DIR").unwrap_or_default();
|
||||||
|
format!("{}/{}", base, Self::WEBTUNNEL_ANDROID_BIN)
|
||||||
|
} else {
|
||||||
|
let mut base = Self::base_path();
|
||||||
|
base.push(Self::WEBTUNNEL_BIN);
|
||||||
|
base.to_str().unwrap().to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Save Tor bridge.
|
/// Save Tor bridge.
|
||||||
pub fn save_bridge(bridge: Option<TorBridge>) {
|
pub fn save_bridge(bridge: Option<TorBridge>) {
|
||||||
let mut w_tor_config = Settings::tor_config_to_update();
|
let mut w_tor_config = Settings::tor_config_to_update();
|
||||||
@@ -105,12 +150,15 @@ impl TorConfig {
|
|||||||
if bridge.is_some() {
|
if bridge.is_some() {
|
||||||
let bridge = bridge.unwrap();
|
let bridge = bridge.unwrap();
|
||||||
match &bridge {
|
match &bridge {
|
||||||
TorBridge::Snowflake(_, _) => {
|
TorBridge::Webtunnel(_, _) => {
|
||||||
w_tor_config.snowflake = bridge
|
w_tor_config.webtunnel = bridge
|
||||||
}
|
}
|
||||||
TorBridge::Obfs4(_, _) => {
|
TorBridge::Obfs4(_, _) => {
|
||||||
w_tor_config.obfs4 = bridge
|
w_tor_config.obfs4 = bridge
|
||||||
}
|
}
|
||||||
|
TorBridge::Snowflake(_, _) => {
|
||||||
|
w_tor_config.snowflake = bridge
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w_tor_config.save();
|
w_tor_config.save();
|
||||||
@@ -122,6 +170,12 @@ impl TorConfig {
|
|||||||
r_config.bridge.clone()
|
r_config.bridge.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get saved Webtunnel bridge.
|
||||||
|
pub fn get_webtunnel() -> TorBridge {
|
||||||
|
let r_config = Settings::tor_config_to_read();
|
||||||
|
r_config.webtunnel.clone()
|
||||||
|
}
|
||||||
|
|
||||||
/// Get saved Obfs4 bridge.
|
/// Get saved Obfs4 bridge.
|
||||||
pub fn get_obfs4() -> TorBridge {
|
pub fn get_obfs4() -> TorBridge {
|
||||||
let r_config = Settings::tor_config_to_read();
|
let r_config = Settings::tor_config_to_read();
|
||||||
@@ -168,4 +222,17 @@ impl TorConfig {
|
|||||||
let r_config = Settings::tor_config_to_read();
|
let r_config = Settings::tor_config_to_read();
|
||||||
r_config.proxy_http.clone()
|
r_config.proxy_http.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check config version to migrate if needed.
|
||||||
|
pub fn migrate(&mut self) {
|
||||||
|
match self.ver {
|
||||||
|
None => {
|
||||||
|
// Migrate to 1st version.
|
||||||
|
self.bridge = Some(TorConfig::default_webtunnel_bridge());
|
||||||
|
self.ver = Some(1);
|
||||||
|
}
|
||||||
|
Some(_) => {}
|
||||||
|
}
|
||||||
|
self.save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+147
-109
@@ -50,7 +50,7 @@ use tor_rtcompat::Runtime;
|
|||||||
|
|
||||||
use crate::http::HttpClient;
|
use crate::http::HttpClient;
|
||||||
use crate::tor::http::ArtiHttpConnector;
|
use crate::tor::http::ArtiHttpConnector;
|
||||||
use crate::tor::{TorConfig, TorProxy};
|
use crate::tor::{TorBridge, TorConfig, TorProxy};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
/// Static thread-aware state of [`Node`] to be updated from separate thread.
|
/// Static thread-aware state of [`Node`] to be updated from separate thread.
|
||||||
@@ -62,34 +62,37 @@ pub struct Tor {
|
|||||||
/// Tor client and config.
|
/// Tor client and config.
|
||||||
client_config: Arc<RwLock<(TorClient<TokioNativeTlsRuntime>, TorClientConfig)>>,
|
client_config: Arc<RwLock<(TorClient<TokioNativeTlsRuntime>, TorClientConfig)>>,
|
||||||
/// Mapping of running Onion services identifiers to proxy.
|
/// Mapping of running Onion services identifiers to proxy.
|
||||||
running_services:
|
run: Arc<RwLock<BTreeMap<String, (Arc<RunningOnionService>, Arc<OnionServiceReverseProxy>)>>>,
|
||||||
Arc<RwLock<BTreeMap<String, (Arc<RunningOnionService>, Arc<OnionServiceReverseProxy>)>>>,
|
|
||||||
/// Starting Onion services identifiers.
|
/// Starting Onion services identifiers.
|
||||||
starting_services: Arc<RwLock<BTreeSet<String>>>,
|
start: Arc<RwLock<BTreeSet<String>>>,
|
||||||
/// Failed Onion services identifiers.
|
/// Failed Onion services identifiers.
|
||||||
failed_services: Arc<RwLock<BTreeSet<String>>>,
|
fail: Arc<RwLock<BTreeSet<String>>>,
|
||||||
/// Checking Onion services identifiers.
|
/// Checking Onion services identifiers.
|
||||||
checking_services: Arc<RwLock<BTreeSet<String>>>,
|
check: Arc<RwLock<BTreeSet<String>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Tor {
|
impl Default for Tor {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
// Cleanup keys, state and cache on start.
|
// Extract webtunnel bridge binary.
|
||||||
fs::remove_dir_all(TorConfig::keystore_path()).unwrap_or_default();
|
if !fs::exists(TorConfig::webtunnel_path()).unwrap_or(true) {
|
||||||
fs::remove_dir_all(TorConfig::state_path()).unwrap_or_default();
|
let webtunnel = include_bytes!(concat!(env!("OUT_DIR"), "/tor/webtunnel"));
|
||||||
fs::remove_dir_all(TorConfig::cache_path()).unwrap_or_default();
|
if !webtunnel.is_empty() {
|
||||||
|
fs::write(TorConfig::webtunnel_path(), webtunnel).unwrap_or_default();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create Tor client.
|
// Create Tor client.
|
||||||
let runtime = TokioNativeTlsRuntime::create().unwrap();
|
let runtime = TokioNativeTlsRuntime::create().unwrap();
|
||||||
let config = Self::build_config();
|
let config = Self::build_config(true);
|
||||||
let client = TorClient::with_runtime(runtime)
|
let client = TorClient::with_runtime(runtime)
|
||||||
.config(config.clone())
|
.config(config.clone())
|
||||||
.create_unbootstrapped()
|
.create_unbootstrapped()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
Self {
|
Self {
|
||||||
running_services: Arc::new(RwLock::new(BTreeMap::new())),
|
run: Arc::new(RwLock::new(BTreeMap::new())),
|
||||||
starting_services: Arc::new(RwLock::new(BTreeSet::new())),
|
start: Arc::new(RwLock::new(BTreeSet::new())),
|
||||||
failed_services: Arc::new(RwLock::new(BTreeSet::new())),
|
fail: Arc::new(RwLock::new(BTreeSet::new())),
|
||||||
checking_services: Arc::new(RwLock::new(BTreeSet::new())),
|
check: Arc::new(RwLock::new(BTreeSet::new())),
|
||||||
client_config: Arc::new(RwLock::new((client, config))),
|
client_config: Arc::new(RwLock::new((client, config))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,7 +100,13 @@ impl Default for Tor {
|
|||||||
|
|
||||||
impl Tor {
|
impl Tor {
|
||||||
/// Create Tor client configuration.
|
/// Create Tor client configuration.
|
||||||
fn build_config() -> TorClientConfig {
|
fn build_config(clean: bool) -> TorClientConfig {
|
||||||
|
// Cleanup keys, state and cache.
|
||||||
|
if clean {
|
||||||
|
fs::remove_dir_all(TorConfig::keystore_path()).unwrap_or_default();
|
||||||
|
fs::remove_dir_all(TorConfig::state_path()).unwrap_or_default();
|
||||||
|
fs::remove_dir_all(TorConfig::cache_path()).unwrap_or_default();
|
||||||
|
}
|
||||||
// Create Tor client config.
|
// Create Tor client config.
|
||||||
let mut builder = TorClientConfigBuilder::from_directories(
|
let mut builder = TorClientConfigBuilder::from_directories(
|
||||||
TorConfig::state_path(),
|
TorConfig::state_path(),
|
||||||
@@ -107,12 +116,7 @@ impl Tor {
|
|||||||
// Setup bridges.
|
// Setup bridges.
|
||||||
let bridge = TorConfig::get_bridge();
|
let bridge = TorConfig::get_bridge();
|
||||||
if let Some(b) = bridge {
|
if let Some(b) = bridge {
|
||||||
match b {
|
Self::build_bridge(&mut builder, b);
|
||||||
super::TorBridge::Snowflake(path, conn) => {
|
|
||||||
Self::build_snowflake(&mut builder, path, conn)
|
|
||||||
}
|
|
||||||
super::TorBridge::Obfs4(path, conn) => Self::build_obfs4(&mut builder, path, conn),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Create config.
|
// Create config.
|
||||||
let config = builder.build().unwrap();
|
let config = builder.build().unwrap();
|
||||||
@@ -121,7 +125,7 @@ impl Tor {
|
|||||||
|
|
||||||
/// Recreate Tor client with configuration.
|
/// Recreate Tor client with configuration.
|
||||||
pub fn rebuild_client() {
|
pub fn rebuild_client() {
|
||||||
let config = Self::build_config();
|
let config = Self::build_config(false);
|
||||||
let r_client = TOR_SERVER_STATE.client_config.read();
|
let r_client = TOR_SERVER_STATE.client_config.read();
|
||||||
r_client.0
|
r_client.0
|
||||||
.reconfigure(&config, tor_config::Reconfigure::AllOrNothing)
|
.reconfigure(&config, tor_config::Reconfigure::AllOrNothing)
|
||||||
@@ -193,25 +197,25 @@ impl Tor {
|
|||||||
|
|
||||||
/// Check if Onion service is starting.
|
/// Check if Onion service is starting.
|
||||||
pub fn is_service_starting(id: &String) -> bool {
|
pub fn is_service_starting(id: &String) -> bool {
|
||||||
let r_services = TOR_SERVER_STATE.starting_services.read();
|
let r_services = TOR_SERVER_STATE.start.read();
|
||||||
r_services.contains(id)
|
r_services.contains(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if Onion service is running.
|
/// Check if Onion service is running.
|
||||||
pub fn is_service_running(id: &String) -> bool {
|
pub fn is_service_running(id: &String) -> bool {
|
||||||
let r_services = TOR_SERVER_STATE.running_services.read();
|
let r_services = TOR_SERVER_STATE.run.read();
|
||||||
r_services.contains_key(id)
|
r_services.contains_key(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if Onion service failed on start.
|
/// Check if Onion service failed on start.
|
||||||
pub fn is_service_failed(id: &String) -> bool {
|
pub fn is_service_failed(id: &String) -> bool {
|
||||||
let r_services = TOR_SERVER_STATE.failed_services.read();
|
let r_services = TOR_SERVER_STATE.fail.read();
|
||||||
r_services.contains(id)
|
r_services.contains(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if Onion service is checking.
|
/// Check if Onion service is checking.
|
||||||
pub fn is_service_checking(id: &String) -> bool {
|
pub fn is_service_checking(id: &String) -> bool {
|
||||||
let r_services = TOR_SERVER_STATE.checking_services.read();
|
let r_services = TOR_SERVER_STATE.check.read();
|
||||||
r_services.contains(id)
|
r_services.contains(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,7 +228,7 @@ impl Tor {
|
|||||||
|
|
||||||
/// Stop running Onion service.
|
/// Stop running Onion service.
|
||||||
pub fn stop_service(id: &String) {
|
pub fn stop_service(id: &String) {
|
||||||
let mut w_services = TOR_SERVER_STATE.running_services.write();
|
let mut w_services = TOR_SERVER_STATE.run.write();
|
||||||
if let Some((svc, proxy)) = w_services.remove(id) {
|
if let Some((svc, proxy)) = w_services.remove(id) {
|
||||||
proxy.shutdown();
|
proxy.shutdown();
|
||||||
drop(svc);
|
drop(svc);
|
||||||
@@ -238,10 +242,10 @@ impl Tor {
|
|||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// Save starting service.
|
// Save starting service.
|
||||||
let mut w_services = TOR_SERVER_STATE.starting_services.write();
|
let mut w_services = TOR_SERVER_STATE.start.write();
|
||||||
w_services.insert(id.clone());
|
w_services.insert(id.clone());
|
||||||
// Remove service from failed.
|
// Remove service from failed.
|
||||||
let mut w_services = TOR_SERVER_STATE.failed_services.write();
|
let mut w_services = TOR_SERVER_STATE.fail.write();
|
||||||
w_services.remove(id);
|
w_services.remove(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,13 +253,32 @@ impl Tor {
|
|||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let on_error = |service_id: String| {
|
let on_error = |service_id: String| {
|
||||||
// Remove service from starting.
|
// Remove service from starting.
|
||||||
let mut w_services = TOR_SERVER_STATE.starting_services.write();
|
let mut w_services = TOR_SERVER_STATE.start.write();
|
||||||
w_services.remove(&service_id);
|
w_services.remove(&service_id);
|
||||||
// Save failed service.
|
// Save failed service.
|
||||||
let mut w_services = TOR_SERVER_STATE.failed_services.write();
|
let mut w_services = TOR_SERVER_STATE.fail.write();
|
||||||
w_services.insert(service_id);
|
w_services.insert(service_id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Check bridge binary existence and permissions.
|
||||||
|
if let Some(bridge) = TorConfig::get_bridge() {
|
||||||
|
if !fs::exists(bridge.binary_path()).unwrap() {
|
||||||
|
on_error(service_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Add execute permission for Unix.
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
use std::os::unix::fs::PermissionsExt;
|
||||||
|
let mut perms = fs::metadata(bridge.binary_path())
|
||||||
|
.unwrap()
|
||||||
|
.permissions();
|
||||||
|
let mode = perms.mode() | 0o100;
|
||||||
|
perms.set_mode(mode);
|
||||||
|
fs::set_permissions(bridge.binary_path(), perms).unwrap_or_default();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let (client, config) = Self::client_config();
|
let (client, config) = Self::client_config();
|
||||||
let client_thread = client.clone();
|
let client_thread = client.clone();
|
||||||
client
|
client
|
||||||
@@ -263,13 +286,15 @@ impl Tor {
|
|||||||
.spawn(async move {
|
.spawn(async move {
|
||||||
// Add service key to keystore.
|
// Add service key to keystore.
|
||||||
let hs_nickname = HsNickname::new(service_id.clone()).unwrap();
|
let hs_nickname = HsNickname::new(service_id.clone()).unwrap();
|
||||||
if let Err(_) = Self::add_service_key(config.fs_mistrust(), &key, &hs_nickname)
|
if let Err(_) = Self::add_service_key(config.fs_mistrust(), &key, &hs_nickname) {
|
||||||
{
|
|
||||||
on_error(service_id);
|
on_error(service_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Bootstrap client.
|
// Bootstrap client.
|
||||||
client_thread.bootstrap().await.unwrap();
|
if let Err(_) = client_thread.bootstrap().await {
|
||||||
|
on_error(service_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Launch Onion service.
|
// Launch Onion service.
|
||||||
let service_config = OnionServiceConfigBuilder::default()
|
let service_config = OnionServiceConfigBuilder::default()
|
||||||
.nickname(hs_nickname.clone())
|
.nickname(hs_nickname.clone())
|
||||||
@@ -313,25 +338,23 @@ impl Tor {
|
|||||||
}
|
}
|
||||||
let client_check = client.clone();
|
let client_check = client.clone();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
// Wait 1 second to start.
|
// Wait 5 seconds to start.
|
||||||
thread::sleep(Duration::from_millis(1000));
|
thread::sleep(Duration::from_millis(5000));
|
||||||
let runtime = client.runtime();
|
let runtime = client.runtime();
|
||||||
// Put service to checking.
|
// Put service to checking.
|
||||||
{
|
{
|
||||||
let mut w_services = TOR_SERVER_STATE.checking_services.write();
|
let mut w_services = TOR_SERVER_STATE.check.write();
|
||||||
w_services.insert(service_id.clone());
|
w_services.insert(service_id.clone());
|
||||||
}
|
}
|
||||||
runtime
|
runtime
|
||||||
.spawn(async move {
|
.spawn(async move {
|
||||||
let tls_conn =
|
let tls_conn = TlsConnector::builder().unwrap().build().unwrap();
|
||||||
TlsConnector::builder().unwrap().build().unwrap();
|
let tor_conn = ArtiHttpConnector::new(client_check.clone(), tls_conn);
|
||||||
let tor_conn =
|
let http = hyper_tor::Client::builder().build::<_, hyper_tor::Body>(tor_conn);
|
||||||
ArtiHttpConnector::new(client_check.clone(), tls_conn);
|
|
||||||
let http =
|
|
||||||
hyper_tor::Client::builder().build::<_, hyper_tor::Body>(tor_conn);
|
|
||||||
|
|
||||||
const MAX_ERRORS: i32 = 3;
|
const MAX_ERRORS: i32 = 3;
|
||||||
let mut errors_count = 0;
|
let mut errors_count = 0;
|
||||||
|
let mut first_start = true;
|
||||||
loop {
|
loop {
|
||||||
// Check if service is running.
|
// Check if service is running.
|
||||||
fn is_running(service_id: &String) -> bool {
|
fn is_running(service_id: &String) -> bool {
|
||||||
@@ -339,7 +362,7 @@ impl Tor {
|
|||||||
if !running {
|
if !running {
|
||||||
// Remove service from checking.
|
// Remove service from checking.
|
||||||
let mut w_services =
|
let mut w_services =
|
||||||
TOR_SERVER_STATE.checking_services.write();
|
TOR_SERVER_STATE.check.write();
|
||||||
w_services.remove(service_id);
|
w_services.remove(service_id);
|
||||||
}
|
}
|
||||||
running
|
running
|
||||||
@@ -347,45 +370,75 @@ impl Tor {
|
|||||||
if !is_running(&service_id) {
|
if !is_running(&service_id) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Send request.
|
// Put service to starting.
|
||||||
let duration = match http
|
if first_start {
|
||||||
.get(hyper_tor::Uri::from_str(url.clone().as_str()).unwrap())
|
{
|
||||||
.await
|
let mut w_services = TOR_SERVER_STATE.start.write();
|
||||||
{
|
w_services.insert(service_id.clone());
|
||||||
Ok(_) => {
|
|
||||||
// Remove service from starting.
|
|
||||||
let mut w_services =
|
|
||||||
TOR_SERVER_STATE.starting_services.write();
|
|
||||||
w_services.remove(&service_id);
|
|
||||||
// Remove service from failed.
|
|
||||||
let mut w_services =
|
|
||||||
TOR_SERVER_STATE.failed_services.write();
|
|
||||||
w_services.remove(&service_id);
|
|
||||||
if !is_running(&service_id) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Check again after 50 seconds.
|
|
||||||
Duration::from_millis(50000)
|
|
||||||
}
|
}
|
||||||
Err(_) => {
|
}
|
||||||
if !is_running(&service_id) {
|
// Send request.
|
||||||
break;
|
let duration = {
|
||||||
|
let uri = hyper_tor::Uri::from_str(url.clone().as_str()).unwrap();
|
||||||
|
let check = http.get(uri);
|
||||||
|
let mut on_error = |service_id: &String| -> bool {
|
||||||
|
if !is_running(service_id) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
// Restart service on 3rd error.
|
// Restart service on 3rd error.
|
||||||
errors_count += 1;
|
errors_count += 1;
|
||||||
if errors_count == MAX_ERRORS {
|
if errors_count == MAX_ERRORS {
|
||||||
errors_count = 0;
|
// Remove service from checking.
|
||||||
|
let mut w_services =
|
||||||
|
TOR_SERVER_STATE.check.write();
|
||||||
|
w_services.remove(service_id);
|
||||||
|
// Remove service from starting.
|
||||||
|
let mut w_services = TOR_SERVER_STATE.start.write();
|
||||||
|
w_services.remove(service_id);
|
||||||
|
// Restart service.
|
||||||
let key = key.clone();
|
let key = key.clone();
|
||||||
let service_id = service_id.clone();
|
let id = service_id.clone();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
Self::restart_service(
|
Self::restart_service(port, key, &id);
|
||||||
port,
|
|
||||||
key,
|
|
||||||
&service_id,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
};
|
||||||
|
// Check with timeout of 30s.
|
||||||
|
match tokio::time::timeout(Duration::from_millis(30000), check).await {
|
||||||
|
Ok(resp) => {
|
||||||
|
match resp {
|
||||||
|
Ok(_) => {
|
||||||
|
if !is_running(&service_id) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Remove service from starting.
|
||||||
|
if first_start {
|
||||||
|
let mut w_services = TOR_SERVER_STATE.start.write();
|
||||||
|
w_services.remove(&service_id);
|
||||||
|
first_start = false;
|
||||||
|
}
|
||||||
|
errors_count = 0;
|
||||||
|
// Check again after 60s.
|
||||||
|
Duration::from_millis(60000)
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
if on_error(&service_id) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Check again after 10s.
|
||||||
|
Duration::from_millis(10000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
if on_error(&service_id) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Check again after 10s.
|
||||||
|
Duration::from_millis(10000)
|
||||||
}
|
}
|
||||||
Duration::from_millis(5000)
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Wait to check service again.
|
// Wait to check service again.
|
||||||
@@ -419,30 +472,32 @@ impl Tor {
|
|||||||
proxy_cfg_builder.set_proxy_ports(vec![proxy_rule]);
|
proxy_cfg_builder.set_proxy_ports(vec![proxy_rule]);
|
||||||
let proxy = OnionServiceReverseProxy::new(proxy_cfg_builder.build().unwrap());
|
let proxy = OnionServiceReverseProxy::new(proxy_cfg_builder.build().unwrap());
|
||||||
|
|
||||||
|
// Remove service from failed.
|
||||||
|
let mut w_services = TOR_SERVER_STATE.fail.write();
|
||||||
|
w_services.remove(&id);
|
||||||
// Save running service.
|
// Save running service.
|
||||||
let mut w_services = TOR_SERVER_STATE.running_services.write();
|
let mut w_services = TOR_SERVER_STATE.run.write();
|
||||||
w_services.insert(id.clone(), (service.clone(), proxy.clone()));
|
w_services.insert(id.clone(), (service.clone(), proxy.clone()));
|
||||||
|
|
||||||
// Start proxy for launched service.
|
// Start proxy for launched service.
|
||||||
client
|
client
|
||||||
.runtime()
|
.runtime()
|
||||||
.spawn(async move {
|
.spawn(async move {
|
||||||
match proxy
|
match proxy.handle_requests(runtime, nickname.clone(), request).await {
|
||||||
.handle_requests(runtime, nickname.clone(), request)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
// Remove service from running.
|
// Remove service from running.
|
||||||
let mut w_services = TOR_SERVER_STATE.running_services.write();
|
let mut w_services = TOR_SERVER_STATE.run.write();
|
||||||
w_services.remove(&id);
|
w_services.remove(&id);
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
// Remove service from running.
|
if Self::is_service_running(&id) {
|
||||||
let mut w_services = TOR_SERVER_STATE.running_services.write();
|
// Remove service from running.
|
||||||
w_services.remove(&id);
|
let mut w_services = TOR_SERVER_STATE.run.write();
|
||||||
// Save failed service.
|
w_services.remove(&id);
|
||||||
let mut w_services = TOR_SERVER_STATE.failed_services.write();
|
// Save failed service.
|
||||||
w_services.insert(id);
|
let mut w_services = TOR_SERVER_STATE.fail.write();
|
||||||
|
w_services.insert(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -487,36 +542,19 @@ impl Tor {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_snowflake(builder: &mut TorClientConfigBuilder, bin_path: String, conn_line: String) {
|
fn build_bridge(builder: &mut TorClientConfigBuilder, bridge: TorBridge) {
|
||||||
let bridge_line = format!("Bridge {}", conn_line);
|
let bridge_line = format!("Bridge {}", bridge.connection_line());
|
||||||
if let Ok(bridge) = bridge_line.parse() {
|
if let Ok(bridge) = bridge_line.parse() {
|
||||||
builder.bridges().bridges().push(bridge);
|
builder.bridges().bridges().push(bridge);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now configure a snowflake transport. (Requires the "pt-client" feature)
|
// Now configure bridge transport. (Requires the "pt-client" feature)
|
||||||
let mut transport = TransportConfigBuilder::default();
|
let mut transport = TransportConfigBuilder::default();
|
||||||
transport
|
transport
|
||||||
.protocols(vec!["snowflake".parse().unwrap()])
|
.protocols(vec![bridge.protocol_name().parse().unwrap()])
|
||||||
// this might be named differently on some systems, this should work on Debian,
|
|
||||||
// but Archlinux is known to use `snowflake-pt-client` instead for instance.
|
|
||||||
.path(CfgPath::new(bin_path.into()))
|
|
||||||
.run_on_startup(true);
|
|
||||||
builder.bridges().set_transports(vec![transport]);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_obfs4(builder: &mut TorClientConfigBuilder, bin_path: String, conn_line: String) {
|
|
||||||
let bridge_line = format!("Bridge {}", conn_line);
|
|
||||||
if let Ok(bridge) = bridge_line.parse() {
|
|
||||||
builder.bridges().bridges().push(bridge);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now configure an obfs4 transport. (Requires the "pt-client" feature)
|
|
||||||
let mut transport = TransportConfigBuilder::default();
|
|
||||||
transport
|
|
||||||
.protocols(vec!["obfs4".parse().unwrap()])
|
|
||||||
// Specify either the name or the absolute path of pluggable transport client binary,
|
// Specify either the name or the absolute path of pluggable transport client binary,
|
||||||
// this may differ from system to system.
|
// this may differ from system to system.
|
||||||
.path(CfgPath::new(bin_path.into()))
|
.path(CfgPath::new(bridge.binary_path().into()))
|
||||||
.run_on_startup(true);
|
.run_on_startup(true);
|
||||||
builder.bridges().transports().push(transport);
|
builder.bridges().transports().push(transport);
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-1
@@ -12,6 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use egui::os;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use crate::tor::TorConfig;
|
use crate::tor::TorConfig;
|
||||||
|
|
||||||
@@ -42,6 +43,8 @@ impl TorProxy {
|
|||||||
/// Tor network bridge type.
|
/// Tor network bridge type.
|
||||||
#[derive(Serialize, Deserialize, Clone, PartialEq)]
|
#[derive(Serialize, Deserialize, Clone, PartialEq)]
|
||||||
pub enum TorBridge {
|
pub enum TorBridge {
|
||||||
|
/// Obfs4 bridge with binary path and connection line.
|
||||||
|
Webtunnel(String, String),
|
||||||
/// Obfs4 bridge with binary path and connection line.
|
/// Obfs4 bridge with binary path and connection line.
|
||||||
Obfs4(String, String),
|
Obfs4(String, String),
|
||||||
/// Snowflake bridge with binary path and connection line.
|
/// Snowflake bridge with binary path and connection line.
|
||||||
@@ -54,6 +57,8 @@ impl TorBridge {
|
|||||||
/// Default Snowflake protocol client binary path.
|
/// Default Snowflake protocol client binary path.
|
||||||
pub const DEFAULT_SNOWFLAKE_BIN_PATH: &'static str = "/usr/bin/snowflake-client";
|
pub const DEFAULT_SNOWFLAKE_BIN_PATH: &'static str = "/usr/bin/snowflake-client";
|
||||||
|
|
||||||
|
/// Default webtunnel protocol connection line.
|
||||||
|
pub const DEFAULT_WEBTUNNEL_CONN_LINE: &'static str = "webtunnel [2001:db8:beb:5884:ffcc:bfe3:2858:b06b]:443 1E242C749707B4A68A269F0D31311CE36CDFEC28 url=https://wt.gri.mw/74Fm0lKUWWMMjZpKf6iSC0UH";
|
||||||
/// Default Obfs4 protocol connection line.
|
/// Default Obfs4 protocol connection line.
|
||||||
pub const DEFAULT_OBFS4_CONN_LINE: &'static str = "obfs4 45.76.43.226:3479 7AAFDC594147E72635DD64DB47A8CD8781F463F6 cert=bJ720bjXkmFGGAD77BsCMopkDzQ/cXDj0QntOmsBYw7Fqohq7Y7yZMV7FlECQNB1tyq1AA iat-mode=0";
|
pub const DEFAULT_OBFS4_CONN_LINE: &'static str = "obfs4 45.76.43.226:3479 7AAFDC594147E72635DD64DB47A8CD8781F463F6 cert=bJ720bjXkmFGGAD77BsCMopkDzQ/cXDj0QntOmsBYw7Fqohq7Y7yZMV7FlECQNB1tyq1AA iat-mode=0";
|
||||||
/// Default Snowflake protocol connection line.
|
/// Default Snowflake protocol connection line.
|
||||||
@@ -62,14 +67,21 @@ impl TorBridge {
|
|||||||
/// Get bridge protocol name.
|
/// Get bridge protocol name.
|
||||||
pub fn protocol_name(&self) -> String {
|
pub fn protocol_name(&self) -> String {
|
||||||
match *self {
|
match *self {
|
||||||
|
TorBridge::Webtunnel(_, _) => "webtunnel".to_string(),
|
||||||
TorBridge::Obfs4(_, _) => "obfs4".to_string(),
|
TorBridge::Obfs4(_, _) => "obfs4".to_string(),
|
||||||
TorBridge::Snowflake(_, _) => "snowflake".to_string()
|
TorBridge::Snowflake(_, _) => "snowflake".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get bridge client binary path.
|
/// Get bridge client binary path.
|
||||||
pub fn binary_path(&self) -> String {
|
pub fn binary_path(&self) -> String {
|
||||||
|
let is_android = os::OperatingSystem::from_target_os() == os::OperatingSystem::Android;
|
||||||
match self {
|
match self {
|
||||||
|
TorBridge::Webtunnel(path, _) => if is_android {
|
||||||
|
TorConfig::webtunnel_path()
|
||||||
|
} else {
|
||||||
|
path.clone()
|
||||||
|
},
|
||||||
TorBridge::Obfs4(path, _) => path.clone(),
|
TorBridge::Obfs4(path, _) => path.clone(),
|
||||||
TorBridge::Snowflake(path, _) => path.clone()
|
TorBridge::Snowflake(path, _) => path.clone()
|
||||||
}
|
}
|
||||||
@@ -78,6 +90,7 @@ impl TorBridge {
|
|||||||
/// Get bridge client connection line.
|
/// Get bridge client connection line.
|
||||||
pub fn connection_line(&self) -> String {
|
pub fn connection_line(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
|
TorBridge::Webtunnel(_, line) => line.clone(),
|
||||||
TorBridge::Obfs4(_, line) => line.clone(),
|
TorBridge::Obfs4(_, line) => line.clone(),
|
||||||
TorBridge::Snowflake(_, line) => line.clone()
|
TorBridge::Snowflake(_, line) => line.clone()
|
||||||
}
|
}
|
||||||
@@ -86,6 +99,9 @@ impl TorBridge {
|
|||||||
/// Save binary path to provided bridge.
|
/// Save binary path to provided bridge.
|
||||||
pub fn save_bridge_bin_path(bridge: &TorBridge, path: String) {
|
pub fn save_bridge_bin_path(bridge: &TorBridge, path: String) {
|
||||||
match bridge {
|
match bridge {
|
||||||
|
TorBridge::Webtunnel(_, line) => {
|
||||||
|
TorConfig::save_bridge(Some(TorBridge::Webtunnel(path, line.into())));
|
||||||
|
}
|
||||||
TorBridge::Obfs4(_, line) => {
|
TorBridge::Obfs4(_, line) => {
|
||||||
TorConfig::save_bridge(Some(TorBridge::Obfs4(path, line.into())));
|
TorConfig::save_bridge(Some(TorBridge::Obfs4(path, line.into())));
|
||||||
}
|
}
|
||||||
@@ -98,6 +114,9 @@ impl TorBridge {
|
|||||||
/// Save connection line to provided bridge.
|
/// Save connection line to provided bridge.
|
||||||
pub fn save_bridge_conn_line(bridge: &TorBridge, line: String) {
|
pub fn save_bridge_conn_line(bridge: &TorBridge, line: String) {
|
||||||
match bridge {
|
match bridge {
|
||||||
|
TorBridge::Webtunnel(path, _) => {
|
||||||
|
TorConfig::save_bridge(Some(TorBridge::Webtunnel(path.into(), line)));
|
||||||
|
}
|
||||||
TorBridge::Obfs4(path, _) => {
|
TorBridge::Obfs4(path, _) => {
|
||||||
TorConfig::save_bridge(
|
TorConfig::save_bridge(
|
||||||
Some(TorBridge::Obfs4(path.into(), line))
|
Some(TorBridge::Obfs4(path.into(), line))
|
||||||
|
|||||||
Submodule
+1
Submodule tor/webtunnel added at 8814d4ef97
+1
-1
Submodule wallet updated: 5c5d149274...c51433d02b
Reference in New Issue
Block a user