mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Allow embedder to bypass devtools prompt
This commit is contained in:
parent
3f999ce785
commit
8cf2f14baa
16 changed files with 83 additions and 35 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1208,6 +1208,7 @@ dependencies = [
|
|||
"msg",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"servo_rand",
|
||||
"servo_url",
|
||||
"time",
|
||||
"uuid",
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
@ -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(..) |
|
||||
|
|
|
@ -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),
|
||||
|
@ -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());
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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) {
|
||||
|
@ -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 =
|
||||
|
|
|
@ -57,6 +57,7 @@ private:
|
|||
void BuildPrefList();
|
||||
DevtoolsStatus mDevtoolsStatus = DevtoolsStatus::Stopped;
|
||||
unsigned int mDevtoolsPort = 0;
|
||||
hstring mDevtoolsToken;
|
||||
std::unique_ptr<servo::DevtoolsClient> mDevtoolsClient;
|
||||
Collections::IObservableVector<IInspectable> mLogs;
|
||||
};
|
||||
|
|
|
@ -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 = {};
|
||||
|
|
|
@ -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();
|
||||
|
@ -30,6 +31,7 @@ public:
|
|||
|
||||
private:
|
||||
hstring mPort;
|
||||
hstring mToken;
|
||||
hstring mHostname;
|
||||
DevtoolsDelegate &mDelegate;
|
||||
std::optional<DataReader> mDataReader;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -108,7 +108,7 @@ public:
|
|||
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;
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue