Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: increase autostartup permissions #1221

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ tauri-plugin-process = "2"
openssl = { version = "0.10", features = ["vendored"] }

[target.'cfg(windows)'.dependencies]
planif = "1.0.0"
whoami = "1.5.2"
winreg = "0.52.0"

# needed for keymanager. TODO: Find a way of creating a keymanager without bundling sqlite
Expand Down
132 changes: 108 additions & 24 deletions src-tauri/src/auto_launcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,24 @@ use anyhow::anyhow;
use auto_launch::{AutoLaunch, AutoLaunchBuilder};
use dunce::canonicalize;
use log::{info, warn};
#[cfg(target_os = "windows")]
use planif::{
enums::TaskCreationFlags,
schedule::TaskScheduler,
schedule_builder::{Action, ScheduleBuilder},
settings::{LogonType, PrincipalSettings, RunLevel, Settings},
};
use tauri::utils::platform::current_exe;
use tokio::sync::RwLock;
#[cfg(target_os = "windows")]
use whoami::username;

use crate::utils::platform_utils::{CurrentOperatingSystem, PlatformUtils};

const LOG_TARGET: &str = "tari::universe::auto_launcher";

static INSTANCE: LazyLock<AutoLauncher> = LazyLock::new(AutoLauncher::new);

pub enum CurrentOperatingSystem {
Windows,
Linux,
MacOS,
}

pub struct AutoLauncher {
auto_launcher: RwLock<Option<AutoLaunch>>,
}
Expand All @@ -50,22 +55,10 @@ impl AutoLauncher {
}
}

fn detect_current_os() -> CurrentOperatingSystem {
if cfg!(target_os = "windows") {
CurrentOperatingSystem::Windows
} else if cfg!(target_os = "linux") {
CurrentOperatingSystem::Linux
} else if cfg!(target_os = "macos") {
CurrentOperatingSystem::MacOS
} else {
panic!("Unsupported OS");
}
}

fn build_auto_launcher(app_name: &str, app_path: &str) -> Result<AutoLaunch, anyhow::Error> {
info!(target: LOG_TARGET, "Building auto-launcher with app_name: {} and app_path: {}", app_name, app_path);

match AutoLauncher::detect_current_os() {
match PlatformUtils::detect_current_os() {
CurrentOperatingSystem::Windows => {
return AutoLaunchBuilder::new()
.set_app_name(app_name)
Expand Down Expand Up @@ -93,21 +86,29 @@ impl AutoLauncher {
}
}

fn toggle_auto_launcher(
async fn toggle_auto_launcher(
&self,
auto_launcher: &AutoLaunch,
config_is_auto_launcher_enabled: bool,
) -> Result<(), anyhow::Error> {
let is_auto_launcher_enabled = auto_launcher.is_enabled().unwrap_or(false);

if config_is_auto_launcher_enabled && !is_auto_launcher_enabled {
info!(target: LOG_TARGET, "Enabling auto-launcher");
match AutoLauncher::detect_current_os() {
match PlatformUtils::detect_current_os() {
CurrentOperatingSystem::MacOS => {
// This for some reason fixes the issue where macOS starts two instances of the app
// when auto-launcher is enabled and when during shutdown user selects to reopen the apps after restart
auto_launcher.disable()?;
auto_launcher.enable()?;
}
CurrentOperatingSystem::Windows => {
auto_launcher.enable()?;
// To startup application as admin on windows, we need to create a task scheduler
#[cfg(target_os = "windows")]
self.toggle_windows_admin_auto_launcher(is_auto_launcher_enabled)
.await?;
}
_ => {
auto_launcher.enable()?;
}
Expand All @@ -117,12 +118,93 @@ impl AutoLauncher {

if !config_is_auto_launcher_enabled && is_auto_launcher_enabled {
info!(target: LOG_TARGET, "Disabling auto-launcher");
auto_launcher.disable()?;
match PlatformUtils::detect_current_os() {
CurrentOperatingSystem::Windows => {
#[cfg(target_os = "windows")]
self.toggle_windows_admin_auto_launcher(is_auto_launcher_enabled)
.await?;
auto_launcher.disable()?;
}
_ => {
auto_launcher.disable()?;
}
}
}

Ok(())
}

#[cfg(target_os = "windows")]
async fn toggle_windows_admin_auto_launcher(
&self,
config_is_auto_launcher_enabled: bool,
) -> Result<(), anyhow::Error> {
if config_is_auto_launcher_enabled {
info!(target: LOG_TARGET, "Enabling admin auto-launcher");
self.create_task_scheduler_for_admin_startup(true)
.await
.map_err(|e| anyhow!("Failed to create task scheduler for admin startup: {}", e))?;
};

if !config_is_auto_launcher_enabled {
info!(target: LOG_TARGET, "Disabling admin auto-launcher");
self.create_task_scheduler_for_admin_startup(false)
.await
.map_err(|e| anyhow!("Failed to create task scheduler for admin startup: {}", e))?;
};

Ok(())
}

#[cfg(target_os = "windows")]
pub async fn create_task_scheduler_for_admin_startup(
&self,
is_triggered: bool,
) -> Result<(), Box<dyn std::error::Error>> {
let task_scheduler = TaskScheduler::new()?;
let com_runtime = task_scheduler.get_com();
let schedule_builder = ScheduleBuilder::new(&com_runtime)?;

let app_exe = current_exe()?;
let app_exe = canonicalize(&app_exe)?;

let app_path = app_exe
.as_os_str()
.to_str()
.ok_or(anyhow!("Failed to convert path to string"))?
.to_string();

schedule_builder
.create_logon()
.author("Tari Universe")?
.trigger("startup_trigger", is_triggered)?
.action(Action::new("startup_action", &app_path, "", ""))?
.principal(PrincipalSettings {
display_name: "Tari Universe".to_string(),
group_id: None,
user_id: Some(username()),
id: "Tari universe principal".to_string(),
logon_type: LogonType::InteractiveToken,
run_level: RunLevel::Highest,
})?
.settings(Settings {
stop_if_going_on_batteries: Some(false),
start_when_available: Some(true),
run_only_if_network_available: Some(false),
run_only_if_idle: Some(false),
enabled: Some(true),
disallow_start_if_on_batteries: Some(false),
..Default::default()
})?
.build()?
.register(
"Tari Universe startup",
TaskCreationFlags::CreateOrUpdate as i32,
)?;

Ok(())
}

pub async fn initialize_auto_launcher(
&self,
is_auto_launcher_enabled: bool,
Expand All @@ -145,7 +227,8 @@ impl AutoLauncher {
info!(target: LOG_TARGET, "Building auto-launcher with app_name: {} and app_path: {}", app_name, app_path);
let auto_launcher = AutoLauncher::build_auto_launcher(app_name, &app_path)?;

AutoLauncher::toggle_auto_launcher(&auto_launcher, is_auto_launcher_enabled)?;
self.toggle_auto_launcher(&auto_launcher, is_auto_launcher_enabled)
.await?;

let _ = &self.auto_launcher.write().await.replace(auto_launcher);

Expand All @@ -168,7 +251,8 @@ impl AutoLauncher {
let auto_launcher_ref = auto_launcher.as_ref();
match auto_launcher_ref {
Some(auto_launcher) => {
AutoLauncher::toggle_auto_launcher(auto_launcher, is_auto_launcher_enabled)?;
self.toggle_auto_launcher(auto_launcher, is_auto_launcher_enabled)
.await?;
}
None => {
warn!(target: LOG_TARGET, "Could not get auto-launcher reference");
Expand Down
Loading