Desktop: Block network requests in CEF that are not explicitly allowlisted (#4225)

This commit is contained in:
Timon
2026-06-11 15:32:53 +00:00
committed by GitHub
parent 26a0b901d4
commit 05d3d66587
4 changed files with 155 additions and 1 deletions

View File

@@ -10,7 +10,9 @@ mod context_menu_handler;
mod display_handler;
mod life_span_handler;
mod load_handler;
mod request_handler;
mod resource_handler;
mod resource_request_handler;
mod scheme_handler_factory;
pub(super) mod render_handler;

View File

@@ -1,6 +1,6 @@
use cef::rc::{Rc, RcImpl};
use cef::sys::{_cef_client_t, cef_base_ref_counted_t};
use cef::{ContextMenuHandler, DisplayHandler, ImplClient, LifeSpanHandler, LoadHandler, RenderHandler, WrapClient};
use cef::{ContextMenuHandler, DisplayHandler, ImplClient, LifeSpanHandler, LoadHandler, RenderHandler, RequestHandler, WrapClient};
use crate::cef::CefEventHandler;
use crate::cef::ipc::{MessageType, UnpackMessage, UnpackedMessage};
@@ -10,6 +10,7 @@ use super::display_handler::DisplayHandlerImpl;
use super::life_span_handler::LifeSpanHandlerImpl;
use super::load_handler::LoadHandlerImpl;
use super::render_handler::RenderHandlerImpl;
use super::request_handler::RequestHandlerImpl;
pub(crate) struct BrowserProcessClientImpl<H: CefEventHandler> {
object: *mut RcImpl<_cef_client_t, Self>,
@@ -17,6 +18,7 @@ pub(crate) struct BrowserProcessClientImpl<H: CefEventHandler> {
load_handler: LoadHandler,
render_handler: RenderHandler,
display_handler: DisplayHandler,
request_handler: RequestHandler,
}
impl<H: CefEventHandler> BrowserProcessClientImpl<H> {
pub(crate) fn new(event_handler: &H) -> Self {
@@ -26,6 +28,7 @@ impl<H: CefEventHandler> BrowserProcessClientImpl<H> {
load_handler: LoadHandler::new(LoadHandlerImpl::new(event_handler.duplicate())),
render_handler: RenderHandler::new(RenderHandlerImpl::new(event_handler.duplicate())),
display_handler: DisplayHandler::new(DisplayHandlerImpl::new(event_handler.duplicate())),
request_handler: RequestHandler::new(RequestHandlerImpl::new()),
}
}
}
@@ -73,6 +76,10 @@ impl<H: CefEventHandler> ImplClient for BrowserProcessClientImpl<H> {
Some(self.display_handler.clone())
}
fn request_handler(&self) -> Option<cef::RequestHandler> {
Some(self.request_handler.clone())
}
fn context_menu_handler(&self) -> Option<cef::ContextMenuHandler> {
Some(ContextMenuHandler::new(ContextMenuHandlerImpl::new()))
}
@@ -94,6 +101,7 @@ impl<H: CefEventHandler> Clone for BrowserProcessClientImpl<H> {
load_handler: self.load_handler.clone(),
render_handler: self.render_handler.clone(),
display_handler: self.display_handler.clone(),
request_handler: self.request_handler.clone(),
}
}
}

View File

@@ -0,0 +1,84 @@
use cef::rc::{Rc, RcImpl};
use cef::sys::{_cef_request_handler_t, cef_base_ref_counted_t};
use cef::{AuthCallback, Browser, CefString, Frame, ImplRequest, ImplRequestHandler, Request, ResourceRequestHandler, WrapRequestHandler};
use std::ffi::c_int;
use super::resource_request_handler::ResourceRequestHandlerImpl;
use crate::cef::consts::{RESOURCE_DOMAIN, RESOURCE_SCHEME};
pub(crate) struct RequestHandlerImpl {
object: *mut RcImpl<_cef_request_handler_t, Self>,
}
impl RequestHandlerImpl {
pub(crate) fn new() -> Self {
Self { object: std::ptr::null_mut() }
}
}
impl ImplRequestHandler for RequestHandlerImpl {
fn on_before_browse(&self, _browser: Option<&mut Browser>, _frame: Option<&mut Frame>, request: Option<&mut Request>, _user_gesture: c_int, _is_redirect: c_int) -> c_int {
let Some(request) = request else { return 1 };
let url = CefString::from(&request.url()).to_string();
if url.starts_with(&format!("{RESOURCE_SCHEME}://{RESOURCE_DOMAIN}/")) {
0
} else {
tracing::warn!("Blocked navigation to: {}", url);
1
}
}
fn resource_request_handler(
&self,
_browser: Option<&mut Browser>,
_frame: Option<&mut Frame>,
_request: Option<&mut Request>,
_is_navigation: c_int,
_is_download: c_int,
_request_initiator: Option<&CefString>,
_disable_default_handling: Option<&mut c_int>,
) -> Option<ResourceRequestHandler> {
Some(ResourceRequestHandler::new(ResourceRequestHandlerImpl::new()))
}
fn auth_credentials(
&self,
_browser: Option<&mut Browser>,
_origin_url: Option<&CefString>,
_is_proxy: c_int,
_host: Option<&CefString>,
_port: c_int,
_realm: Option<&CefString>,
_scheme: Option<&CefString>,
_callback: Option<&mut AuthCallback>,
) -> c_int {
0
}
fn get_raw(&self) -> *mut _cef_request_handler_t {
self.object.cast()
}
}
impl Clone for RequestHandlerImpl {
fn clone(&self) -> Self {
unsafe {
let rc_impl = &mut *self.object;
rc_impl.interface.add_ref();
}
Self { object: self.object }
}
}
impl Rc for RequestHandlerImpl {
fn as_base(&self) -> &cef_base_ref_counted_t {
unsafe {
let base = &*self.object;
std::mem::transmute(&base.cef_object)
}
}
}
impl WrapRequestHandler for RequestHandlerImpl {
fn wrap_rc(&mut self, object: *mut RcImpl<_cef_request_handler_t, Self>) {
self.object = object;
}
}

View File

@@ -0,0 +1,60 @@
use cef::rc::{Rc, RcImpl};
use cef::sys::{_cef_resource_request_handler_t, cef_base_ref_counted_t};
use cef::{Browser, Callback, CefString, Frame, ImplRequest, ImplResourceRequestHandler, Request, ReturnValue, WrapResourceRequestHandler};
use crate::cef::consts::{RESOURCE_DOMAIN, RESOURCE_SCHEME};
// TODO: Deny all external requests once we stop relying on google fonts for font preview
fn is_allowed_url(url: &str) -> bool {
url.starts_with(&format!("{RESOURCE_SCHEME}://{RESOURCE_DOMAIN}/")) || url.starts_with("https://fonts.googleapis.com/css2") || url.starts_with("https://fonts.gstatic.com/")
}
pub(crate) struct ResourceRequestHandlerImpl {
object: *mut RcImpl<_cef_resource_request_handler_t, Self>,
}
impl ResourceRequestHandlerImpl {
pub(crate) fn new() -> Self {
Self { object: std::ptr::null_mut() }
}
}
impl ImplResourceRequestHandler for ResourceRequestHandlerImpl {
fn on_before_resource_load(&self, _browser: Option<&mut Browser>, _frame: Option<&mut Frame>, request: Option<&mut Request>, _callback: Option<&mut Callback>) -> ReturnValue {
let Some(request) = request else { return ReturnValue::CANCEL };
let url = CefString::from(&request.url()).to_string();
if is_allowed_url(&url) {
ReturnValue::CONTINUE
} else {
tracing::error!("Blocked resource load: {}", url);
ReturnValue::CANCEL
}
}
fn get_raw(&self) -> *mut _cef_resource_request_handler_t {
self.object.cast()
}
}
impl Clone for ResourceRequestHandlerImpl {
fn clone(&self) -> Self {
unsafe {
let rc_impl = &mut *self.object;
rc_impl.interface.add_ref();
}
Self { object: self.object }
}
}
impl Rc for ResourceRequestHandlerImpl {
fn as_base(&self) -> &cef_base_ref_counted_t {
unsafe {
let base = &*self.object;
std::mem::transmute(&base.cef_object)
}
}
}
impl WrapResourceRequestHandler for ResourceRequestHandlerImpl {
fn wrap_rc(&mut self, object: *mut RcImpl<_cef_resource_request_handler_t, Self>) {
self.object = object;
}
}