mirror of
https://github.com/Cyrix126/gupaxx.git
synced 2025-01-03 12:39:35 +00:00
main: add [zeroize] and implement sudo input/test screen for xmrig
This commit is contained in:
parent
31f23d9d58
commit
f988e4224c
9 changed files with 169 additions and 9 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -37,6 +37,7 @@ dependencies = [
|
|||
"tor-rtcompat",
|
||||
"walkdir",
|
||||
"winres",
|
||||
"zeroize",
|
||||
"zip",
|
||||
]
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@ tokio = { version = "1.21.2", features = ["rt", "time", "macros", "process"] }
|
|||
toml = { version = "0.5.9", features = ["preserve_order"] }
|
||||
tor-rtcompat = "0.7.0"
|
||||
walkdir = "2.3.2"
|
||||
zeroize = "1.5.7"
|
||||
|
||||
# Unix dependencies
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
|
|
BIN
images/ferris/cute.png
Normal file
BIN
images/ferris/cute.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
BIN
images/ferris/gesture.png
Normal file
BIN
images/ferris/gesture.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 35 KiB |
BIN
images/ferris/sudo.png
Normal file
BIN
images/ferris/sudo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 214 KiB |
|
@ -67,6 +67,7 @@ pub const SPACE: f32 = 10.0;
|
|||
pub const RED: egui::Color32 = egui::Color32::from_rgb(230, 50, 50);
|
||||
pub const GREEN: egui::Color32 = egui::Color32::from_rgb(100, 230, 100);
|
||||
pub const YELLOW: egui::Color32 = egui::Color32::from_rgb(230, 230, 100);
|
||||
pub const BRIGHT_YELLOW: egui::Color32 = egui::Color32::from_rgb(250, 250, 100);
|
||||
pub const GRAY: egui::Color32 = egui::Color32::GRAY;
|
||||
pub const LIGHT_GRAY: egui::Color32 = egui::Color32::LIGHT_GRAY;
|
||||
pub const BLACK: egui::Color32 = egui::Color32::BLACK;
|
||||
|
@ -78,6 +79,16 @@ pub const ZERO_SECONDS: std::time::Duration = std::time::Duration::from_secs(0);
|
|||
pub const MILLI_900: std::time::Duration = std::time::Duration::from_millis(900);
|
||||
pub const TOKIO_SECOND: tokio::time::Duration = std::time::Duration::from_secs(1);
|
||||
|
||||
// The explaination given to the user on why XMRig needs sudo.
|
||||
pub const XMRIG_ADMIN_REASON: &str =
|
||||
r#"The large hashrate difference between XMRig and other miners like Monero and P2Pool's built-in miners is mostly due to XMRig configuring CPU MSRs and setting up hugepages. Other miners like Monero or P2Pool's built-in miner do not do this. It can be done manually but it isn't recommended since XMRig does this for you automatically, but only if it has the proper admin priviledges."#;
|
||||
// Password buttons
|
||||
pub const PASSWORD_TEXT: &str = "Enter sudo/admin password here...";
|
||||
pub const PASSWORD_LEAVE: &str = "Return to the previous screen";
|
||||
pub const PASSWORD_ENTER: &str = "Attempt with the current password";
|
||||
pub const PASSWORD_HIDE: &str = "Toggle hiding/showing the password";
|
||||
|
||||
|
||||
// OS specific
|
||||
#[cfg(target_os = "windows")]
|
||||
pub const OS: &'static str = " Windows";
|
||||
|
|
|
@ -21,6 +21,7 @@ pub const FERRIS_HAPPY: &[u8] = include_bytes!("../images/ferris/happy.png");
|
|||
pub const FERRIS_OOPS: &[u8] = include_bytes!("../images/ferris/oops.png");
|
||||
pub const FERRIS_ERROR: &[u8] = include_bytes!("../images/ferris/error.png");
|
||||
pub const FERRIS_PANIC: &[u8] = include_bytes!("../images/ferris/panic.png"); // This isnt technically ferris but its ok since its spooky
|
||||
pub const FERRIS_SUDO: &[u8] = include_bytes!("../images/ferris/sudo.png");
|
||||
|
||||
|
||||
|
||||
|
|
89
src/main.rs
89
src/main.rs
|
@ -24,11 +24,12 @@ use egui::{
|
|||
TextStyle::*,
|
||||
color::Color32,
|
||||
FontFamily::Proportional,
|
||||
TextStyle,
|
||||
TextStyle,Spinner,
|
||||
Layout,Align,
|
||||
FontId,Label,RichText,Stroke,Vec2,Button,SelectableLabel,
|
||||
Key,Modifiers,
|
||||
Key,Modifiers,TextEdit,
|
||||
CentralPanel,TopBottomPanel,
|
||||
Hyperlink,
|
||||
};
|
||||
use egui_extras::RetainedImage;
|
||||
use eframe::{egui,NativeOptions};
|
||||
|
@ -61,6 +62,12 @@ mod update;
|
|||
mod helper;
|
||||
use {ferris::*,constants::*,node::*,disk::*,status::*,update::*,gupax::*,helper::*};
|
||||
|
||||
// Sudo (unix only)
|
||||
#[cfg(target_family = "unix")]
|
||||
mod sudo;
|
||||
#[cfg(target_family = "unix")]
|
||||
use sudo::*;
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Struct + Impl
|
||||
// The state of the outer main [App].
|
||||
// See the [State] struct in [state.rs] for the
|
||||
|
@ -113,6 +120,9 @@ pub struct App {
|
|||
xmrig_img: Arc<Mutex<ImgXmrig>>, // A one-time snapshot of what data XMRig started with
|
||||
// Buffer State
|
||||
p2pool_console: String, // The buffer between the p2pool console and the [Helper]
|
||||
// Sudo State
|
||||
#[cfg(target_family = "unix")]
|
||||
sudo: Arc<Mutex<SudoState>>,
|
||||
// State from [--flags]
|
||||
no_startup: bool,
|
||||
// Static stuff
|
||||
|
@ -174,6 +184,8 @@ impl App {
|
|||
p2pool_img,
|
||||
xmrig_img,
|
||||
p2pool_console: String::with_capacity(10),
|
||||
#[cfg(target_family = "unix")]
|
||||
sudo: Arc::new(Mutex::new(SudoState::new())),
|
||||
resizing: false,
|
||||
alpha: 0,
|
||||
no_startup: false,
|
||||
|
@ -366,6 +378,7 @@ pub enum ErrorButtons {
|
|||
ResetNode,
|
||||
Okay,
|
||||
Quit,
|
||||
Sudo,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
|
@ -374,6 +387,7 @@ pub enum ErrorFerris {
|
|||
Oops,
|
||||
Error,
|
||||
Panic,
|
||||
Sudo,
|
||||
}
|
||||
|
||||
pub struct ErrorState {
|
||||
|
@ -412,6 +426,23 @@ impl ErrorState {
|
|||
buttons,
|
||||
};
|
||||
}
|
||||
|
||||
// Just sets the current state to new, resetting it.
|
||||
pub fn reset(&mut self) {
|
||||
*self = Self::new();
|
||||
}
|
||||
|
||||
// Instead of creating a whole new screen and system, this (ab)uses ErrorState
|
||||
// to ask for the [sudo] when starting XMRig. Yes, yes I know, it's called "ErrorState"
|
||||
// but rewriting the UI code and button stuff might be worse.
|
||||
pub fn ask_sudo(&mut self) {
|
||||
*self = Self {
|
||||
error: true,
|
||||
msg: String::new(),
|
||||
ferris: ErrorFerris::Sudo,
|
||||
buttons: ErrorButtons::Sudo,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- [Images] struct
|
||||
|
@ -421,6 +452,7 @@ struct Images {
|
|||
oops: RetainedImage,
|
||||
error: RetainedImage,
|
||||
panic: RetainedImage,
|
||||
sudo: RetainedImage,
|
||||
}
|
||||
|
||||
impl Images {
|
||||
|
@ -431,6 +463,7 @@ impl Images {
|
|||
oops: RetainedImage::from_image_bytes("oops.png", FERRIS_OOPS).unwrap(),
|
||||
error: RetainedImage::from_image_bytes("error.png", FERRIS_ERROR).unwrap(),
|
||||
panic: RetainedImage::from_image_bytes("panic.png", FERRIS_PANIC).unwrap(),
|
||||
sudo: RetainedImage::from_image_bytes("panic.png", FERRIS_SUDO).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -804,6 +837,7 @@ impl eframe::App for App {
|
|||
Oops => &self.img.oops,
|
||||
Error => &self.img.error,
|
||||
Panic => &self.img.panic,
|
||||
ErrorFerris::Sudo => &self.img.sudo,
|
||||
};
|
||||
ferris.show_max_size(ui, Vec2::new(width, height));
|
||||
|
||||
|
@ -825,6 +859,14 @@ impl eframe::App for App {
|
|||
ui.add_sized([width, height], Label::new(format!("--- Gupax has encountered an error! ---\n{}", &self.error_state.msg)));
|
||||
ui.add_sized([width, height], Label::new("Reset the manual node list?"))
|
||||
},
|
||||
ErrorButtons::Sudo => {
|
||||
let text = format!("Why does XMRig need admin priviledge?\n{}", XMRIG_ADMIN_REASON);
|
||||
let height = height/4.0;
|
||||
ui.add_sized([width, height], Label::new(format!("--- Gupax needs sudo/admin priviledge for XMRig! ---\n{}", &self.error_state.msg)));
|
||||
ui.style_mut().override_text_style = Some(Name("MonospaceSmall".into()));
|
||||
ui.add_sized([width/2.0, height], Label::new(text));
|
||||
ui.add_sized([width, height], Hyperlink::from_label_and_url("Click here for more info.", "https://xmrig.com/docs/miner/randomx-optimization-guide"))
|
||||
},
|
||||
_ => {
|
||||
match self.error_state.ferris {
|
||||
Panic => ui.add_sized([width, height], Label::new("--- Gupax has encountered an un-recoverable error! ---")),
|
||||
|
@ -841,7 +883,7 @@ impl eframe::App for App {
|
|||
|
||||
match self.error_state.buttons {
|
||||
YesNo => {
|
||||
if ui.add_sized([width, height/2.0], Button::new("Yes")).clicked() { self.error_state = ErrorState::new(); }
|
||||
if ui.add_sized([width, height/2.0], Button::new("Yes")).clicked() { self.error_state.reset() }
|
||||
// If [Esc] was pressed, assume [No]
|
||||
if esc || ui.add_sized([width, height/2.0], Button::new("No")).clicked() { exit(0); }
|
||||
},
|
||||
|
@ -871,7 +913,7 @@ impl eframe::App for App {
|
|||
Err(e) => self.error_state.set(format!("State reset fail: {}", e), ErrorFerris::Panic, ErrorButtons::Quit),
|
||||
};
|
||||
}
|
||||
if esc || ui.add_sized([width, height/2.0], Button::new("No")).clicked() { self.error_state = ErrorState::new() }
|
||||
if esc || ui.add_sized([width, height/2.0], Button::new("No")).clicked() { self.error_state.reset() }
|
||||
},
|
||||
ResetNode => {
|
||||
if ui.add_sized([width, height/2.0], Button::new("Yes")).clicked() {
|
||||
|
@ -889,9 +931,38 @@ impl eframe::App for App {
|
|||
Err(e) => self.error_state.set(format!("Node reset fail: {}", e), ErrorFerris::Panic, ErrorButtons::Quit),
|
||||
};
|
||||
}
|
||||
if esc || ui.add_sized([width, height/2.0], Button::new("No")).clicked() { self.error_state = ErrorState::new() }
|
||||
if esc || ui.add_sized([width, height/2.0], Button::new("No")).clicked() { self.error_state.reset() }
|
||||
},
|
||||
Okay => if esc || ui.add_sized([width, height], Button::new("Okay")).clicked() { self.error_state = ErrorState::new(); },
|
||||
ErrorButtons::Sudo => {
|
||||
let sudo_width = (width/10.0);
|
||||
let height = ui.available_height()/4.0;
|
||||
let mut sudo = self.sudo.lock().unwrap();
|
||||
let hide = sudo.hide.clone();
|
||||
ui.style_mut().override_text_style = Some(Monospace);
|
||||
if sudo.testing {
|
||||
ui.add_sized([width, height], Spinner::new().size(height));
|
||||
ui.set_enabled(false);
|
||||
} else {
|
||||
ui.add_sized([width, height], Label::new(&sudo.msg));
|
||||
}
|
||||
ui.add_space(height);
|
||||
let height = ui.available_height()/5.0;
|
||||
// Password input box with a hider.
|
||||
ui.horizontal(|ui| {
|
||||
let response = ui.add_sized([sudo_width*8.0, height], TextEdit::hint_text(TextEdit::singleline(&mut sudo.pass).password(hide), PASSWORD_TEXT));
|
||||
let box_width = (ui.available_width()/2.0)-5.0;
|
||||
if (response.lost_focus() && ui.input().key_pressed(Key::Enter)) ||
|
||||
ui.add_sized([box_width, height], Button::new("Enter")).on_hover_text(PASSWORD_ENTER).clicked() {
|
||||
if !sudo.testing {
|
||||
SudoState::test_sudo(Arc::clone(&self.sudo));
|
||||
}
|
||||
}
|
||||
let color = if hide { BLACK } else { BRIGHT_YELLOW };
|
||||
if ui.add_sized([box_width, height], Button::new(RichText::new("👁").color(color))).on_hover_text(PASSWORD_HIDE).clicked() { sudo.hide = !sudo.hide; }
|
||||
});
|
||||
if esc || ui.add_sized([width, height*4.0], Button::new("Leave")).clicked() { self.error_state.reset(); };
|
||||
},
|
||||
Okay => if esc || ui.add_sized([width, height], Button::new("Okay")).clicked() { self.error_state.reset(); },
|
||||
Quit => if ui.add_sized([width, height], Button::new("Quit")).clicked() { exit(1); },
|
||||
}
|
||||
})});
|
||||
|
@ -1079,10 +1150,10 @@ impl eframe::App for App {
|
|||
let width = (ui.available_width()/3.0)-5.0;
|
||||
if self.xmrig.lock().unwrap().is_alive() {
|
||||
if ui.add_sized([width, height], Button::new("⟲")).on_hover_text("Restart XMRig").clicked() {
|
||||
self.xmrig.lock().unwrap().state = ProcessState::Middle;
|
||||
self.error_state.ask_sudo();
|
||||
}
|
||||
if ui.add_sized([width, height], Button::new("⏹")).on_hover_text("Stop XMRig").clicked() {
|
||||
self.xmrig.lock().unwrap().state = ProcessState::Dead;
|
||||
self.error_state.ask_sudo();
|
||||
}
|
||||
ui.add_enabled_ui(false, |ui| {
|
||||
ui.add_sized([width, height], Button::new("⏺")).on_hover_text("Start XMRig");
|
||||
|
@ -1093,7 +1164,7 @@ impl eframe::App for App {
|
|||
ui.add_sized([width, height], Button::new("⏹")).on_hover_text("Stop XMRig");
|
||||
});
|
||||
if ui.add_sized([width, height], Button::new("⏺")).on_hover_text("Start XMRig").clicked() {
|
||||
// Helper::spawn_xmrig(&self.helper, &self.state.xmrig, self.state.gupax.absolute_xmrig_path.clone());
|
||||
self.error_state.ask_sudo();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
75
src/sudo.rs
Normal file
75
src/sudo.rs
Normal file
|
@ -0,0 +1,75 @@
|
|||
// Gupax - GUI Uniting P2Pool And XMRig
|
||||
//
|
||||
// Copyright (c) 2022 hinto-janaiyo
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
// Handling of [sudo] for XMRig.
|
||||
// [zeroize] is used to wipe the memory after use.
|
||||
// Only gets imported in [main.rs] for Unix.
|
||||
|
||||
use zeroize::Zeroize;
|
||||
use std::sync::{Arc,Mutex};
|
||||
use std::thread;
|
||||
use log::*;
|
||||
|
||||
#[derive(Debug,Clone)]
|
||||
pub struct SudoState {
|
||||
pub testing: bool, // Are we attempting a sudo test right now?
|
||||
pub success: bool, // Was the sudo test a success?
|
||||
pub hide: bool, // Are we hiding the password?
|
||||
pub msg: String, // The message shown to the user if unsuccessful
|
||||
pub pass: String, // The actual password wrapped in a [SecretVec]
|
||||
}
|
||||
|
||||
impl SudoState {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
testing: false,
|
||||
success: false,
|
||||
hide: true,
|
||||
msg: "".to_string(),
|
||||
pass: String::with_capacity(256),
|
||||
}
|
||||
}
|
||||
|
||||
// Swaps the pass with another 256-capacity String,
|
||||
// zeroizes the old and drops it.
|
||||
pub fn wipe(state: &Arc<Mutex<Self>>) {
|
||||
info!("Sudo | Wiping password with zeros and dropping from memory...");
|
||||
let mut new = String::with_capacity(256);
|
||||
let mut state = state.lock().unwrap();
|
||||
// new is now == old, and vice-versa.
|
||||
std::mem::swap(&mut new, &mut state.pass);
|
||||
// we're wiping & dropping the old pass here.
|
||||
new.zeroize();
|
||||
std::mem::drop(new);
|
||||
info!("Sudo ... Password Wipe OK");
|
||||
}
|
||||
|
||||
pub fn test_sudo(state: Arc<Mutex<Self>>) {
|
||||
std::thread::spawn(move || {
|
||||
state.lock().unwrap().testing = true;
|
||||
info!("in test_sudo()");
|
||||
std::thread::sleep(std::time::Duration::from_secs(3));
|
||||
state.lock().unwrap().testing = false;
|
||||
if state.lock().unwrap().pass == "secret" {
|
||||
state.lock().unwrap().msg = "Correct!".to_string();
|
||||
} else {
|
||||
state.lock().unwrap().msg = "Incorrect password!".to_string();
|
||||
}
|
||||
Self::wipe(&state);
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue