tauri_plugin_keygen_rs2/
machine.rs1use std::{
2 fs::{self, File},
3 io::Write,
4 path::PathBuf,
5};
6
7use keygen_rs::{machine::MachineCheckoutOpts, machine_file::MachineFile};
8use tauri::{webview_version, AppHandle, Runtime};
9#[cfg(mobile)]
10use tauri_plugin_machine_uid::MachineUidExt;
11
12use crate::{error::Error, utils::get_app_keygen_path, AppHandleExt, Result};
13
14#[cfg(mobile)]
15static ENGINE_NAME: &str = "WRY";
16
17#[cfg(target_os = "linux")]
18static ENGINE_NAME: &str = "WebKit";
19
20#[cfg(target_os = "macos")]
21static ENGINE_NAME: &str = "WebKit";
22
23#[cfg(target_os = "windows")]
24static ENGINE_NAME: &str = "WebView2";
25
26#[derive(Debug, Clone)]
27pub struct MachineState {
28 pub name: String,
29 pub fingerprint: String,
30 pub platform: String,
31 pub user_agent: String,
32}
33
34impl MachineState {
35 #[cfg(desktop)]
36 pub fn get_fingerprint() -> String {
37 machine_uid::get().unwrap_or_default()
38 }
39
40 #[cfg(desktop)]
41 pub fn get_fingerprint_app<R: Runtime>(_app_handle: &AppHandle<R>) -> String {
42 Self::get_fingerprint()
43 }
44
45 #[cfg(mobile)]
46 pub fn get_fingerprint() -> String {
47 panic!(
48 r#"On mobile, you should use the `get_fingerprint_app` method instead of `get_fingerprint`."#
49 );
50 }
51
52 #[cfg(mobile)]
53 pub fn get_fingerprint_app<R: Runtime>(app_handle: &AppHandle<R>) -> String {
54 let Some(state) = app_handle.try_machine_uid() else {
55 panic!(
56 r#"tauri-plugin-machine-uid is not initialized but is required to get machine fingerprints on mobile.
57You should add it to your application and initialize it before tauri-plugin-keygen-rs2."#
58 );
59 };
60
61 state
62 .get_machine_uid()
63 .ok()
64 .and_then(|uid| uid.id)
65 .unwrap_or_default()
66 }
67
68 pub(crate) fn new<R: Runtime>(
69 app_handle: &AppHandle<R>,
70 app_name: String,
71 app_version: String,
72 ) -> Self {
73 let fingerprint = Self::get_fingerprint_app(app_handle);
74 let name = whoami::devicename();
75
76 let os_name = format!("{}", whoami::platform());
77 let os_version = whoami::distro().to_string();
78 let arch = format!("{}", whoami::arch());
79 let platform = format!("{} - {} - {}", os_name, os_version, arch);
80
81 let engine_name = ENGINE_NAME.to_string();
82 let engine_version = webview_version().unwrap_or_default();
83 let locale = sys_locale::get_locale().unwrap_or_default();
84 let user_agent = format!(
85 "{}/{} {}/{} {}/{} {}",
86 app_name, app_version, os_name, os_version, engine_name, engine_version, locale
87 );
88
89 Self {
90 name,
91 fingerprint,
92 platform,
93 user_agent,
94 }
95 }
96
97 pub async fn checkout<R: Runtime>(
98 &self,
99 app_handle: &AppHandle<R>,
100 options: &MachineCheckoutOpts,
101 ) -> Result<MachineFile> {
102 let config_state = app_handle.get_keygen_config();
103 let config = config_state.lock().await;
104 let license_state = app_handle.get_license_state();
105 let license_state = license_state.lock().await;
106 if let Some(license) = &license_state.license {
107 log::info!("Checking out machine file: {}", self.fingerprint);
108 let machine = license
109 .clone()
110 .with_config(config.clone())
111 .machine(&self.fingerprint)
112 .await?;
113 let machine_file = machine
114 .with_config(config.clone())
115 .checkout(options)
116 .await?;
117 Self::save_machine_file(app_handle, &machine_file)?;
118 Ok(machine_file)
119 } else {
120 Err(Error::NoLicenseError)
121 }
122 }
123
124 pub fn load_machine_file<R: Runtime>(
125 app_handle: &AppHandle<R>,
126 key: &str,
127 ) -> Result<Option<MachineFile>> {
128 let path = Self::get_machine_file_path(app_handle)?;
129 if !path.exists() {
130 return Ok(None);
131 }
132 let content = fs::read_to_string(path)?;
133 let machine_file = MachineFile::from_cert(key, &content)?;
134 Ok(Some(machine_file))
135 }
136
137 pub fn remove_machine_file<R: Runtime>(app_handle: &AppHandle<R>) -> Result<()> {
138 let path = Self::get_machine_file_path(app_handle)?;
139 if path.exists() {
140 fs::remove_file(path)?;
141 }
142 Ok(())
143 }
144
145 fn get_machine_file_path<R: Runtime>(app_handle: &AppHandle<R>) -> Result<PathBuf> {
146 let data_dir = get_app_keygen_path(app_handle)?;
147 let path = data_dir.join("machine.lic");
148 Ok(path)
149 }
150
151 fn save_machine_file<R: Runtime>(
152 app_handle: &AppHandle<R>,
153 machine_file: &MachineFile,
154 ) -> Result<()> {
155 let path = Self::get_machine_file_path(app_handle)?;
156 let mut file = File::create(path)?;
157 file.write_all(machine_file.certificate.as_bytes())?;
158 Ok(())
159 }
160}