From 24c14ac94ea53e93ce700ebe1c463fb8f049b54c Mon Sep 17 00:00:00 2001 From: gatowololo Date: Thu, 27 Jun 2019 10:23:52 -0700 Subject: [PATCH 1/5] Factored out permission_state_invocation_results API to GlobalScope Instead of Window --- components/script/dom/globalscope.rs | 11 +++++++++++ components/script/dom/permissions.rs | 6 ------ components/script/dom/window.rs | 11 ----------- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index d86104c1ee6..e631c9bfc9c 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -5,6 +5,7 @@ use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::BroadcastChannelBinding::BroadcastChannelMethods; use crate::dom::bindings::codegen::Bindings::EventSourceBinding::EventSourceBinding::EventSourceMethods; +use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionState; use crate::dom::bindings::codegen::Bindings::VoidFunctionBinding::VoidFunction; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use crate::dom::bindings::codegen::Bindings::WorkerGlobalScopeBinding::WorkerGlobalScopeMethods; @@ -189,6 +190,9 @@ pub struct GlobalScope { /// The origin of the globalscope origin: MutableOrigin, + /// A map for storing the previous permission state read results. + permission_state_invocation_results: DomRefCell>, + /// The microtask queue associated with this global. /// /// It is refcounted because windows in the same script thread share the @@ -575,6 +579,7 @@ impl GlobalScope { timers: OneshotTimers::new(scheduler_chan), init_timers: Default::default(), origin, + permission_state_invocation_results: Default::default(), microtask_queue, list_auto_close_worker: Default::default(), event_source_tracker: DOMTracker::new(), @@ -1701,6 +1706,12 @@ impl GlobalScope { } } + pub fn permission_state_invocation_results( + &self, + ) -> &DomRefCell> { + &self.permission_state_invocation_results + } + pub fn track_worker(&self, closing_worker: Arc) { self.list_auto_close_worker .borrow_mut() diff --git a/components/script/dom/permissions.rs b/components/script/dom/permissions.rs index cb91fb692f9..e31ce563262 100644 --- a/components/script/dom/permissions.rs +++ b/components/script/dom/permissions.rs @@ -143,7 +143,6 @@ impl Permissions { // (Revoke) Step 3. let globalscope = self.global(); globalscope - .as_window() .permission_state_invocation_results() .borrow_mut() .remove(&root_desc.name.to_string()); @@ -176,7 +175,6 @@ impl Permissions { // (Revoke) Step 3. let globalscope = self.global(); globalscope - .as_window() .permission_state_invocation_results() .borrow_mut() .remove(&root_desc.name.to_string()); @@ -269,7 +267,6 @@ impl PermissionAlgorithm for Permissions { ); globalscope - .as_window() .permission_state_invocation_results() .borrow_mut() .insert(perm_name.to_string(), state); @@ -309,7 +306,6 @@ pub fn get_descriptor_permission_state( PermissionState::Granted } else { settings - .as_window() .permission_state_invocation_results() .borrow_mut() .remove(&permission_name.to_string()); @@ -323,7 +319,6 @@ pub fn get_descriptor_permission_state( // Step 3. if let Some(prev_result) = settings - .as_window() .permission_state_invocation_results() .borrow() .get(&permission_name.to_string()) @@ -333,7 +328,6 @@ pub fn get_descriptor_permission_state( // Store the invocation result settings - .as_window() .permission_state_invocation_results() .borrow_mut() .insert(permission_name.to_string(), state); diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index c2679c2899a..e06eb243856 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -8,7 +8,6 @@ use crate::dom::bindings::codegen::Bindings::DocumentBinding::{ }; use crate::dom::bindings::codegen::Bindings::HistoryBinding::HistoryBinding::HistoryMethods; use crate::dom::bindings::codegen::Bindings::MediaQueryListBinding::MediaQueryListBinding::MediaQueryListMethods; -use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionState; use crate::dom::bindings::codegen::Bindings::RequestBinding::RequestInit; use crate::dom::bindings::codegen::Bindings::VoidFunctionBinding::VoidFunction; use crate::dom::bindings::codegen::Bindings::WindowBinding::{ @@ -275,9 +274,6 @@ pub struct Window { #[ignore_malloc_size_of = "defined in webxr"] webxr_registry: webxr_api::Registry, - /// A map for storing the previous permission state read results. - permission_state_invocation_results: DomRefCell>, - /// All of the elements that have an outstanding image request that was /// initiated by layout during a reflow. They are stored in the script thread /// to ensure that the element can be marked dirty when the image data becomes @@ -476,12 +472,6 @@ impl Window { Worklet::new(self, WorkletGlobalScopeType::Paint) } - pub fn permission_state_invocation_results( - &self, - ) -> &DomRefCell> { - &self.permission_state_invocation_results - } - pub fn pending_image_notification(&self, response: PendingImageResponse) { //XXXjdm could be more efficient to send the responses to the layout thread, // rather than making the layout thread talk to the image cache to @@ -2333,7 +2323,6 @@ impl Window { webgl_chan, webvr_chan, webxr_registry, - permission_state_invocation_results: Default::default(), pending_layout_images: Default::default(), unminified_js_dir: Default::default(), test_worklet: Default::default(), From 675b36dde561810af94879e5263e656b784a2364 Mon Sep 17 00:00:00 2001 From: gatowololo Date: Wed, 26 Jun 2019 14:44:44 -0700 Subject: [PATCH 2/5] Move tinyfiledialog out of script into embedder. --- Cargo.lock | 1 - components/embedder_traits/lib.rs | 11 +++++ components/script/Cargo.toml | 3 -- components/script/dom/globalscope.rs | 9 ++++ components/script/dom/permissions.rs | 72 +++++++++++++--------------- ports/glutin/browser.rs | 30 +++++++++++- 6 files changed, 81 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2c561e97ff5..8aca24486c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4762,7 +4762,6 @@ dependencies = [ "swapper", "tendril", "time", - "tinyfiledialogs", "unicode-bidi", "unicode-segmentation", "url", diff --git a/components/embedder_traits/lib.rs b/components/embedder_traits/lib.rs index c13ad617920..71eb7876eca 100644 --- a/components/embedder_traits/lib.rs +++ b/components/embedder_traits/lib.rs @@ -185,6 +185,9 @@ pub enum EmbedderMsg { GetSelectedBluetoothDevice(Vec, IpcSender>), /// Open file dialog to select files. Set boolean flag to true allows to select multiple files. SelectFiles(Vec, bool, IpcSender>>), + /// Open yes/no message for user to allow permission specified by first String. + /// With dialog title specified by second String. + PromptPermission(String, String, IpcSender), /// Request to present an IME to the user when an editable element is focused. ShowIME(InputMethodType), /// Request to hide the IME when the editable element is blurred. @@ -222,6 +225,7 @@ impl Debug for EmbedderMsg { EmbedderMsg::Panic(..) => write!(f, "Panic"), EmbedderMsg::GetSelectedBluetoothDevice(..) => write!(f, "GetSelectedBluetoothDevice"), EmbedderMsg::SelectFiles(..) => write!(f, "SelectFiles"), + EmbedderMsg::PromptPermission(..) => write!(f, "PromptPermission"), EmbedderMsg::ShowIME(..) => write!(f, "ShowIME"), EmbedderMsg::HideIME => write!(f, "HideIME"), EmbedderMsg::Shutdown => write!(f, "Shutdown"), @@ -299,3 +303,10 @@ pub enum MediaSessionEvent { /// Indicates that the position state is set. SetPositionState(MediaPositionState), } + +// Status for prompting user for permission. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum PermissionRequest { + Granted, + Denied, +} diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index 03eac6cae65..9c5995c1c89 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -29,9 +29,6 @@ phf_codegen = "0.8" phf_shared = "0.8" serde_json = "1.0" -[target.'cfg(target_os = "linux")'.dependencies] -tinyfiledialogs = "3.0" - [dependencies] accountable-refcell = {version = "0.2.0", optional = true} app_units = "0.7" diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index e631c9bfc9c..f46a07bbcb2 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -61,6 +61,7 @@ use crate::timers::{OneshotTimers, TimerCallback}; use content_security_policy::CspList; use devtools_traits::{PageError, ScriptToDevtoolsControlMsg}; use dom_struct::dom_struct; +use embedder_traits::EmbedderMsg; use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::router::ROUTER; use js::glue::{IsWrapper, UnwrapObjectDynamic}; @@ -1917,6 +1918,14 @@ impl GlobalScope { &self.script_to_constellation_chan } + pub fn send_to_embedder(&self, msg: EmbedderMsg) { + self.send_to_constellation(ScriptMsg::ForwardToEmbedder(msg)); + } + + pub fn send_to_constellation(&self, msg: ScriptMsg) { + self.script_to_constellation_chan().send(msg).unwrap(); + } + pub fn scheduler_chan(&self) -> &IpcSender { &self.scheduler_chan } diff --git a/components/script/dom/permissions.rs b/components/script/dom/permissions.rs index e31ce563262..e456571cbc3 100644 --- a/components/script/dom/permissions.rs +++ b/components/script/dom/permissions.rs @@ -19,15 +19,14 @@ use crate::dom::promise::Promise; use crate::realms::{AlreadyInRealm, InRealm}; use crate::script_runtime::JSContext; use dom_struct::dom_struct; +use embedder_traits::{EmbedderMsg, PermissionRequest}; +use ipc_channel::ipc; use js::conversions::ConversionResult; use js::jsapi::JSObject; use js::jsval::{ObjectValue, UndefinedValue}; use servo_config::pref; use std::rc::Rc; -#[cfg(target_os = "linux")] -use tinyfiledialogs::{self, MessageBoxIcon, YesNo}; -#[cfg(target_os = "linux")] const DIALOG_TITLE: &'static str = "Permission request dialog"; const NONSECURE_DIALOG_MESSAGE: &'static str = "feature is only safe to use in secure context,\ but servo can't guarantee\n that the current context is secure. Do you want to proceed and grant permission?"; @@ -258,14 +257,10 @@ impl PermissionAlgorithm for Permissions { PermissionState::Prompt => { let perm_name = status.get_query(); - let globalscope = GlobalScope::current().expect("No current global object"); - // https://w3c.github.io/permissions/#request-permission-to-use (Step 3 - 4) - let state = prompt_user( - &format!("{} {} ?", REQUEST_DIALOG_MESSAGE, perm_name.clone()), - globalscope.is_headless(), - ); - + let globalscope = GlobalScope::current().expect("No current global object"); + let prompt = format!("{} {} ?", REQUEST_DIALOG_MESSAGE, perm_name.clone()); + let state = prompt_user_from_embedder(prompt, &globalscope); globalscope .permission_state_invocation_results() .borrow_mut() @@ -289,7 +284,7 @@ pub fn get_descriptor_permission_state( env_settings_obj: Option<&GlobalScope>, ) -> PermissionState { // Step 1. - let settings = match env_settings_obj { + let globalscope = match env_settings_obj { Some(env_settings_obj) => DomRoot::from_ref(env_settings_obj), None => GlobalScope::current().expect("No current global object"), }; @@ -305,20 +300,18 @@ pub fn get_descriptor_permission_state( if pref!(dom.permissions.testing.allowed_in_nonsecure_contexts) { PermissionState::Granted } else { - settings + globalscope .permission_state_invocation_results() .borrow_mut() .remove(&permission_name.to_string()); - prompt_user( - &format!("The {} {}", permission_name, NONSECURE_DIALOG_MESSAGE), - settings.is_headless(), - ) + let prompt = format!("The {} {}", permission_name, NONSECURE_DIALOG_MESSAGE); + prompt_user_from_embedder(prompt, &globalscope) } }; // Step 3. - if let Some(prev_result) = settings + if let Some(prev_result) = globalscope .permission_state_invocation_results() .borrow() .get(&permission_name.to_string()) @@ -327,7 +320,7 @@ pub fn get_descriptor_permission_state( } // Store the invocation result - settings + globalscope .permission_state_invocation_results() .borrow_mut() .insert(permission_name.to_string(), state); @@ -336,28 +329,6 @@ pub fn get_descriptor_permission_state( state } -#[cfg(target_os = "linux")] -fn prompt_user(message: &str, headless: bool) -> PermissionState { - if headless { - return PermissionState::Denied; - } - match tinyfiledialogs::message_box_yes_no( - DIALOG_TITLE, - message, - MessageBoxIcon::Question, - YesNo::No, - ) { - YesNo::Yes => PermissionState::Granted, - YesNo::No => PermissionState::Denied, - } -} - -#[cfg(not(target_os = "linux"))] -fn prompt_user(_message: &str, _headless: bool) -> PermissionState { - // TODO popup only supported on linux - PermissionState::Denied -} - // https://w3c.github.io/permissions/#allowed-in-non-secure-contexts fn allowed_in_nonsecure_contexts(permission_name: &PermissionName) -> bool { match *permission_name { @@ -385,3 +356,24 @@ fn allowed_in_nonsecure_contexts(permission_name: &PermissionName) -> bool { PermissionName::Persistent_storage => false, } } + +fn prompt_user_from_embedder(prompt: String, gs: &GlobalScope) -> PermissionState { + let (sender, receiver) = ipc::channel().expect("Failed to create IPC channel!"); + gs.send_to_embedder(EmbedderMsg::PromptPermission( + prompt, + DIALOG_TITLE.to_string(), + sender, + )); + + match receiver.recv() { + Ok(PermissionRequest::Granted) => PermissionState::Granted, + Ok(PermissionRequest::Denied) => PermissionState::Denied, + Err(e) => { + warn!( + "Failed to receive permission state from embedder ({:?}).", + e + ); + PermissionState::Denied + }, + } +} diff --git a/ports/glutin/browser.rs b/ports/glutin/browser.rs index 1b21bfebf5f..b250a38662a 100644 --- a/ports/glutin/browser.rs +++ b/ports/glutin/browser.rs @@ -7,7 +7,9 @@ use crate::window_trait::{WindowPortsMethods, LINE_HEIGHT}; use euclid::{Point2D, Vector2D}; use keyboard_types::{Key, KeyboardEvent, Modifiers, ShortcutMatcher}; use servo::compositing::windowing::{WebRenderDebugOption, WindowEvent}; -use servo::embedder_traits::{EmbedderMsg, FilterPattern, PromptDefinition, PromptOrigin, PromptResult}; +use servo::embedder_traits::{ + EmbedderMsg, FilterPattern, PermissionRequest, PromptDefinition, PromptOrigin, PromptResult, +}; use servo::msg::constellation_msg::TopLevelBrowsingContextId as BrowserId; use servo::msg::constellation_msg::TraversalDirection; use servo::net_traits::pub_domains::is_reg_domain; @@ -491,6 +493,10 @@ where self.event_queue.push(WindowEvent::SendError(None, reason)); }; }, + EmbedderMsg::PromptPermission(message, dialog_title, sender) => { + let permission_state = prompt_user(&message, &dialog_title); + let _ = sender.send(permission_state); + } EmbedderMsg::ShowIME(_kind) => { debug!("ShowIME received"); }, @@ -513,6 +519,28 @@ where } } +#[cfg(target_os = "linux")] +fn prompt_user(prompt: &str, dialog_title: &str) -> PermissionRequest { + if opts::get().headless { + return PermissionRequest::Denied; + } + match tinyfiledialogs::message_box_yes_no( + dialog_title, + prompt, + MessageBoxIcon::Question, + YesNo::No, + ) { + YesNo::Yes => PermissionRequest::Granted, + YesNo::No => PermissionRequest::Denied, + } +} + +#[cfg(not(target_os = "linux"))] +fn prompt_user(_prompt: &str, _dialog_title: &str) -> PermissionRequest { + // TODO popup only supported on linux + PermissionRequest::Denied +} + #[cfg(target_os = "linux")] fn platform_get_selected_devices(devices: Vec) -> Option { let picker_name = "Choose a device"; From f75d547c614e7e610c50315a75e5d8a145fdc3e8 Mon Sep 17 00:00:00 2001 From: Iulian Gabriel Radu Date: Fri, 28 Feb 2020 11:44:33 +0200 Subject: [PATCH 3/5] Delegate permission prompt dialog formatting to embedders --- components/embedder_traits/lib.rs | 30 ++++++++++++++++--- components/script/dom/permissions.rs | 44 ++++++++++++++++++---------- ports/glutin/browser.rs | 27 +++++++++++++---- 3 files changed, 76 insertions(+), 25 deletions(-) diff --git a/components/embedder_traits/lib.rs b/components/embedder_traits/lib.rs index 71eb7876eca..cacaf80ca50 100644 --- a/components/embedder_traits/lib.rs +++ b/components/embedder_traits/lib.rs @@ -185,9 +185,8 @@ pub enum EmbedderMsg { GetSelectedBluetoothDevice(Vec, IpcSender>), /// Open file dialog to select files. Set boolean flag to true allows to select multiple files. SelectFiles(Vec, bool, IpcSender>>), - /// Open yes/no message for user to allow permission specified by first String. - /// With dialog title specified by second String. - PromptPermission(String, String, IpcSender), + /// Open interface to request permission specified by prompt. + PromptPermission(PermissionPrompt, IpcSender), /// Request to present an IME to the user when an editable element is focused. ShowIME(InputMethodType), /// Request to hide the IME when the editable element is blurred. @@ -304,7 +303,30 @@ pub enum MediaSessionEvent { SetPositionState(MediaPositionState), } -// Status for prompting user for permission. +/// Enum with variants that match the DOM PermissionName enum +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum PermissionName { + Geolocation, + Notifications, + Push, + Midi, + Camera, + Microphone, + Speaker, + DeviceInfo, + BackgroundSync, + Bluetooth, + PersistentStorage, +} + +/// Information required to display a permission prompt +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum PermissionPrompt { + Insecure(PermissionName), + Request(PermissionName), +} + +/// Status for prompting user for permission. #[derive(Clone, Debug, Deserialize, Serialize)] pub enum PermissionRequest { Granted, diff --git a/components/script/dom/permissions.rs b/components/script/dom/permissions.rs index e456571cbc3..37887f60773 100644 --- a/components/script/dom/permissions.rs +++ b/components/script/dom/permissions.rs @@ -19,7 +19,7 @@ use crate::dom::promise::Promise; use crate::realms::{AlreadyInRealm, InRealm}; use crate::script_runtime::JSContext; use dom_struct::dom_struct; -use embedder_traits::{EmbedderMsg, PermissionRequest}; +use embedder_traits::{self, EmbedderMsg, PermissionPrompt, PermissionRequest}; use ipc_channel::ipc; use js::conversions::ConversionResult; use js::jsapi::JSObject; @@ -27,11 +27,6 @@ use js::jsval::{ObjectValue, UndefinedValue}; use servo_config::pref; use std::rc::Rc; -const DIALOG_TITLE: &'static str = "Permission request dialog"; -const NONSECURE_DIALOG_MESSAGE: &'static str = "feature is only safe to use in secure context,\ - but servo can't guarantee\n that the current context is secure. Do you want to proceed and grant permission?"; -const REQUEST_DIALOG_MESSAGE: &'static str = "Do you want to grant permission for"; - pub trait PermissionAlgorithm { type Descriptor; type Status; @@ -256,10 +251,11 @@ impl PermissionAlgorithm for Permissions { // Step 3. PermissionState::Prompt => { let perm_name = status.get_query(); + let prompt = + PermissionPrompt::Request(embedder_traits::PermissionName::from(perm_name)); // https://w3c.github.io/permissions/#request-permission-to-use (Step 3 - 4) let globalscope = GlobalScope::current().expect("No current global object"); - let prompt = format!("{} {} ?", REQUEST_DIALOG_MESSAGE, perm_name.clone()); let state = prompt_user_from_embedder(prompt, &globalscope); globalscope .permission_state_invocation_results() @@ -305,8 +301,10 @@ pub fn get_descriptor_permission_state( .borrow_mut() .remove(&permission_name.to_string()); - let prompt = format!("The {} {}", permission_name, NONSECURE_DIALOG_MESSAGE); - prompt_user_from_embedder(prompt, &globalscope) + prompt_user_from_embedder( + PermissionPrompt::Insecure(embedder_traits::PermissionName::from(permission_name)), + &globalscope, + ) } }; @@ -357,13 +355,9 @@ fn allowed_in_nonsecure_contexts(permission_name: &PermissionName) -> bool { } } -fn prompt_user_from_embedder(prompt: String, gs: &GlobalScope) -> PermissionState { +fn prompt_user_from_embedder(prompt: PermissionPrompt, gs: &GlobalScope) -> PermissionState { let (sender, receiver) = ipc::channel().expect("Failed to create IPC channel!"); - gs.send_to_embedder(EmbedderMsg::PromptPermission( - prompt, - DIALOG_TITLE.to_string(), - sender, - )); + gs.send_to_embedder(EmbedderMsg::PromptPermission(prompt, sender)); match receiver.recv() { Ok(PermissionRequest::Granted) => PermissionState::Granted, @@ -377,3 +371,23 @@ fn prompt_user_from_embedder(prompt: String, gs: &GlobalScope) -> PermissionStat }, } } + +impl From for embedder_traits::PermissionName { + fn from(permission_name: PermissionName) -> Self { + match permission_name { + PermissionName::Geolocation => embedder_traits::PermissionName::Geolocation, + PermissionName::Notifications => embedder_traits::PermissionName::Notifications, + PermissionName::Push => embedder_traits::PermissionName::Push, + PermissionName::Midi => embedder_traits::PermissionName::Midi, + PermissionName::Camera => embedder_traits::PermissionName::Camera, + PermissionName::Microphone => embedder_traits::PermissionName::Microphone, + PermissionName::Speaker => embedder_traits::PermissionName::Speaker, + PermissionName::Device_info => embedder_traits::PermissionName::DeviceInfo, + PermissionName::Background_sync => embedder_traits::PermissionName::BackgroundSync, + PermissionName::Bluetooth => embedder_traits::PermissionName::Bluetooth, + PermissionName::Persistent_storage => { + embedder_traits::PermissionName::PersistentStorage + }, + } + } +} diff --git a/ports/glutin/browser.rs b/ports/glutin/browser.rs index b250a38662a..c46b0bd8337 100644 --- a/ports/glutin/browser.rs +++ b/ports/glutin/browser.rs @@ -9,6 +9,7 @@ use keyboard_types::{Key, KeyboardEvent, Modifiers, ShortcutMatcher}; use servo::compositing::windowing::{WebRenderDebugOption, WindowEvent}; use servo::embedder_traits::{ EmbedderMsg, FilterPattern, PermissionRequest, PromptDefinition, PromptOrigin, PromptResult, + PermissionPrompt, }; use servo::msg::constellation_msg::TopLevelBrowsingContextId as BrowserId; use servo::msg::constellation_msg::TraversalDirection; @@ -493,8 +494,8 @@ where self.event_queue.push(WindowEvent::SendError(None, reason)); }; }, - EmbedderMsg::PromptPermission(message, dialog_title, sender) => { - let permission_state = prompt_user(&message, &dialog_title); + EmbedderMsg::PromptPermission(prompt, sender) => { + let permission_state = prompt_user(prompt); let _ = sender.send(permission_state); } EmbedderMsg::ShowIME(_kind) => { @@ -520,13 +521,27 @@ where } #[cfg(target_os = "linux")] -fn prompt_user(prompt: &str, dialog_title: &str) -> PermissionRequest { +fn prompt_user(prompt: PermissionPrompt) -> PermissionRequest { if opts::get().headless { return PermissionRequest::Denied; } + + let message = match prompt { + PermissionPrompt::Request(permission_name) => { + format!("Do you want to grant permission for {:?}?", permission_name) + }, + PermissionPrompt::Insecure(permission_name) => { + format!( + "The {:?} feature is only safe to use in secure context, but servo can't guarantee\n\ + that the current context is secure. Do you want to proceed and grant permission?", + permission_name + ) + }, + }; + match tinyfiledialogs::message_box_yes_no( - dialog_title, - prompt, + "Permission request dialog", + &message, MessageBoxIcon::Question, YesNo::No, ) { @@ -536,7 +551,7 @@ fn prompt_user(prompt: &str, dialog_title: &str) -> PermissionRequest { } #[cfg(not(target_os = "linux"))] -fn prompt_user(_prompt: &str, _dialog_title: &str) -> PermissionRequest { +fn prompt_user(_prompt: PermissionPrompt) -> PermissionRequest { // TODO popup only supported on linux PermissionRequest::Denied } From ffba9d0ea762e5614b28a835cbb8ec2f1b44134b Mon Sep 17 00:00:00 2001 From: Iulian Gabriel Radu Date: Fri, 28 Feb 2020 22:02:52 +0200 Subject: [PATCH 4/5] Handle PromptPermission in libsimpleservo --- ports/libsimpleservo/api/src/lib.rs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/ports/libsimpleservo/api/src/lib.rs b/ports/libsimpleservo/api/src/lib.rs index 1d62d642be1..fcbcf89cc6d 100644 --- a/ports/libsimpleservo/api/src/lib.rs +++ b/ports/libsimpleservo/api/src/lib.rs @@ -7,7 +7,9 @@ extern crate log; pub mod gl_glue; -pub use servo::embedder_traits::{MediaSessionPlaybackState, PromptResult}; +pub use servo::embedder_traits::{ + MediaSessionPlaybackState, PermissionPrompt, PermissionRequest, PromptResult, +}; pub use servo::script_traits::{MediaSessionActionType, MouseButton}; use getopts::Options; @@ -615,6 +617,29 @@ impl ServoGlue { EmbedderMsg::Shutdown => { self.callbacks.host_callbacks.on_shutdown_complete(); }, + EmbedderMsg::PromptPermission(prompt, sender) => { + let message = match prompt { + PermissionPrompt::Request(permission_name) => { + format!("Do you want to grant permission for {:?}?", permission_name) + }, + PermissionPrompt::Insecure(permission_name) => { + format!( + "The {:?} feature is only safe to use in secure context, but servo can't guarantee\n\ + that the current context is secure. Do you want to proceed and grant permission?", + permission_name + ) + }, + }; + + let result = match self.callbacks.host_callbacks.prompt_yes_no(message, true) { + PromptResult::Primary => PermissionRequest::Granted, + PromptResult::Secondary | PromptResult::Dismissed => { + PermissionRequest::Denied + }, + }; + + let _ = sender.send(result); + }, EmbedderMsg::ShowIME(..) => { self.callbacks.host_callbacks.on_ime_state_changed(true); }, From 3b85c6a24e254af375e27421de2464b746d104fb Mon Sep 17 00:00:00 2001 From: Iulian Gabriel Radu Date: Sat, 29 Feb 2020 20:34:07 +0200 Subject: [PATCH 5/5] Update expectations for permissions tests --- tests/wpt/metadata/permissions/idlharness.any.js.ini | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/wpt/metadata/permissions/idlharness.any.js.ini b/tests/wpt/metadata/permissions/idlharness.any.js.ini index ec3d06ab7a6..279591e8021 100644 --- a/tests/wpt/metadata/permissions/idlharness.any.js.ini +++ b/tests/wpt/metadata/permissions/idlharness.any.js.ini @@ -1,5 +1,9 @@ [idlharness.any.worker.html] - expected: CRASH + [Permissions interface: operation query(object)] + expected: FAIL + + [Permissions interface: calling query(object) on navigator.permissions with too few arguments must throw TypeError] + expected: FAIL [idlharness.any.html] [Permissions interface: operation query(object)]