Skip to content

Commit

Permalink
Allow embedder to bypass devtools prompt
Browse files Browse the repository at this point in the history
  • Loading branch information
paulrouget committed Jun 22, 2020
1 parent 3f999ce commit 8cf2f14
Show file tree
Hide file tree
Showing 16 changed files with 83 additions and 35 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions components/devtools/Cargo.toml
Expand Up @@ -22,6 +22,7 @@ log = "0.4"
msg = { path = "../msg" }
serde = "1.0"
serde_json = "1.0"
servo_rand = { path = "../rand" }
servo_url = { path = "../url" }
time = "0.1"
uuid = { version = "0.8", features = ["v4"] }
51 changes: 40 additions & 11 deletions components/devtools/lib.rs
Expand Up @@ -39,9 +39,11 @@ use devtools_traits::{PageError, ScriptToDevtoolsControlMsg, WorkerId};
use embedder_traits::{EmbedderMsg, EmbedderProxy, PromptDefinition, PromptOrigin, PromptResult};
use ipc_channel::ipc::{self, IpcSender};
use msg::constellation_msg::{BrowsingContextId, PipelineId};
use servo_rand::RngCore;
use std::borrow::ToOwned;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::HashMap;
use std::io::Read;
use std::net::{Shutdown, TcpListener, TcpStream};
use std::sync::{Arc, Mutex};
use std::thread;
Expand Down Expand Up @@ -137,8 +139,11 @@ fn run_server(
.map(|port| (l, port))
});

// A token shared with the embedder to bypass permission prompt.
let token = format!("{:X}", servo_rand::ServoRng::new().next_u32());

let port = bound.as_ref().map(|(_, port)| *port).ok_or(());
embedder.send((None, EmbedderMsg::OnDevtoolsStarted(port)));
embedder.send((None, EmbedderMsg::OnDevtoolsStarted(port, token.clone())));

let listener = match bound {
Some((l, _)) => l,
Expand Down Expand Up @@ -563,20 +568,14 @@ fn run_server(
.spawn(move || {
// accept connections and process them, spawning a new thread for each one
for stream in listener.incoming() {
// Prompt user for permission
let (embedder_sender, receiver) =
ipc::channel().expect("Failed to create IPC channel!");
let message = "Accept incoming devtools connection?".to_owned();
let prompt = PromptDefinition::YesNo(message, embedder_sender);
let msg = EmbedderMsg::Prompt(prompt, PromptOrigin::Trusted);
embedder.send((None, msg));
if receiver.recv().unwrap() != PromptResult::Primary {
let mut stream = stream.expect("Can't retrieve stream");
if !allow_devtools_client(&mut stream, &embedder, &token) {
continue;
}
};
// connection succeeded and accepted
sender
.send(DevtoolsControlMsg::FromChrome(
ChromeToDevtoolsControlMsg::AddClient(stream.unwrap()),
ChromeToDevtoolsControlMsg::AddClient(stream),
))
.unwrap();
}
Expand Down Expand Up @@ -704,3 +703,33 @@ fn run_server(
let _ = connection.shutdown(Shutdown::Both);
}
}

fn allow_devtools_client(stream: &mut TcpStream, embedder: &EmbedderProxy, token: &str) -> bool {
// By-pass prompt if we receive a valid token.
let token = format!("25:{{\"auth_token\":\"{}\"}}", token);
let mut buf = [0; 28];
let timeout = std::time::Duration::from_millis(500);
// This will read but not consume the bytes from the stream.
stream.set_read_timeout(Some(timeout)).unwrap();
let peek = stream.peek(&mut buf);
stream.set_read_timeout(None).unwrap();
if let Ok(len) = peek {
if len == buf.len() {
if let Ok(s) = std::str::from_utf8(&buf) {
if s == token {
// Consume the message as it was relevant to us.
let _ = stream.read_exact(&mut buf);
return true;
}
}
}
};

// No token found. Prompt user
let (embedder_sender, receiver) = ipc::channel().expect("Failed to create IPC channel!");
let message = "Accept incoming devtools connection?".to_owned();
let prompt = PromptDefinition::YesNo(message, embedder_sender);
let msg = EmbedderMsg::Prompt(prompt, PromptOrigin::Trusted);
embedder.send((None, msg));
receiver.recv().unwrap() == PromptResult::Primary
}
4 changes: 2 additions & 2 deletions components/embedder_traits/lib.rs
Expand Up @@ -207,8 +207,8 @@ pub enum EmbedderMsg {
/// Notifies the embedder about media session events
/// (i.e. when there is metadata for the active media session, playback state changes...).
MediaSessionEvent(MediaSessionEvent),
/// Report the status of Devtools Server
OnDevtoolsStarted(Result<u16, ()>),
/// Report the status of Devtools Server with a token that can be used to bypass the permission prompt.
OnDevtoolsStarted(Result<u16, ()>, String),
}

impl Debug for EmbedderMsg {
Expand Down
8 changes: 5 additions & 3 deletions ports/libsimpleservo/api/src/lib.rs
Expand Up @@ -146,7 +146,7 @@ pub trait HostTrait {
/// Called when the media session position state is set.
fn on_media_session_set_position_state(&self, duration: f64, position: f64, playback_rate: f64);
/// Called when devtools server is started
fn on_devtools_started(&self, port: Result<u16, ()>);
fn on_devtools_started(&self, port: Result<u16, ()>, token: String);
}

pub struct ServoGlue {
Expand Down Expand Up @@ -751,8 +751,10 @@ impl ServoGlue {
),
};
},
EmbedderMsg::OnDevtoolsStarted(port) => {
self.callbacks.host_callbacks.on_devtools_started(port);
EmbedderMsg::OnDevtoolsStarted(port, token) => {
self.callbacks
.host_callbacks
.on_devtools_started(port, token);
},
EmbedderMsg::Status(..) |
EmbedderMsg::SelectFiles(..) |
Expand Down
14 changes: 10 additions & 4 deletions ports/libsimpleservo/capi/src/lib.rs
Expand Up @@ -227,7 +227,8 @@ pub struct CHostCallbacks {
default: *const c_char,
trusted: bool,
) -> *const c_char,
pub on_devtools_started: extern "C" fn(result: CDevtoolsServerState, port: c_uint),
pub on_devtools_started:
extern "C" fn(result: CDevtoolsServerState, port: c_uint, token: *const c_char),
pub show_context_menu:
extern "C" fn(title: *const c_char, items_list: *const *const c_char, items_size: u32),
pub on_log_output: extern "C" fn(buffer: *const c_char, buffer_length: u32),
Expand Down Expand Up @@ -883,15 +884,20 @@ impl HostTrait for HostCallbacks {
Some(contents_str.to_owned())
}

fn on_devtools_started(&self, port: Result<u16, ()>) {
fn on_devtools_started(&self, port: Result<u16, ()>, token: String) {
let token = CString::new(token).expect("Can't create string");
match port {
Ok(p) => {
info!("Devtools Server running on port {}", p);
(self.0.on_devtools_started)(CDevtoolsServerState::Started, p.into());
(self.0.on_devtools_started)(
CDevtoolsServerState::Started,
p.into(),
token.as_ptr(),
);
},
Err(()) => {
error!("Error running devtools server");
(self.0.on_devtools_started)(CDevtoolsServerState::Error, 0);
(self.0.on_devtools_started)(CDevtoolsServerState::Error, 0, token.as_ptr());
},
}
}
Expand Down
2 changes: 1 addition & 1 deletion ports/winit/browser.rs
Expand Up @@ -515,7 +515,7 @@ where
debug!("MediaSessionEvent received");
// TODO(ferjm): MediaSession support for winit based browsers.
},
EmbedderMsg::OnDevtoolsStarted(port) => {
EmbedderMsg::OnDevtoolsStarted(port, _token) => {
match port {
Ok(p) => info!("Devtools Server running on port {}", p),
Err(()) => error!("Error running devtools server"),
Expand Down
7 changes: 4 additions & 3 deletions support/hololens/ServoApp/BrowserPage.cpp
Expand Up @@ -80,9 +80,10 @@ void BrowserPage::BindServoEvents() {
: Visibility::Visible);
});
servoControl().OnDevtoolsStatusChanged(
[=](DevtoolsStatus status, unsigned int port) {
[=](DevtoolsStatus status, unsigned int port, hstring token) {
mDevtoolsStatus = status;
mDevtoolsPort = port;
mDevtoolsToken = token;
});
Window::Current().VisibilityChanged(
[=](const auto &, const VisibilityChangedEventArgs &args) {
Expand Down Expand Up @@ -318,8 +319,8 @@ void BrowserPage::OnDevtoolsButtonClicked(IInspectable const &,
hstring port = to_hstring(mDevtoolsPort);
if (mDevtoolsClient == nullptr) {
DevtoolsDelegate *dd = static_cast<DevtoolsDelegate *>(this);
mDevtoolsClient =
std::make_unique<DevtoolsClient>(L"localhost", port, *dd);
mDevtoolsClient = std::make_unique<DevtoolsClient>(L"localhost", port,
mDevtoolsToken, *dd);
}
mDevtoolsClient->Run();
std::wstring message =
Expand Down
1 change: 1 addition & 0 deletions support/hololens/ServoApp/BrowserPage.h
Expand Up @@ -57,6 +57,7 @@ struct BrowserPage : BrowserPageT<BrowserPage>, public servo::DevtoolsDelegate {
void BuildPrefList();
DevtoolsStatus mDevtoolsStatus = DevtoolsStatus::Stopped;
unsigned int mDevtoolsPort = 0;
hstring mDevtoolsToken;
std::unique_ptr<servo::DevtoolsClient> mDevtoolsClient;
Collections::IObservableVector<IInspectable> mLogs;
};
Expand Down
5 changes: 5 additions & 0 deletions support/hololens/ServoApp/Devtools/Client.cpp
Expand Up @@ -31,6 +31,11 @@ void DevtoolsClient::Run() {
connecting.Completed([=](const auto &, const auto &) {
mDataReader = DataReader(socket.InputStream());
mDataWriter = DataWriter(socket.OutputStream());

JsonObject out;
out.Insert(L"auth_token", JsonValue::CreateStringValue(mToken));
Send(out);

mReceiveOp = {Loop()};
mReceiveOp->Completed([=](const auto &, const auto &) {
mReceiveOp = {};
Expand Down
6 changes: 4 additions & 2 deletions support/hololens/ServoApp/Devtools/Client.h
Expand Up @@ -19,8 +19,9 @@ enum DevtoolsMessageLevel { Error, Warn, None };
class DevtoolsClient {

public:
DevtoolsClient(hstring hostname, hstring port, DevtoolsDelegate &d)
: mDelegate(d), mHostname(hostname), mPort(port){};
DevtoolsClient(hstring hostname, hstring port, hstring token,
DevtoolsDelegate &d)
: mDelegate(d), mHostname(hostname), mToken(token), mPort(port){};

~DevtoolsClient() { Stop(); }
void Run();
Expand All @@ -30,6 +31,7 @@ class DevtoolsClient {

private:
hstring mPort;
hstring mToken;
hstring mHostname;
DevtoolsDelegate &mDelegate;
std::optional<DataReader> mDataReader;
Expand Down
6 changes: 3 additions & 3 deletions support/hololens/ServoApp/ServoControl/Servo.cpp
Expand Up @@ -83,9 +83,9 @@ void show_context_menu(const char *title, const char *const *items_list,
}

void on_devtools_started(Servo::DevtoolsServerState result,
const unsigned int port) {
sServo->Delegate().OnServoDevtoolsStarted(
result == Servo::DevtoolsServerState::Started, port);
const unsigned int port, const char *token) {
auto state = result == Servo::DevtoolsServerState::Started;
sServo->Delegate().OnServoDevtoolsStarted(state, port, char2hstring(token));
}

void on_log_output(const char *buffer, uint32_t buffer_length) {
Expand Down
2 changes: 1 addition & 1 deletion support/hololens/ServoApp/ServoControl/Servo.h
Expand Up @@ -108,7 +108,7 @@ class ServoDelegate {
virtual bool OnServoAllowNavigation(hstring) = 0;
virtual void OnServoAnimatingChanged(bool) = 0;
virtual void OnServoIMEStateChanged(bool) = 0;
virtual void OnServoDevtoolsStarted(bool, const unsigned int) = 0;
virtual void OnServoDevtoolsStarted(bool, const unsigned int, hstring) = 0;
virtual void OnServoMediaSessionMetadata(hstring, hstring, hstring) = 0;
virtual void OnServoMediaSessionPlaybackStateChange(int) = 0;
virtual void OnServoPromptAlert(hstring, bool) = 0;
Expand Down
6 changes: 3 additions & 3 deletions support/hololens/ServoApp/ServoControl/ServoControl.cpp
Expand Up @@ -571,11 +571,11 @@ std::optional<hstring> ServoControl::OnServoPromptInput(winrt::hstring message,
return string;
}

void ServoControl::OnServoDevtoolsStarted(bool success,
const unsigned int port) {
void ServoControl::OnServoDevtoolsStarted(bool success, const unsigned int port,
hstring token) {
RunOnUIThread([=] {
auto status = success ? DevtoolsStatus::Running : DevtoolsStatus::Failed;
mOnDevtoolsStatusChangedEvent(status, port);
mOnDevtoolsStatusChangedEvent(status, port, token);
});
}

Expand Down
2 changes: 1 addition & 1 deletion support/hololens/ServoApp/ServoControl/ServoControl.h
Expand Up @@ -185,7 +185,7 @@ struct ServoControl : ServoControlT<ServoControl>, public servo::ServoDelegate {
virtual servo::Servo::PromptResult OnServoPromptYesNo(winrt::hstring, bool);
virtual std::optional<hstring> OnServoPromptInput(winrt::hstring,
winrt::hstring, bool);
virtual void OnServoDevtoolsStarted(bool, const unsigned int);
virtual void OnServoDevtoolsStarted(bool, const unsigned int, winrt::hstring);

DevtoolsStatus GetDevtoolsStatus();

Expand Down
2 changes: 1 addition & 1 deletion support/hololens/ServoApp/ServoControl/ServoControl.idl
Expand Up @@ -3,7 +3,7 @@ namespace ServoApp {
delegate void EventDelegate();
delegate void HistoryChangedDelegate(Boolean back, Boolean forward);
delegate void MediaSessionMetadataDelegate(String title, String artist, String album);
delegate void DevtoolsStatusChangedDelegate(DevtoolsStatus status, UInt32 port);
delegate void DevtoolsStatusChangedDelegate(DevtoolsStatus status, UInt32 port, String token);

enum DevtoolsStatus {
Running = 0,
Expand Down

0 comments on commit 8cf2f14

Please sign in to comment.