diff --git a/Cargo.lock b/Cargo.lock index 8f10e85..818714a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3823,9 +3823,9 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.27.0" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d08ba83d6dde63d053e42d7230f0dc7f8d8efeb8d30d3681580d158156461ba" +checksum = "ccb297c0afb439440834b4bcf02c5c9da8ec2e808e70f36b0d8e815ff403bd24" dependencies = [ "cfg-if", "core-foundation-sys", diff --git a/Cargo.toml b/Cargo.toml index 83c5949..5fed009 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,10 @@ strip = "symbols" codegen-units = 1 lto = true +[features] +default = [] +distro = [] + [dependencies] anyhow = "1.0.65" arti-client = { version = "0.7.0", features = ["static"] } diff --git a/README.md b/README.md index cdcdc36..ca0d6f0 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ Gupax is a (Windows|macOS|Linux) GUI for mining [**Monero**](https://github.com/ * [Build](#Build) - [General Info](#General-Info) - [Linux](#Linux) + - [Building for a distribution](#building-for-a-distribution) - [macOS](#macOS) - [Windows](#Windows) * [License](#License) @@ -126,7 +127,7 @@ P2Pool Simple allows you to ping & connect to a [Community Monero Node](#communi To start P2Pool, first input the Monero address you'd like to receive payouts from. You must use a primary Monero address to mine on P2Pool (starts with a 4). It is highly recommended to create a new wallet since addresses are public on P2Pool! -**Warning: [There are negative privacy and security implications when using Monero node not in your control.](https://www.getmonero.org/resources/moneropedia/remote-node.html)** Select a community node that you trust, or better yet, run your own node. If you'd like to manually specify a node to connect to, see [Advanced.](#advanced) +**Warning: [There are negative privacy/security implications when using a Monero node not in your control.](https://www.getmonero.org/resources/moneropedia/remote-node.html)** Select a community node that you trust, or better yet, run your own node. If you'd like to manually specify a node to connect to, see [Advanced.](#advanced) --- @@ -141,17 +142,17 @@ Gupax will automatically launch XMRig with administrator privileges to activate **macOS/Linux:** Gupax will prompt for your `sudo` password to start XMRig with and do all the things above. -XMRig Simple will always mine to your own local P2Pool (`localhost:3333`), if you'd like to manually specify a pool to mine to, see [Advanced](#advanced). +XMRig Simple will always mine to your own local P2Pool (`127.0.0.1:3333`), if you'd like to manually specify a pool to mine to, see [Advanced](#advanced). ## Advanced ### Verifying It is recommended to verify the hash and PGP signature of the download before using Gupax. -Download the [`SHA256SUM`](https://github.com/hinto-janaiyo/gupax/releases/latest) file, download and import my [`PGP key`](https://github.com/hinto-janaiyo/gupax/blob/main/pgp/hinto-janaiyo.asc), and verify: +Download the [`SHA256SUMS`](https://github.com/hinto-janaiyo/gupax/releases/latest) file, download and import my [`PGP key`](https://github.com/hinto-janaiyo/gupax/blob/main/pgp/hinto-janaiyo.asc), and verify: ```bash -sha256sum -c SHA256SUM +sha256sum -c SHA256SUMS gpg --import hinto-janaiyo.asc -gpg --verify SHA256SUM +gpg --verify SHA256SUMS ``` Q: How can I be sure the P2Pool/XMRig bundled with Gupax hasn't been tampered with? @@ -277,11 +278,11 @@ RUST_LOG=debug ./gupax ``` In general: -- `ERROR` means something has gone wrong and that something will likely break -- `WARN` means something has gone wrong, but things will likely be fine +- `ERROR` means something has gone wrong and that something will probably break +- `WARN` means something has gone wrong, but things will be fine - `INFO` logs are general info about what Gupax (the GUI thread) is currently doing - `DEBUG` logs are much more verbose and include what EVERY thread is doing (not just the main GUI thread) -- `TRACE` logs are insanely verbose and shows the logs of the libraries Gupax uses (HTTP connections, GUI polling, etc) +- `TRACE` logs are insanely verbose and shows very low-level logs of the libraries Gupax uses (HTTP connections, GUI polling, etc) --- @@ -464,6 +465,12 @@ You need [`cargo`](https://www.rust-lang.org/learn/get-started), Rust's build to The `--release` profile in Gupax is set to prefer code performance & small binary sizes over compilation speed (see [`Cargo.toml`](https://github.com/hinto-janaiyo/gupax/blob/main/Cargo.toml)). Gupax itself (with all dependencies already built) takes around 1m30s to build (vs 10s on a normal `--release`) with a Ryzen 5950x. +There are `20` unit tests throughout the codebase files, you should probably run: +``` +cargo test +``` +before attempting a full build. + --- ### Linux @@ -474,6 +481,17 @@ After that, run: cargo build --release ``` +### Building for a distribution +Gupax has a build flag for use as a package in a Linux distribution: +``` +cargo build --release --features distro +``` +This is the same as the `--release` profile, but with some changes: +| Change | Reason | +|--------------------------------------------|--------| +| Built-in `Update` feature is disabled | Updates should be handled by the native package manager +| Default `P2Pool/XMRig` path is `/usr/bin/` | `P2Pool/XMRig` exist in _[some](https://aur.archlinux.org)_ repositories, which means they'll be installed in `/usr/bin/` + --- ### macOS @@ -515,12 +533,12 @@ The latest versions are downloaded using the GitHub API. * P2Pool [`https://github.com/SChernykh/p2pool`](https://github.com/SChernykh/p2pool) * XMRig [`https://github.com/xmrig/xmrig`](https://github.com/xmrig/xmrig) -GitHub's API blocks request that do not have an HTTP `User-Agent` header. [For privacy, Gupax randomly uses a recent version of a `Wget/Curl` user-agent.](https://github.com/hinto-janaiyo/gupax/blob/2b80aa027728ddd193bac2e77caa5ddb4323f8fd/src/update.rs#L134) +GitHub's API blocks request that do not have an HTTP `User-Agent` header. [Gupax uses a random recent version of a `Wget/Curl` user-agent.](https://github.com/hinto-janaiyo/gupax/blob/2b80aa027728ddd193bac2e77caa5ddb4323f8fd/src/update.rs#L134) --- ### Can I quit mid-update? -If you started an update, you should let it finish. If the update has been stuck for a *long* time, it may be worth quitting Gupax. The worst that can happen is that your `Gupax/P2Pool/XMRig` binaries may be moved/deleted. Those can be easily redownloaded. Your actual `Gupax` user data (settings, custom nodes, pools, etc) is never touched. +If you started an update, you should let it finish. If the update has been stuck for a *long* time, quitting Gupax is probably okay. The worst that can happen is that your `Gupax/P2Pool/XMRig` binaries may be moved/deleted. Those can be easily redownloaded. Your actual `Gupax` user data (settings, custom nodes, pools, etc) is never touched. Although Gupax uses a temporary folder (`gupax_update_[A-Za-z0-9]`) to store temporary downloaded files, there aren't measures in place to revert an upgrade once the file swapping has actually started. If you quit Gupax anytime before the `Upgrading packages` phase (after metadata, download, extraction), you will technically be safe but this is not recommended as it is risky, especially since these updates can be very fast. @@ -536,7 +554,7 @@ Although Gupax uses a temporary folder (`gupax_update_[A-Za-z0-9]`) to store tem ### How much memory does Gupax use? Gupax itself uses around 100-300 megabytes of memory. -Gupax also holds up to [500,000 bytes](https://github.com/hinto-janaiyo/gupax/blob/2b80aa027728ddd193bac2e77caa5ddb4323f8fd/src/helper.rs#L63) of log data from `P2Pool/XMRig` to display in the GUI terminals. These logs are reset once over capacity which takes around 1-2 hours. +Gupax also holds up to [500,000 bytes](https://github.com/hinto-janaiyo/gupax/blob/2b80aa027728ddd193bac2e77caa5ddb4323f8fd/src/helper.rs#L63) of log data from `P2Pool/XMRig` to display in the GUI terminals. These logs are reset once over capacity which takes around 1-4 hours. Memory usage should *never* be above 500~ megabytes. If you see Gupax using more than this, please send a bug report. diff --git a/src/README.md b/src/README.md index 7e289d9..e43d15f 100644 --- a/src/README.md +++ b/src/README.md @@ -105,7 +105,7 @@ Exceptions (there are always exceptions...): - P2Pool hashes are in UPPERCASE ## Sudo -Unlike Windows, Unix (macOS/Linux) have a userland program that handles all the dirty details of privilege escalation: `sudo`. +Unlike Windows, Unix (macOS/Linux) has a userland program that handles all the dirty details of privilege escalation: `sudo`. `sudo` is used in Gupax to execute XMRig, to enable MSR mods and hugepages. After every use of `sudo`, the memory holding the `String` buffer containing the password is wiped with 0's using [`zeroize`](https://docs.rs/zeroize/) to make sure the compiler doesn't optimize away the wipe. Although memory *should* be safe, this prevents passive accidents (core-dumps revealing plain-text password) and active attacks (attackers accessing live process memory) from happening. diff --git a/src/constants.rs b/src/constants.rs index f28a082..e69e509 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -15,11 +15,20 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -pub const GUPAX_VERSION: &str = concat!("v", env!("CARGO_PKG_VERSION")); +pub const GUPAX_VERSION: &str = concat!("v", env!("CARGO_PKG_VERSION")); // e.g: Gupax v1.0.0 pub const P2POOL_VERSION: &str = "v2.5"; pub const XMRIG_VERSION: &str = "v6.18.0"; pub const COMMIT: &str = include_str!("../.git/refs/heads/main"); -pub const GUPAX_VERSION_UNDERSCORE: &str = concat!("Gupax_v", env!("CARGO_PKG_VERSION")); +// e.g: Gupax_v1_0_0 +// Would have been [Gupax_v1.0.0] but P2Pool truncates everything after [.] +pub const GUPAX_VERSION_UNDERSCORE: &str = concat!( + "Gupax_v", + env!("CARGO_PKG_VERSION_MAJOR"), + "_", + env!("CARGO_PKG_VERSION_MINOR"), + "_", + env!("CARGO_PKG_VERSION_PATCH"), +); // App frame resolution, [4:3] aspect ratio, [1.33:1] pub const APP_MIN_WIDTH: f32 = 640.0; @@ -30,6 +39,11 @@ pub const APP_MAX_HEIGHT: f32 = 1920.0; pub const APP_DEFAULT_WIDTH: f32 = 1280.0; pub const APP_DEFAULT_HEIGHT: f32 = 960.0; +// Constants specific for Linux distro packaging of Gupax +#[cfg(feature = "distro")] +pub const DISTRO_NO_UPDATE: &str = +r#"This [Gupax] was compiled for use as a Linux distro package. Built-in updates are disabled. The below settings [Update-via-Tor] & [Auto-Update] will not do anything. Please use your package manager to update [Gupax/P2Pool/XMRig]."#; + // Use macOS shaped icon for macOS #[cfg(target_os = "macos")] pub const BYTES_ICON: &[u8] = include_bytes!("../images/icons/icon@2x.png"); diff --git a/src/disk.rs b/src/disk.rs index b4c6299..6a4c76c 100644 --- a/src/disk.rs +++ b/src/disk.rs @@ -53,21 +53,33 @@ use log::*; const ERROR: &str = "Disk error"; const PATH_ERROR: &str = "PATH for state directory could not be not found"; #[cfg(target_os = "windows")] -const DIRECTORY: &'static str = r#"Gupax\"#; +const DIRECTORY: &str = r#"Gupax\"#; #[cfg(target_os = "macos")] -const DIRECTORY: &'static str = "Gupax/"; +const DIRECTORY: &str = "Gupax/"; #[cfg(target_os = "linux")] const DIRECTORY: &str = "gupax/"; #[cfg(target_os = "windows")] -pub const DEFAULT_P2POOL_PATH: &'static str = r"P2Pool\p2pool.exe"; -#[cfg(target_family = "unix")] +pub const DEFAULT_P2POOL_PATH: &str = r"P2Pool\p2pool.exe"; +#[cfg(target_os = "macos")] pub const DEFAULT_P2POOL_PATH: &str = "p2pool/p2pool"; #[cfg(target_os = "windows")] -pub const DEFAULT_XMRIG_PATH: &'static str = r"XMRig\xmrig.exe"; -#[cfg(target_family = "unix")] +pub const DEFAULT_XMRIG_PATH: &str = r"XMRig\xmrig.exe"; +#[cfg(target_os = "macos")] pub const DEFAULT_XMRIG_PATH: &str = "xmrig/xmrig"; +// Default to [/usr/bin/] for Linux distro builds. +#[cfg(target_os = "linux")] +#[cfg(not(feature = "distro"))] +pub const DEFAULT_P2POOL_PATH: &str = "p2pool/p2pool"; +#[cfg(target_os = "linux")] +#[cfg(not(feature = "distro"))] +pub const DEFAULT_XMRIG_PATH: &str = "xmrig/xmrig"; +#[cfg(feature = "distro")] +pub const DEFAULT_P2POOL_PATH: &str = "/usr/bin/p2pool"; +#[cfg(feature = "distro")] +pub const DEFAULT_XMRIG_PATH: &str = "/usr/bin/xmrig"; + //---------------------------------------------------------------------------------------------------- General functions for all [File]'s // get_file_path() | Return absolute path to OS data path + filename // read_to_string() | Convert the file at a given path into a [String] diff --git a/src/gupax.rs b/src/gupax.rs index ad1f849..68202eb 100644 --- a/src/gupax.rs +++ b/src/gupax.rs @@ -93,7 +93,15 @@ impl Gupax { let width = width - SPACE; let updating = *update.lock().unwrap().updating.lock().unwrap(); ui.vertical(|ui| { + // If [Gupax] is being built for a Linux distro, + // disable built-in updating completely. + #[cfg(feature = "distro")] + ui.set_enabled(false); + #[cfg(feature = "distro")] + ui.add_sized([width, height], Button::new("Updates are disabled")).on_disabled_hover_text(DISTRO_NO_UPDATE); + #[cfg(not(feature = "distro"))] ui.set_enabled(!updating); + #[cfg(not(feature = "distro"))] if ui.add_sized([width, height], Button::new("Check for updates")).on_hover_text(GUPAX_UPDATE).clicked() { Update::spawn_thread(og, self, state_path, update, error_state, restart); } diff --git a/src/helper.rs b/src/helper.rs index 623dafd..12ea8a3 100644 --- a/src/helper.rs +++ b/src/helper.rs @@ -1724,6 +1724,18 @@ impl Hashrate { //---------------------------------------------------------------------------------------------------- TESTS #[cfg(test)] mod test { + #[test] + fn reset_gui_output() { + let max = crate::helper::GUI_OUTPUT_LEEWAY; + let mut string = String::with_capacity(max); + for _ in 0..=max { + string.push('0'); + } + crate::Helper::check_reset_gui_output(&mut string, crate::ProcessName::P2pool); + // Some text gets added, so just check for less than 500 bytes. + assert!(string.len() < 500); + } + #[test] fn human_number() { use crate::HumanNumber; diff --git a/src/main.rs b/src/main.rs index 12deba5..cf38e12 100644 --- a/src/main.rs +++ b/src/main.rs @@ -713,6 +713,7 @@ fn init_auto(app: &mut App) { } // [Auto-Update] + #[cfg(not(feature = "distro"))] if app.state.gupax.auto_update { Update::spawn_thread(&app.og, &app.state.gupax, &app.state_path, &app.update, &mut app.error_state, &app.restart); } else { @@ -1563,12 +1564,6 @@ impl eframe::App for App { //---------------------------------------------------------------------------------------------------- TESTS #[cfg(test)] mod test { - #[test] - fn build_app() { - let mut app = crate::App::new(std::time::Instant::now()); - crate::init_auto(&mut app); - } - #[test] fn build_regex() { use regex::Regex; @@ -1587,9 +1582,4 @@ mod test { assert!(!Regex::is_match(&r.port, "0")); assert!(!Regex::is_match(&r.port, "65536")); } - - #[test] - fn build_images() { - crate::Images::new(); - } } diff --git a/src/update.rs b/src/update.rs index 98fd544..58a36b7 100644 --- a/src/update.rs +++ b/src/update.rs @@ -285,6 +285,14 @@ impl Update { // an update needs to happen (Gupax tab, auto-update), the // code only needs to be edited once, here. pub fn spawn_thread(og: &Arc>, gupax: &crate::disk::Gupax, state_path: &Path, update: &Arc>, error_state: &mut ErrorState, restart: &Arc>) { + // We really shouldn't be in the function for + // the Linux distro Gupax (UI gets disabled) + // but if somehow get in here, just return. + #[cfg(feature = "distro")] + error!("Update | This is the [Linux distro] version of Gupax, updates are disabled"); + #[cfg(feature = "distro")] + return; + // Check P2Pool path for safety // Attempt relative to absolute path let p2pool_path = match into_absolute_path(gupax.p2pool_path.clone()) { @@ -383,6 +391,11 @@ impl Update { // 5. extract, upgrade #[tokio::main] pub async fn start(update: Arc>, _og: Arc>, state_ver: Arc>, restart: Arc>) -> Result<(), anyhow::Error> { + #[cfg(feature = "distro")] + error!("Update | This is the [Linux distro] version of Gupax, updates are disabled"); + #[cfg(feature = "distro")] + return Err(anyhow!("This is the [Linux distro] version of Gupax, updates are disabled")); + //---------------------------------------------------------------------------------------------------- Init *update.lock().unwrap().updating.lock().unwrap() = true; // Set timer