Skip to content

Commit

Permalink
Delegate permission prompt dialog formatting to embedders
Browse files Browse the repository at this point in the history
  • Loading branch information
iulianR committed Feb 28, 2020
1 parent 675b36d commit f75d547
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 25 deletions.
30 changes: 26 additions & 4 deletions components/embedder_traits/lib.rs
Expand Up @@ -185,9 +185,8 @@ pub enum EmbedderMsg {
GetSelectedBluetoothDevice(Vec<String>, IpcSender<Option<String>>),
/// Open file dialog to select files. Set boolean flag to true allows to select multiple files.
SelectFiles(Vec<FilterPattern>, bool, IpcSender<Option<Vec<String>>>),
/// Open yes/no message for user to allow permission specified by first String.
/// With dialog title specified by second String.
PromptPermission(String, String, IpcSender<PermissionRequest>),
/// Open interface to request permission specified by prompt.
PromptPermission(PermissionPrompt, IpcSender<PermissionRequest>),
/// 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.
Expand Down Expand Up @@ -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,
Expand Down
44 changes: 29 additions & 15 deletions components/script/dom/permissions.rs
Expand Up @@ -19,19 +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 embedder_traits::{self, EmbedderMsg, PermissionPrompt, 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;

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;
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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,
)
}
};

Expand Down Expand Up @@ -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,
Expand All @@ -377,3 +371,23 @@ fn prompt_user_from_embedder(prompt: String, gs: &GlobalScope) -> PermissionStat
},
}
}

impl From<PermissionName> 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
},
}
}
}
27 changes: 21 additions & 6 deletions ports/glutin/browser.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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) => {
Expand All @@ -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,
) {
Expand All @@ -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
}
Expand Down

0 comments on commit f75d547

Please sign in to comment.