diff --git a/app/MindWork AI Studio/Program.cs b/app/MindWork AI Studio/Program.cs
index 1630a7a7..81b25fa7 100644
--- a/app/MindWork AI Studio/Program.cs
+++ b/app/MindWork AI Studio/Program.cs
@@ -208,6 +208,30 @@ internal sealed class Program
await rust.AppIsReady();
programLogger.LogInformation("The AI Studio server is ready.");
+ //
+ // Read the enterprise environment for the current user's configuration:
+ //
+ var enterpriseConfigServerUrl = await RUST_SERVICE.EnterpriseEnvConfigServerUrl();
+ var enterpriseConfigId = await RUST_SERVICE.EnterpriseEnvConfigId();
+ switch (enterpriseConfigServerUrl)
+ {
+ case null when enterpriseConfigId == Guid.Empty:
+ programLogger.LogInformation("AI Studio runs without an enterprise configuration.");
+ break;
+
+ case null:
+ programLogger.LogWarning($"AI Studio runs with an enterprise configuration id ('{enterpriseConfigId}'), but the configuration server URL is not set.");
+ break;
+
+ case not null when enterpriseConfigId == Guid.Empty:
+ programLogger.LogWarning($"AI Studio runs with an enterprise configuration server URL ('{enterpriseConfigServerUrl}'), but the configuration ID is not set.");
+ break;
+
+ default:
+ programLogger.LogInformation($"AI Studio runs with an enterprise configuration id ('{enterpriseConfigId}') and configuration server URL ('{enterpriseConfigServerUrl}').");
+ break;
+ }
+
TaskScheduler.UnobservedTaskException += (sender, taskArgs) =>
{
programLogger.LogError(taskArgs.Exception, $"Unobserved task exception by sender '{sender ?? "n/a"}'.");
diff --git a/app/MindWork AI Studio/Tools/Services/RustService.Enterprise.cs b/app/MindWork AI Studio/Tools/Services/RustService.Enterprise.cs
new file mode 100644
index 00000000..6fae98af
--- /dev/null
+++ b/app/MindWork AI Studio/Tools/Services/RustService.Enterprise.cs
@@ -0,0 +1,44 @@
+namespace AIStudio.Tools.Services;
+
+public sealed partial class RustService
+{
+ ///
+ /// Tries to read the enterprise environment for the current user's configuration ID.
+ ///
+ ///
+ /// Returns the empty Guid when the environment is not set or the request fails.
+ /// Otherwise, the configuration ID.
+ ///
+ public async Task EnterpriseEnvConfigId()
+ {
+ var result = await this.http.GetAsync("/system/enterprise/config/id");
+ if (!result.IsSuccessStatusCode)
+ {
+ this.logger!.LogError($"Failed to query the enterprise configuration ID: '{result.StatusCode}'");
+ return Guid.Empty;
+ }
+
+ Guid.TryParse(await result.Content.ReadAsStringAsync(), out var configurationId);
+ return configurationId;
+ }
+
+ ///
+ /// Tries to read the enterprise environment for the current user's configuration server URL.
+ ///
+ ///
+ /// Returns null when the environment is not set or the request fails.
+ /// Otherwise, the configuration server URL.
+ ///
+ public async Task EnterpriseEnvConfigServerUrl()
+ {
+ var result = await this.http.GetAsync("/system/enterprise/config/server");
+ if (!result.IsSuccessStatusCode)
+ {
+ this.logger!.LogError($"Failed to query the enterprise configuration server URL: '{result.StatusCode}'");
+ return null;
+ }
+
+ var serverUrl = await result.Content.ReadAsStringAsync();
+ return string.IsNullOrWhiteSpace(serverUrl) ? null : serverUrl;
+ }
+}
\ No newline at end of file
diff --git a/runtime/Cargo.lock b/runtime/Cargo.lock
index e6db9da3..c6375c26 100644
--- a/runtime/Cargo.lock
+++ b/runtime/Cargo.lock
@@ -2632,6 +2632,7 @@ dependencies = [
"base64 0.22.1",
"calamine",
"cbc",
+ "cfg-if",
"cipher",
"crossbeam-channel",
"file-format",
@@ -2660,6 +2661,7 @@ dependencies = [
"tokio",
"tokio-stream",
"url",
+ "windows-registry 0.5.2",
]
[[package]]
@@ -3978,7 +3980,7 @@ dependencies = [
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
- "windows-registry",
+ "windows-registry 0.4.0",
]
[[package]]
@@ -5949,15 +5951,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3"
dependencies = [
"windows-result",
- "windows-strings",
+ "windows-strings 0.3.1",
"windows-targets 0.53.0",
]
[[package]]
-name = "windows-result"
-version = "0.3.2"
+name = "windows-registry"
+version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
+checksum = "b3bab093bdd303a1240bb99b8aba8ea8a69ee19d34c9e2ef9594e708a4878820"
+dependencies = [
+ "windows-link",
+ "windows-result",
+ "windows-strings 0.4.2",
+]
+
+[[package]]
+name = "windows-result"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
dependencies = [
"windows-link",
]
@@ -5971,6 +5984,15 @@ dependencies = [
"windows-link",
]
+[[package]]
+name = "windows-strings"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
+dependencies = [
+ "windows-link",
+]
+
[[package]]
name = "windows-sys"
version = "0.42.0"
diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml
index 1687f162..6bb18649 100644
--- a/runtime/Cargo.toml
+++ b/runtime/Cargo.toml
@@ -37,6 +37,7 @@ file-format = "0.27.0"
calamine = "0.27.0"
pdfium-render = "0.8.31"
sys-locale = "0.3.2"
+cfg-if = "1.0.0"
# Fixes security vulnerability downstream, where the upstream is not fixed yet:
url = "2.5"
@@ -50,5 +51,8 @@ reqwest = { version = "0.12.15", features = ["native-tls-vendored"] }
# Fixes security vulnerability downstream, where the upstream is not fixed yet:
openssl = "0.10.72"
+[target.'cfg(target_os = "windows")'.dependencies]
+windows-registry = "0.5.2"
+
[features]
custom-protocol = ["tauri/custom-protocol"]
diff --git a/runtime/src/environment.rs b/runtime/src/environment.rs
index af3435b1..dbcf7361 100644
--- a/runtime/src/environment.rs
+++ b/runtime/src/environment.rs
@@ -1,4 +1,6 @@
+use std::env;
use std::sync::OnceLock;
+use log::info;
use rocket::get;
use sys_locale::get_locale;
use crate::api_token::APIToken;
@@ -43,4 +45,98 @@ pub fn read_user_language(_token: APIToken) -> String {
log::warn!("Could not determine the system language. Use default 'en-US'.");
String::from("en-US")
})
+}
+
+#[get("/system/enterprise/config/id")]
+pub fn read_enterprise_env_config_id(_token: APIToken) -> Option {
+ //
+ // When we are on a Windows machine, we try to read the enterprise config from
+ // the Windows registry. In case we can't find the registry key, or we are on a
+ // macOS or Linux machine, we try to read the enterprise config from the
+ // environment variables.
+ //
+ // The registry key is:
+ // HKEY_CURRENT_USER\Software\github\MindWork AI Studio\Enterprise IT
+ //
+ // In this registry key, we expect the following values:
+ // - config_id
+ //
+ // The environment variable is:
+ // MINDWORK_AI_STUDIO_ENTERPRISE_CONFIG_ID
+ //
+ get_enterprise_configuration(
+ "config_id",
+ "MINDWORK_AI_STUDIO_ENTERPRISE_CONFIG_ID",
+ )
+}
+
+#[get("/system/enterprise/config/server")]
+pub fn read_enterprise_env_config_server_url(_token: APIToken) -> Option {
+ //
+ // When we are on a Windows machine, we try to read the enterprise config from
+ // the Windows registry. In case we can't find the registry key, or we are on a
+ // macOS or Linux machine, we try to read the enterprise config from the
+ // environment variables.
+ //
+ // The registry key is:
+ // HKEY_CURRENT_USER\Software\github\MindWork AI Studio\Enterprise IT
+ //
+ // In this registry key, we expect the following values:
+ // - config_server_url
+ //
+ // The environment variable is:
+ // MINDWORK_AI_STUDIO_ENTERPRISE_CONFIG_SERVER_URL
+ //
+ get_enterprise_configuration(
+ "config_server_url",
+ "MINDWORK_AI_STUDIO_ENTERPRISE_CONFIG_SERVER_URL",
+ )
+}
+
+fn get_enterprise_configuration(reg_value: &str, env_name: &str) -> Option {
+ info!("Trying to read the enterprise environment for some predefined configuration.");
+ cfg_if::cfg_if! {
+ if #[cfg(target_os = "windows")] {
+ info!(r"Detected a Windows machine, trying to read the registry key 'HKEY_CURRENT_USER\Software\github\MindWork AI Studio\Enterprise IT' or the environment variables");
+ use windows_registry::*;
+ let key_path = r"Software\github\MindWork AI Studio\Enterprise IT";
+ let key = match CURRENT_USER.open(key_path) {
+ Ok(key) => key,
+ Err(_) => {
+ info!(r"Could not read the registry key HKEY_CURRENT_USER\Software\github\MindWork AI Studio\Enterprise IT. Falling back to environment variables.");
+ return match env::var(env_name) {
+ Ok(val) => {
+ info!("Falling back to the environment variable '{}' was successful.", env_name);
+ Some(val)
+ },
+ Err(_) => {
+ info!("Falling back to the environment variable '{}' was not successful. It appears that this is not an enterprise environment.", env_name);
+ None
+ },
+ }
+ },
+ };
+
+ match key.get_string(reg_value) {
+ Ok(val) => Some(val),
+ Err(_) => {
+ info!(r"We could read the registry key 'HKEY_CURRENT_USER\Software\github\MindWork AI Studio\Enterprise IT', but the value '{}' could not be read. Falling back to environment variables.", reg_value);
+ match env::var(env_name) {
+ Ok(val) => {
+ info!("Falling back to the environment variable '{}' was successful.", env_name);
+ Some(val)
+ },
+ Err(_) => {
+ info!("Falling back to the environment variable '{}' was not successful. It appears that this is not an enterprise environment.", env_name);
+ None
+ }
+ }
+ },
+ }
+ } else {
+ // In the case of macOS or Linux, we just read the environment variable:
+ info!(r"Detected a Unix machine, trying to read the environment variable '{}'.", env_name)
+ env::var(env_name).ok()
+ }
+ }
}
\ No newline at end of file
diff --git a/runtime/src/runtime_api.rs b/runtime/src/runtime_api.rs
index 459fc936..a90b43f1 100644
--- a/runtime/src/runtime_api.rs
+++ b/runtime/src/runtime_api.rs
@@ -78,6 +78,8 @@ pub fn start_runtime_api() {
crate::environment::get_data_directory,
crate::environment::get_config_directory,
crate::environment::read_user_language,
+ crate::environment::read_enterprise_env_config_id,
+ crate::environment::read_enterprise_env_config_server_url,
crate::file_data::extract_data,
crate::file_data::read_pdf,
crate::log::get_log_paths,