From 462a825bd1797f881bc724006dbf2563775a341f Mon Sep 17 00:00:00 2001 From: Zakor Gyula Date: Mon, 13 Feb 2017 12:26:00 +0100 Subject: [PATCH] previous invocation results --- components/script/dom/permissions.rs | 113 ++++++++++++++++------ components/script/dom/permissionstatus.rs | 10 +- components/script/dom/window.rs | 13 ++- 3 files changed, 106 insertions(+), 30 deletions(-) diff --git a/components/script/dom/permissions.rs b/components/script/dom/permissions.rs index dec92bc1548..87d333f5bac 100644 --- a/components/script/dom/permissions.rs +++ b/components/script/dom/permissions.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use dom::bindings::codegen::Bindings::PermissionStatusBinding::{PermissionDescriptor, PermissionName, PermissionState}; +use dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionStatusMethods; use dom::bindings::codegen::Bindings::PermissionsBinding::{self, PermissionsMethods}; use dom::bindings::error::Error; use dom::bindings::js::Root; @@ -22,9 +23,9 @@ use tinyfiledialogs::{self, MessageBoxIcon, YesNo}; #[cfg(target_os = "linux")] const DIALOG_TITLE: &'static str = "Permission request dialog"; -#[cfg(target_os = "linux")] -const QUERY_DIALOG_MESSAGE: &'static str = "Can't guarantee, that the current context is secure. -\t\tStill grant permission for"; +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"; const ROOT_DESC_CONVERSION_ERROR: &'static str = "Can't convert to an IDL value of type PermissionDescriptor"; pub trait PermissionAlgorithm { @@ -114,8 +115,17 @@ impl Permissions { // (Query) Step 6 - 7. &Operation::Query => Bluetooth::permission_query(cx, &p, &bluetooth_desc, &result), - // (Revoke) Step 3 - 4. - &Operation::Revoke => Bluetooth::permission_revoke(&bluetooth_desc, &result), + &Operation::Revoke => { + // (Revoke) Step 3. + let globalscope = self.global(); + globalscope.as_window() + .permission_state_invocation_results() + .borrow_mut() + .remove(&root_desc.name.to_string()); + + // (Revoke) Step 4. + Bluetooth::permission_revoke(&bluetooth_desc, &result) + }, } }, _ => { @@ -136,8 +146,18 @@ impl Permissions { // (Query) Step 7. p.resolve_native(cx, &status); }, - // (Revoke) Step 3 - 4. - &Operation::Revoke => Permissions::permission_revoke(&root_desc, &status), + + &Operation::Revoke => { + // (Revoke) Step 3. + let globalscope = self.global(); + globalscope.as_window() + .permission_state_invocation_results() + .borrow_mut() + .remove(&root_desc.name.to_string()); + + // (Revoke) Step 4. + Permissions::permission_revoke(&root_desc, &status); + }, } }, }; @@ -210,46 +230,85 @@ impl PermissionAlgorithm for Permissions { // Step 1. Permissions::permission_query(cx, promise, descriptor, status); - // TODO: Step 2 - 4: `environment settings object` is not implemented in Servo yet. - // For this reason in the `get_descriptor_permission_state` function we can't decide - // if we have a secure context or not, or store the previous invocation results. - // Without these the remaining steps can't be implemented properly. + match status.State() { + // Step 3. + PermissionState::Prompt => { + let perm_name = status.get_query(); + // https://w3c.github.io/permissions/#request-permission-to-use (Step 3 - 4) + let state = + prompt_user(&format!("{} {} ?", REQUEST_DIALOG_MESSAGE, perm_name.clone())); + + let globalscope = GlobalScope::current(); + globalscope.as_window() + .permission_state_invocation_results() + .borrow_mut() + .insert(perm_name.to_string(), state); + }, + + // Step 2. + _ => return, + } + + // Step 4. + Permissions::permission_query(cx, promise, descriptor, status); } fn permission_revoke(_descriptor: &PermissionDescriptor, _status: &PermissionStatus) {} } // https://w3c.github.io/permissions/#permission-state -pub fn get_descriptor_permission_state(permission_name: PermissionName , - _env_settings_obj: Option<*mut JSObject>) +pub fn get_descriptor_permission_state(permission_name: PermissionName, + env_settings_obj: Option<&GlobalScope>) -> PermissionState { - // TODO: Step 1: If settings wasn’t passed, set it to the current settings object. - // TODO: `environment settings object` is not implemented in Servo yet. + // Step 1. + let settings = match env_settings_obj { + Some(env_settings_obj) => Root::from_ref(env_settings_obj), + None => GlobalScope::current(), + }; // Step 2. // TODO: The `is the environment settings object a non-secure context` check is missing. // The current solution is a workaround with a message box to warn about this, // if the feature is not allowed in non-secure contexcts, // and let the user decide to grant the permission or not. - if !allowed_in_nonsecure_contexts(&permission_name) { - if PREFS.get("dom.permissions.testing.allowed_in_nonsecure_contexts").as_boolean().unwrap_or(false) { - return PermissionState::Granted; - } else { - return prompt_user(permission_name); - } + let state = match allowed_in_nonsecure_contexts(&permission_name) { + true => PermissionState::Prompt, + false => { + match PREFS.get("dom.permissions.testing.allowed_in_nonsecure_contexts").as_boolean().unwrap_or(false) { + true => PermissionState::Granted, + false => { + settings.as_window() + .permission_state_invocation_results() + .borrow_mut() + .remove(&permission_name.to_string()); + prompt_user(&format!("The {} {}", permission_name, NONSECURE_DIALOG_MESSAGE)) + }, + } + }, + }; + + // Step 3. + if let Some(prev_result) = settings.as_window() + .permission_state_invocation_results() + .borrow() + .get(&permission_name.to_string()) { + return prev_result.clone(); } - // TODO: Step 3: Store the invocation results - // TODO: `environment settings object` is not implemented in Servo yet. + // Store the invocation result + settings.as_window() + .permission_state_invocation_results() + .borrow_mut() + .insert(permission_name.to_string(), state); // Step 4. - PermissionState::Granted + state } #[cfg(target_os = "linux")] -fn prompt_user(permission_name: PermissionName) -> PermissionState { +fn prompt_user(message: &str) -> PermissionState { match tinyfiledialogs::message_box_yes_no(DIALOG_TITLE, - &format!("{} {:?} ?", QUERY_DIALOG_MESSAGE, permission_name), + message, MessageBoxIcon::Question, YesNo::No) { YesNo::Yes => PermissionState::Granted, @@ -258,7 +317,7 @@ fn prompt_user(permission_name: PermissionName) -> PermissionState { } #[cfg(not(target_os = "linux"))] -fn prompt_user(_permission_name: PermissionName) -> PermissionState { +fn prompt_user(_message: &str) -> PermissionState { // TODO popup only supported on linux PermissionState::Denied } diff --git a/components/script/dom/permissionstatus.rs b/components/script/dom/permissionstatus.rs index 11af67ecd13..0d060aa8e84 100644 --- a/components/script/dom/permissionstatus.rs +++ b/components/script/dom/permissionstatus.rs @@ -4,12 +4,14 @@ use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull; use dom::bindings::codegen::Bindings::PermissionStatusBinding::{self, PermissionDescriptor, PermissionName}; -use dom::bindings::codegen::Bindings::PermissionStatusBinding::{PermissionState, PermissionStatusMethods}; +use dom::bindings::codegen::Bindings::PermissionStatusBinding::{PermissionNameValues, PermissionState}; +use dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionStatusMethods; use dom::bindings::js::Root; use dom::bindings::reflector::reflect_dom_object; use dom::eventtarget::EventTarget; use dom::globalscope::GlobalScope; use std::cell::Cell; +use std::fmt::{self, Display, Formatter}; // https://w3c.github.io/permissions/#permissionstatus #[dom_struct] @@ -52,3 +54,9 @@ impl PermissionStatusMethods for PermissionStatus { // https://w3c.github.io/permissions/#dom-permissionstatus-onchange event_handler!(onchange, GetOnchange, SetOnchange); } + +impl Display for PermissionName { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "{}", PermissionNameValues::strings[*self as usize].to_string()) + } +} diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 18cd5a86246..b68bd492fd0 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -13,6 +13,7 @@ use dom::bindings::codegen::Bindings::EventHandlerBinding::OnBeforeUnloadEventHa use dom::bindings::codegen::Bindings::EventHandlerBinding::OnErrorEventHandlerNonNull; use dom::bindings::codegen::Bindings::FunctionBinding::Function; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; +use dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionState; use dom::bindings::codegen::Bindings::RequestBinding::RequestInit; use dom::bindings::codegen::Bindings::WindowBinding::{self, FrameRequestCallback, WindowMethods}; use dom::bindings::codegen::Bindings::WindowBinding::{ScrollBehavior, ScrollToOptions}; @@ -249,7 +250,10 @@ pub struct Window { /// A handle for communicating messages to the webvr thread, if available. #[ignore_heap_size_of = "channels are hard"] - webvr_thread: Option> + webvr_thread: Option>, + + /// A map for storing the previous permission state read results. + permission_state_invocation_results: DOMRefCell> } impl Window { @@ -338,6 +342,10 @@ impl Window { pub fn webvr_thread(&self) -> Option> { self.webvr_thread.clone() } + + pub fn permission_state_invocation_results(&self) -> &DOMRefCell> { + &self.permission_state_invocation_results + } } #[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] @@ -1704,7 +1712,8 @@ impl Window { scroll_offsets: DOMRefCell::new(HashMap::new()), media_query_lists: WeakMediaQueryListVec::new(), test_runner: Default::default(), - webvr_thread: webvr_thread + webvr_thread: webvr_thread, + permission_state_invocation_results: DOMRefCell::new(HashMap::new()), }; unsafe {