mirror of
https://code.gri.mw/GUI/grim.git
synced 2026-07-04 05:57:29 +00:00
build + tor: update grin libs fix android build, add arti lib, tor server config, connection with snowflake, transport at connections
This commit is contained in:
Generated
+2994
-242
File diff suppressed because it is too large
Load Diff
+26
-17
@@ -16,21 +16,21 @@ log = "0.4"
|
||||
|
||||
## node
|
||||
openssl-sys = { version = "0.9.82", features = ["vendored"] }
|
||||
grin_api = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
grin_chain = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
grin_config = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
grin_core = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
grin_p2p = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
grin_servers = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
grin_keychain = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
grin_util = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
grin_api = "5.3.0"
|
||||
grin_chain = "5.3.0"
|
||||
grin_config = "5.3.0"
|
||||
grin_core = "5.3.0"
|
||||
grin_p2p = "5.3.0"
|
||||
grin_servers = "5.3.0"
|
||||
grin_keychain = "5.3.0"
|
||||
grin_util = "5.3.0"
|
||||
|
||||
## wallet
|
||||
grin_wallet_impls = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" }
|
||||
grin_wallet_api = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" }
|
||||
grin_wallet_libwallet = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" }
|
||||
grin_wallet_util = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" }
|
||||
grin_wallet_controller = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" }
|
||||
grin_wallet_impls = "5.3.0"
|
||||
grin_wallet_api = "5.3.0"
|
||||
grin_wallet_libwallet = "5.3.0"
|
||||
grin_wallet_util = "5.3.0"
|
||||
grin_wallet_controller = "5.3.0"
|
||||
|
||||
## ui
|
||||
egui = { version = "0.27.2", default-features = false }
|
||||
@@ -38,6 +38,7 @@ egui_extras = { version = "0.27.2", features = ["image"] }
|
||||
rust-i18n = "2.3.1"
|
||||
|
||||
## other
|
||||
anyhow = "1.0.75"
|
||||
thiserror = "1.0.58"
|
||||
futures = "0.3"
|
||||
dirs = "5.0.1"
|
||||
@@ -48,13 +49,20 @@ toml = "0.8.2"
|
||||
serde = "1.0.170"
|
||||
local-ip-address = "0.6.1"
|
||||
url = "2.4.0"
|
||||
|
||||
## stratum server
|
||||
rand = "0.8.5"
|
||||
serde_derive = "1.0.197"
|
||||
serde_json = "1.0.115"
|
||||
tokio = {version = "1.29.1", features = ["full"] }
|
||||
tokio = { version = "1.37.0", features = ["full"] }
|
||||
|
||||
## tor
|
||||
arti = { version = "1.2.0", features = ["experimental-api", "pt-client", "static"] }
|
||||
arti-client = { version = "0.17.0", features = ["experimental-api", "pt-client", "static"] }
|
||||
tor-rtcompat = { version = "0.17.0", features = ["static"] }
|
||||
tor-config = "0.17.0"
|
||||
fs-mistrust = "0.7.9"
|
||||
|
||||
## stratum server
|
||||
tokio-util = { version = "0.7.8", features = ["codec"] }
|
||||
rand = "0.8.5"
|
||||
|
||||
[build-dependencies]
|
||||
built = { version = "0.7.0", features = ["git2"]}
|
||||
@@ -70,5 +78,6 @@ image = "0.25.1"
|
||||
android_logger = "0.13.1"
|
||||
jni = "0.21.1"
|
||||
android-activity = "0.5.2"
|
||||
wgpu = "0.19"
|
||||
winit = { version = "0.29", features = [ "android-game-activity" ] }
|
||||
eframe = { version = "0.27.2", features = [ "wgpu", "android-game-activity" ] }
|
||||
@@ -40,6 +40,7 @@ public class MainActivity extends GameActivity {
|
||||
try {
|
||||
Os.setenv("HOME", getExternalFilesDir("").getPath(), true);
|
||||
Os.setenv("XDG_CACHE_HOME", getExternalCacheDir().getPath(), true);
|
||||
Os.setenv("ARTI_FS_DISABLE_PERMISSION_CHECKS", "true", true);
|
||||
} catch (ErrnoException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
@@ -126,6 +126,12 @@ network:
|
||||
available: Available
|
||||
not_available: Not available
|
||||
availability_check: Availability check
|
||||
tor_network: Tor network
|
||||
server_enabled: Server enabled
|
||||
server_starting: Server is starting
|
||||
server_stopping: Server is stopping
|
||||
server_error: Server error
|
||||
server_disabled: Server disabled
|
||||
sync_status:
|
||||
node_restarting: Node is restarting
|
||||
node_down: Node is down
|
||||
|
||||
@@ -126,6 +126,12 @@ network:
|
||||
available: Доступно
|
||||
not_available: Недоступно
|
||||
availability_check: Проверка доступности
|
||||
tor_network: Сеть Tor
|
||||
server_enabled: Сервер включен
|
||||
server_starting: Сервер запускается
|
||||
server_stopping: Сервер останавливается
|
||||
server_error: Ошибка сервера
|
||||
server_disabled: Сервер отключен
|
||||
sync_status:
|
||||
node_restarting: Узел перезапускается
|
||||
node_down: Узел выключен
|
||||
|
||||
@@ -17,11 +17,12 @@ use url::Url;
|
||||
|
||||
use crate::AppConfig;
|
||||
use crate::gui::Colors;
|
||||
use crate::gui::icons::{CARET_RIGHT, CHECK_CIRCLE, COMPUTER_TOWER, DOTS_THREE_CIRCLE, PENCIL, POWER, TRASH, X_CIRCLE};
|
||||
use crate::gui::icons::{CARET_RIGHT, CHECK_CIRCLE, COMPUTER_TOWER, DOTS_THREE_CIRCLE, GEAR_SIX, PENCIL, POWER, TRASH, WARNING_CIRCLE, X_CIRCLE};
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
use crate::gui::views::{Modal, NodeSetup, View};
|
||||
use crate::gui::views::types::{ModalContainer, ModalPosition, TextEditOptions};
|
||||
use crate::node::{Node, NodeConfig};
|
||||
use crate::tor::{TorServer, TorServerConfig};
|
||||
use crate::wallet::{ConnectionsConfig, ExternalConnection};
|
||||
|
||||
/// Network connections content.
|
||||
@@ -99,12 +100,21 @@ impl ConnectionsContent {
|
||||
// Show integrated node info content.
|
||||
Self::integrated_node_item_ui(ui);
|
||||
|
||||
// Show transport connections.
|
||||
ui.add_space(6.0);
|
||||
let transport_text = format!("{}:", t!("wallets.transport"));
|
||||
ui.label(RichText::new(transport_text).size(16.0).color(Colors::GRAY));
|
||||
ui.add_space(6.0);
|
||||
|
||||
// Show Tor SOCKS server.
|
||||
Self::tor_transport_item_ui(ui);
|
||||
|
||||
// Show external connections.
|
||||
let ext_conn_list = ConnectionsConfig::ext_conn_list();
|
||||
if !ext_conn_list.is_empty() {
|
||||
ui.add_space(6.0);
|
||||
ui.label(RichText::new(t!("wallets.ext_conn")).size(16.0).color(Colors::GRAY));
|
||||
ui.add_space(6.0);
|
||||
// Show external connections.
|
||||
for (index, conn) in ext_conn_list.iter().enumerate() {
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
// Draw connection list item.
|
||||
@@ -114,6 +124,67 @@ impl ConnectionsContent {
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw Tor connection item content.
|
||||
fn tor_transport_item_ui(ui: &mut egui::Ui) {
|
||||
// Draw round background.
|
||||
let mut rect = ui.available_rect_before_wrap();
|
||||
rect.set_height(78.0);
|
||||
let rounding = View::item_rounding(0, 1, false);
|
||||
ui.painter().rect(rect, rounding, Colors::FILL, View::ITEM_STROKE);
|
||||
|
||||
ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| {
|
||||
// Draw button to show Tor connection settings.
|
||||
View::item_button(ui, View::item_rounding(0, 1, true), GEAR_SIX, None, || {
|
||||
AppConfig::toggle_show_connections_network_panel();
|
||||
});
|
||||
|
||||
// Draw buttons to stop or start Tor server.
|
||||
if !TorServer::is_stopping() && !TorServer::is_starting() {
|
||||
if TorServer::is_running() {
|
||||
View::item_button(ui, Rounding::default(), POWER, Some(Colors::RED), || {
|
||||
TorServer::stop();
|
||||
});
|
||||
} else {
|
||||
View::item_button(ui, Rounding::default(), POWER, Some(Colors::GREEN), || {
|
||||
TorServer::start();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let layout_size = ui.available_size();
|
||||
ui.allocate_ui_with_layout(layout_size, Layout::left_to_right(Align::Center), |ui| {
|
||||
ui.add_space(6.0);
|
||||
ui.vertical(|ui| {
|
||||
ui.add_space(3.0);
|
||||
ui.label(RichText::new(t!("network.tor_network"))
|
||||
.size(18.0)
|
||||
.color(Colors::TITLE));
|
||||
|
||||
// Setup SOCKS server address.
|
||||
let socks_port = TorServerConfig::socks_port();
|
||||
let addr_text = format!("{} http://127.0.0.1:{}", COMPUTER_TOWER, socks_port);
|
||||
ui.label(RichText::new(addr_text).size(15.0).color(Colors::TEXT));
|
||||
ui.add_space(1.0);
|
||||
|
||||
// Setup server status text.
|
||||
let (status_icon, status_text) = if TorServer::has_error() {
|
||||
(WARNING_CIRCLE, t!("network.server_error"))
|
||||
} else if TorServer::is_starting() {
|
||||
(DOTS_THREE_CIRCLE, t!("network.server_starting"))
|
||||
} else if TorServer::is_stopping() {
|
||||
(DOTS_THREE_CIRCLE, t!("network.server_stopping"))
|
||||
} else if TorServer::is_running() {
|
||||
(CHECK_CIRCLE, t!("network.server_enabled"))
|
||||
} else {
|
||||
(X_CIRCLE, t!("network.server_disabled"))
|
||||
};
|
||||
let status_text = format!("{} {}", status_icon, status_text);
|
||||
ui.label(RichText::new(status_text).size(15.0).color(Colors::GRAY));
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// Draw integrated node connection item content.
|
||||
fn integrated_node_item_ui(ui: &mut egui::Ui) {
|
||||
// Draw round background.
|
||||
@@ -123,9 +194,6 @@ impl ConnectionsContent {
|
||||
ui.painter().rect(rect, rounding, Colors::FILL, View::ITEM_STROKE);
|
||||
|
||||
ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| {
|
||||
// Setup padding for item buttons.
|
||||
ui.style_mut().spacing.button_padding = egui::vec2(14.0, 0.0);
|
||||
|
||||
// Draw button to show integrated node info.
|
||||
View::item_button(ui, View::item_rounding(0, 1, true), CARET_RIGHT, None, || {
|
||||
AppConfig::toggle_show_connections_network_panel();
|
||||
@@ -137,7 +205,7 @@ impl ConnectionsContent {
|
||||
Node::start();
|
||||
});
|
||||
} else if !Node::is_starting() && !Node::is_stopping() && !Node::is_restarting() {
|
||||
// Draw button to open closed wallet.
|
||||
// Draw button to stop integrated node.
|
||||
View::item_button(ui, Rounding::default(), POWER, Some(Colors::RED), || {
|
||||
Node::stop(false);
|
||||
});
|
||||
|
||||
@@ -22,6 +22,7 @@ use crate::gui::views::{ConnectionsContent, NetworkMetrics, NetworkMining, Netwo
|
||||
use crate::gui::views::network::types::{NetworkTab, NetworkTabType};
|
||||
use crate::gui::views::types::{TitleContentType, TitleType};
|
||||
use crate::node::Node;
|
||||
use crate::tor::TorServer;
|
||||
use crate::wallet::ExternalConnection;
|
||||
|
||||
/// Network content.
|
||||
@@ -147,7 +148,8 @@ impl NetworkContent {
|
||||
});
|
||||
|
||||
// Redraw after delay if node is syncing to update stats.
|
||||
if Node::is_running() {
|
||||
if Node::is_running() || TorServer::is_running() || TorServer::is_starting() ||
|
||||
TorServer::is_stopping() {
|
||||
ui.ctx().request_repaint_after(Node::STATS_UPDATE_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -32,7 +32,7 @@ i18n!("locales");
|
||||
|
||||
mod node;
|
||||
mod wallet;
|
||||
|
||||
mod tor;
|
||||
mod settings;
|
||||
pub mod gui;
|
||||
|
||||
@@ -63,8 +63,9 @@ fn android_main(app: AndroidApp) {
|
||||
|
||||
let width = app.config().screen_width_dp().unwrap() as f32;
|
||||
let height = app.config().screen_height_dp().unwrap() as f32;
|
||||
let size = egui::emath::vec2(width, height);
|
||||
let mut options = eframe::NativeOptions {
|
||||
viewport: egui::ViewportBuilder::default().with_inner_size(vec2(width, height)),
|
||||
viewport: egui::ViewportBuilder::default().with_inner_size(size),
|
||||
..Default::default()
|
||||
};
|
||||
// Setup limits that are guaranteed to be compatible with Android devices.
|
||||
|
||||
@@ -24,6 +24,7 @@ use serde::Serialize;
|
||||
|
||||
use crate::node::NodeConfig;
|
||||
use crate::settings::AppConfig;
|
||||
use crate::tor::TorServerConfig;
|
||||
use crate::wallet::ConnectionsConfig;
|
||||
|
||||
lazy_static! {
|
||||
@@ -42,18 +43,27 @@ pub struct Settings {
|
||||
node_config: Arc<RwLock<NodeConfig>>,
|
||||
/// Wallet connections configuration.
|
||||
conn_config: Arc<RwLock<ConnectionsConfig>>,
|
||||
/// Tor server configuration.
|
||||
tor_config: Arc<RwLock<TorServerConfig>>
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
/// Initialize settings with app and node configs.
|
||||
fn init() -> Self {
|
||||
// Initialize app config.
|
||||
let app_config_path = Settings::get_config_path(AppConfig::FILE_NAME, None);
|
||||
let app_config = Self::init_config::<AppConfig>(app_config_path);
|
||||
|
||||
// Initialize tor config.
|
||||
let tor_config_path = Settings::get_config_path(TorServerConfig::FILE_NAME, None);
|
||||
let tor_config = Self::init_config::<TorServerConfig>(tor_config_path);
|
||||
|
||||
let chain_type = &app_config.chain_type;
|
||||
Self {
|
||||
node_config: Arc::new(RwLock::new(NodeConfig::for_chain_type(chain_type))),
|
||||
conn_config: Arc::new(RwLock::new(ConnectionsConfig::for_chain_type(chain_type))),
|
||||
app_config: Arc::new(RwLock::new(app_config)),
|
||||
tor_config: Arc::new(RwLock::new(tor_config)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,6 +109,16 @@ impl Settings {
|
||||
SETTINGS_STATE.conn_config.write().unwrap()
|
||||
}
|
||||
|
||||
/// Get tor server configuration to read values.
|
||||
pub fn tor_config_to_read() -> RwLockReadGuard<'static, TorServerConfig> {
|
||||
SETTINGS_STATE.tor_config.read().unwrap()
|
||||
}
|
||||
|
||||
/// Get tor server configuration to update values.
|
||||
pub fn tor_config_to_update() -> RwLockWriteGuard<'static, TorServerConfig> {
|
||||
SETTINGS_STATE.tor_config.write().unwrap()
|
||||
}
|
||||
|
||||
/// Get base directory path for configuration.
|
||||
pub fn get_base_path(sub_dir: Option<String>) -> PathBuf {
|
||||
// Check if dir exists.
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
// Copyright 2024 The Grim Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use crate::Settings;
|
||||
|
||||
/// Tor SOCKS proxy server configuration.
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct TorServerConfig {
|
||||
socks_port: u16
|
||||
}
|
||||
|
||||
/// Default SOCKS port value.
|
||||
const DEFAULT_SOCKS_PORT: u16 = 9060;
|
||||
|
||||
impl Default for TorServerConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
socks_port: DEFAULT_SOCKS_PORT,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TorServerConfig {
|
||||
/// Application configuration file name.
|
||||
pub const FILE_NAME: &'static str = "app.toml";
|
||||
|
||||
/// Save application configuration to the file.
|
||||
pub fn save(&self) {
|
||||
Settings::write_to_file(self, Settings::get_config_path(Self::FILE_NAME, None));
|
||||
}
|
||||
|
||||
/// Get SOCKS port value.
|
||||
pub fn socks_port() -> u16 {
|
||||
let r_config = Settings::tor_config_to_read();
|
||||
r_config.socks_port
|
||||
}
|
||||
|
||||
/// Save SOCKS port value.
|
||||
pub fn save_socks_port(port: u16) {
|
||||
let mut w_config = Settings::tor_config_to_update();
|
||||
w_config.socks_port = port;
|
||||
w_config.save();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright 2024 The Grim Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
mod config;
|
||||
pub use config::TorServerConfig;
|
||||
|
||||
mod tor;
|
||||
pub use tor::TorServer;
|
||||
+228
@@ -0,0 +1,228 @@
|
||||
// Copyright 2024 The Grim Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use lazy_static::lazy_static;
|
||||
use arti::socks::run_socks_proxy;
|
||||
use arti_client::{TorClient, TorClientConfig};
|
||||
use arti_client::config::pt::{TransportConfigBuilder};
|
||||
use arti_client::config::{BridgeConfigBuilder, TorClientConfigBuilder, StorageConfigBuilder};
|
||||
use futures::task::SpawnExt;
|
||||
use tokio::task::JoinHandle;
|
||||
use anyhow::{Result};
|
||||
use tokio::time::sleep;
|
||||
use tor_config::{CfgPath, Listen};
|
||||
use tor_rtcompat::{BlockOn, Runtime};
|
||||
use tor_rtcompat::tokio::TokioNativeTlsRuntime;
|
||||
|
||||
use crate::tor::TorServerConfig;
|
||||
|
||||
lazy_static! {
|
||||
/// Static thread-aware state of [`Node`] to be updated from separate thread.
|
||||
static ref TOR_SERVER_STATE: Arc<TorServer> = Arc::new(TorServer::default());
|
||||
}
|
||||
|
||||
/// Tor SOCKS proxy server.
|
||||
pub struct TorServer {
|
||||
/// Flag to check if server is running.
|
||||
running: AtomicBool,
|
||||
/// Flag to check if server is starting.
|
||||
starting: AtomicBool,
|
||||
/// Flag to check if server needs to stop.
|
||||
stopping: AtomicBool,
|
||||
/// Flag to check if error happened.
|
||||
error: AtomicBool,
|
||||
/// Tor client to use for proxy.
|
||||
client: Arc<RwLock<Option<TorClient<TokioNativeTlsRuntime>>>>
|
||||
}
|
||||
|
||||
impl Default for TorServer {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
running: AtomicBool::new(false),
|
||||
starting: AtomicBool::new(false),
|
||||
stopping: AtomicBool::new(false),
|
||||
error: AtomicBool::new(false),
|
||||
client: Arc::new(RwLock::new(None)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TorServer {
|
||||
/// Check if server is running.
|
||||
pub fn is_running() -> bool {
|
||||
TOR_SERVER_STATE.running.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
/// Check if server is running.
|
||||
pub fn is_starting() -> bool {
|
||||
TOR_SERVER_STATE.starting.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
/// Check if server is stopping.
|
||||
pub fn is_stopping() -> bool {
|
||||
TOR_SERVER_STATE.stopping.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
/// Check if server has error.
|
||||
pub fn has_error() -> bool {
|
||||
TOR_SERVER_STATE.error.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
/// Stop the server.
|
||||
pub fn stop() {
|
||||
TOR_SERVER_STATE.stopping.store(true, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
/// Start or restart the server if already running.
|
||||
pub fn start() {
|
||||
if Self::is_running() {
|
||||
Self::stop();
|
||||
}
|
||||
|
||||
thread::spawn(|| {
|
||||
while Self::is_stopping() {
|
||||
thread::sleep(Duration::from_millis(1000));
|
||||
}
|
||||
TOR_SERVER_STATE.starting.store(true, Ordering::Relaxed);
|
||||
TOR_SERVER_STATE.error.store(false, Ordering::Relaxed);
|
||||
|
||||
// Check if Tor client is already running.
|
||||
if TOR_SERVER_STATE.client.read().unwrap().is_some() {
|
||||
let r_client = TOR_SERVER_STATE.client.read().unwrap();
|
||||
let runtime = TokioNativeTlsRuntime::create().unwrap();
|
||||
let _ = runtime.clone().block_on(
|
||||
Self::launch_socks_proxy(runtime, r_client.as_ref().unwrap().clone())
|
||||
);
|
||||
} else {
|
||||
// Create Tor client config to connect.
|
||||
let mut builder = TorClientConfig::builder();
|
||||
|
||||
// Setup Snowflake bridges.
|
||||
Self::setup_bridges(&mut builder);
|
||||
|
||||
// Create Tor client from config.
|
||||
if let Ok(config) = builder.build() {
|
||||
// Restart server on connection timeout.
|
||||
thread::spawn(|| {
|
||||
thread::sleep(Duration::from_millis(30000));
|
||||
let r_client = TOR_SERVER_STATE.client.read().unwrap();
|
||||
if r_client.is_none() {
|
||||
Self::start();
|
||||
}
|
||||
});
|
||||
// Create Tor client.
|
||||
let runtime = TokioNativeTlsRuntime::create().unwrap();
|
||||
match TorClient::with_runtime(runtime.clone())
|
||||
.config(config)
|
||||
.bootstrap_behavior(arti_client::BootstrapBehavior::OnDemand)
|
||||
.create_unbootstrapped() {
|
||||
Ok(tor_client) => {
|
||||
let mut w_client = TOR_SERVER_STATE.client.write().unwrap();
|
||||
if w_client.is_some() {
|
||||
return;
|
||||
}
|
||||
*w_client = Some(tor_client.clone());
|
||||
let _ = runtime.clone().block_on(
|
||||
// Launch SOCKS proxy server.
|
||||
Self::launch_socks_proxy(runtime, tor_client)
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("{}", e);
|
||||
TOR_SERVER_STATE.starting.store(false, Ordering::Relaxed);
|
||||
TOR_SERVER_STATE.error.store(true, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TOR_SERVER_STATE.starting.store(false, Ordering::Relaxed);
|
||||
TOR_SERVER_STATE.error.store(true, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Launch SOCKS proxy server.
|
||||
async fn launch_socks_proxy<R: Runtime>(runtime: R, tor_client: TorClient<R>) -> Result<()> {
|
||||
let proxy_handle: JoinHandle<Result<()>> = tokio::spawn(
|
||||
run_socks_proxy(
|
||||
runtime,
|
||||
tor_client,
|
||||
Listen::new_localhost(TorServerConfig::socks_port()),
|
||||
)
|
||||
);
|
||||
|
||||
// Setup server state flags.
|
||||
TOR_SERVER_STATE.starting.store(false, Ordering::Relaxed);
|
||||
TOR_SERVER_STATE.running.store(true, Ordering::Relaxed);
|
||||
|
||||
loop {
|
||||
if Self::is_stopping() || proxy_handle.is_finished() {
|
||||
proxy_handle.abort();
|
||||
TOR_SERVER_STATE.stopping.store(false, Ordering::Relaxed);
|
||||
TOR_SERVER_STATE.running.store(false, Ordering::Relaxed);
|
||||
return Ok(());
|
||||
}
|
||||
sleep(Duration::from_millis(3000)).await;
|
||||
}
|
||||
}
|
||||
|
||||
/// Setup Tor Snowflake bridges.
|
||||
fn setup_bridges(builder: &mut TorClientConfigBuilder) {
|
||||
// Add a single bridge to the list of bridges, from a bridge line.
|
||||
// This line comes from https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/blob/main/projects/common/bridges_list.snowflake.txt
|
||||
// this is a real bridge line you can use as-is, after making sure it's still up to date with
|
||||
// above link.
|
||||
const BRIDGE1_LINE: &str = "Bridge snowflake 192.0.2.3:80 2B280B23E1107BB62ABFC40DDCC8824814F80A72 fingerprint=2B280B23E1107BB62ABFC40DDCC8824814F80A72 url=https://snowflake-broker.torproject.net.global.prod.fastly.net/ front=cdn.sstatic.net ice=stun:stun.l.google.com:19302,stun:stun.antisip.com:3478,stun:stun.bluesip.net:3478,stun:stun.dus.net:3478,stun:stun.epygi.com:3478,stun:stun.sonetel.com:3478,stun:stun.uls.co.za:3478,stun:stun.voipgate.com:3478,stun:stun.voys.nl:3478 utls-imitate=hellorandomizedalpn";
|
||||
let bridge_1: BridgeConfigBuilder = BRIDGE1_LINE.parse().unwrap();
|
||||
builder.bridges().bridges().push(bridge_1);
|
||||
|
||||
// Add a second bridge, built by hand. We use the 2nd bridge line from above, but modify some
|
||||
// parameters to use AMP Cache instead of Fastly as a signaling channel. The difference in
|
||||
// configuration is detailed in
|
||||
// https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/tree/main/client#amp-cache
|
||||
let mut bridge2_builder = BridgeConfigBuilder::default();
|
||||
bridge2_builder
|
||||
.transport("snowflake")
|
||||
.push_setting(
|
||||
"fingerprint",
|
||||
"8838024498816A039FCBBAB14E6F40A0843051FA"
|
||||
)
|
||||
.push_setting("url", "https://snowflake-broker.torproject.net/")
|
||||
.push_setting("ampcache", "https://cdn.ampproject.org/")
|
||||
.push_setting("front", "www.google.com")
|
||||
.push_setting(
|
||||
"ice",
|
||||
"stun:stun.l.google.com:19302,stun:stun.antisip.com:3478,stun:stun.bluesip.net:3478,stun:stun.dus.net:3478,stun:stun.epygi.com:3478,stun:stun.sonetel.net:3478,stun:stun.uls.co.za:3478,stun:stun.voipgate.com:3478,stun:stun.voys.nl:3478",
|
||||
)
|
||||
.push_setting("utls-imitate", "hellorandomizedalpn");
|
||||
bridge2_builder.set_addrs(vec!["192.0.2.4:80".parse().unwrap()]);
|
||||
bridge2_builder.set_ids(vec!["8838024498816A039FCBBAB14E6F40A0843051FA".parse().unwrap()]);
|
||||
// Now insert the second bridge into our config builder.
|
||||
builder.bridges().bridges().push(bridge2_builder);
|
||||
|
||||
// Now configure an snowflake transport. (Requires the "pt-client" feature)
|
||||
let mut transport = TransportConfigBuilder::default();
|
||||
transport
|
||||
.protocols(vec!["snowflake".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("snowflake-client".into()))
|
||||
.run_on_startup(true);
|
||||
builder.bridges().transports().push(transport);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user