mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-07-14 08:26:26 +00:00
Enabled WebKit permission handling for Linux audio capture (#854)
Some checks are pending
Build and Release / Determine run mode (push) Waiting to run
Build and Release / Read metadata (push) Blocked by required conditions
Build and Release / Sync Flatpak repo (push) Blocked by required conditions
Build and Release / Collect Flatpak artifacts (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Prepare & create release (push) Blocked by required conditions
Build and Release / Publish release (push) Blocked by required conditions
Some checks are pending
Build and Release / Determine run mode (push) Waiting to run
Build and Release / Read metadata (push) Blocked by required conditions
Build and Release / Sync Flatpak repo (push) Blocked by required conditions
Build and Release / Collect Flatpak artifacts (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Prepare & create release (push) Blocked by required conditions
Build and Release / Publish release (push) Blocked by required conditions
This commit is contained in:
parent
50d7b56ac0
commit
5dc6282908
@ -1,7 +1,6 @@
|
||||
@using AIStudio.Settings
|
||||
@using AIStudio.Settings.DataModel
|
||||
@using AIStudio.Tools.Rust
|
||||
@using AIStudio.Tools.Services
|
||||
@inherits SettingsPanelBase
|
||||
|
||||
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.Apps" HeaderText="@T("App Options")">
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
- Improved update guidance for Flatpak installations and added an enterprise option that lets organizations manage updates entirely through their IT department.
|
||||
- Fixed an issue that could leave AI Studio unresponsive after waking the computer from sleep.
|
||||
- Fixed enterprise configuration plugins from Windows-created ZIP files not loading correctly on Linux when the ZIP contained plugin files inside a folder.
|
||||
- Fixed voice recording not starting on Linux.
|
||||
- Upgraded Rust to v1.97.0.
|
||||
- Upgraded Tauri to v2.11.5.
|
||||
- Upgraded common dependencies.
|
||||
1
runtime/Cargo.lock
generated
1
runtime/Cargo.lock
generated
@ -4042,6 +4042,7 @@ dependencies = [
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"webkit2gtk",
|
||||
"whoami",
|
||||
"windows-native-keyring-store",
|
||||
"windows-registry",
|
||||
|
||||
@ -69,6 +69,7 @@ apple-native-keyring-store = { version = "1.0.0", features = ["keychain"] }
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
dbus-secret-service-keyring-store = { version = "1.0.0", features = ["crypto-rust"] }
|
||||
webkit2gtk = { version = "2.0.2", features = ["v2_8"] }
|
||||
|
||||
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
||||
tauri-plugin-global-shortcut = "2"
|
||||
|
||||
@ -30,9 +30,16 @@ use crate::environment::{
|
||||
use crate::log::switch_to_file_logging;
|
||||
use crate::pdfium::PDFIUM_LIB_PATH;
|
||||
use crate::qdrant_edge_database::{start_qdrant_edge_database, stop_qdrant_edge_database};
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
use crate::dotnet::create_startup_env_file;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use webkit2gtk::glib::Cast;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use webkit2gtk::{PermissionRequestExt, UserMediaPermissionRequestExt};
|
||||
|
||||
/// The Tauri main window.
|
||||
pub static MAIN_WINDOW: Lazy<Mutex<Option<WebviewWindow>>> = Lazy::new(|| Mutex::new(None));
|
||||
|
||||
@ -138,6 +145,9 @@ pub fn start_tauri() {
|
||||
// Get the main window:
|
||||
let window = app.get_webview_window("main").expect("Failed to get main window.");
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
register_linux_permission_request_handler(&window);
|
||||
|
||||
// Register a callback for window events, such as file drops. We have to use
|
||||
// this handler in addition to the app event handler, because file drop events
|
||||
// are only available in the window event handler (is a bug, cf. https://github.com/tauri-apps/tauri/issues/14338):
|
||||
@ -247,6 +257,69 @@ fn same_origin(left: &tauri::Url, right: &tauri::Url) -> bool {
|
||||
&& left.port_or_known_default() == right.port_or_known_default()
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", test))]
|
||||
fn should_allow_audio_capture(
|
||||
approved_app_url: Option<&tauri::Url>,
|
||||
current_webview_url: Option<&tauri::Url>,
|
||||
requests_audio: bool,
|
||||
requests_video: bool,
|
||||
) -> bool {
|
||||
requests_audio
|
||||
&& !requests_video
|
||||
&& approved_app_url.is_some_and(is_local_http_url)
|
||||
&& approved_app_url
|
||||
.zip(current_webview_url)
|
||||
.is_some_and(|(approved, current)| same_origin(approved, current))
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn register_linux_permission_request_handler(window: &WebviewWindow) {
|
||||
if let Err(error) = window.with_webview(|platform_webview| {
|
||||
use webkit2gtk::WebViewExt;
|
||||
use webkit2gtk::UserMediaPermissionRequest;
|
||||
|
||||
let webview = platform_webview.inner();
|
||||
webview.connect_permission_request(|webview, request| {
|
||||
let Some(user_media_request) = request.downcast_ref::<UserMediaPermissionRequest>() else {
|
||||
request.deny();
|
||||
info!(Source = "Tauri"; "Denied a non-user-media WebKit permission request.");
|
||||
return true;
|
||||
};
|
||||
|
||||
let current_webview_url = webview
|
||||
.uri()
|
||||
.and_then(|uri| tauri::Url::parse(uri.as_str()).ok());
|
||||
let approved_app_url = APPROVED_APP_URL.lock().unwrap().clone();
|
||||
let origin_matches = approved_app_url
|
||||
.as_ref()
|
||||
.zip(current_webview_url.as_ref())
|
||||
.is_some_and(|(approved, current)| same_origin(approved, current));
|
||||
let requests_audio = user_media_request.is_for_audio_device();
|
||||
let requests_video = user_media_request.is_for_video_device();
|
||||
let allow = should_allow_audio_capture(
|
||||
approved_app_url.as_ref(),
|
||||
current_webview_url.as_ref(),
|
||||
requests_audio,
|
||||
requests_video,
|
||||
);
|
||||
|
||||
if allow {
|
||||
request.allow();
|
||||
} else {
|
||||
request.deny();
|
||||
}
|
||||
|
||||
info!(
|
||||
Source = "Tauri";
|
||||
"Handled WebKit user-media permission request: allowed={allow}, origin_matches={origin_matches}, audio={requests_audio}, video={requests_video}."
|
||||
);
|
||||
true
|
||||
});
|
||||
}) {
|
||||
error!(Source = "Tauri"; "Failed to register the Linux WebKit permission request handler: {error}");
|
||||
}
|
||||
}
|
||||
|
||||
fn should_open_in_system_browser<R: tauri::Runtime>(webview: &tauri::Webview<R>, url: &tauri::Url) -> bool {
|
||||
match url.scheme() {
|
||||
"mailto" | "tel" => return true,
|
||||
@ -1139,4 +1212,42 @@ mod tests {
|
||||
assert!(!is_tauri_asset_url(&url));
|
||||
assert!(!is_local_http_url(&url));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn audio_capture_is_allowed_for_exact_approved_app_origin() {
|
||||
let approved = tauri::Url::parse("http://localhost:12345/").unwrap();
|
||||
let current = tauri::Url::parse("http://localhost:12345/voice-recorder").unwrap();
|
||||
|
||||
assert!(should_allow_audio_capture(Some(&approved), Some(¤t), true, false));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn audio_capture_is_denied_for_wrong_port() {
|
||||
let approved = tauri::Url::parse("http://localhost:12345/").unwrap();
|
||||
let current = tauri::Url::parse("http://localhost:54321/").unwrap();
|
||||
|
||||
assert!(!should_allow_audio_capture(Some(&approved), Some(¤t), true, false));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn audio_capture_is_denied_for_external_origin() {
|
||||
let approved = tauri::Url::parse("http://localhost:12345/").unwrap();
|
||||
let current = tauri::Url::parse("https://example.com/").unwrap();
|
||||
|
||||
assert!(!should_allow_audio_capture(Some(&approved), Some(¤t), true, false));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn video_capture_is_denied() {
|
||||
let approved = tauri::Url::parse("http://localhost:12345/").unwrap();
|
||||
|
||||
assert!(!should_allow_audio_capture(Some(&approved), Some(&approved), false, true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn combined_audio_and_video_capture_is_denied() {
|
||||
let approved = tauri::Url::parse("http://localhost:12345/").unwrap();
|
||||
|
||||
assert!(!should_allow_audio_capture(Some(&approved), Some(&approved), true, true));
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user