Pass site permission grants to sidecar snapshots

This commit is contained in:
2026-05-09 00:01:14 -04:00
parent 4ed1666ece
commit 79d9646ab8
10 changed files with 303 additions and 12 deletions
+1
View File
@@ -23,6 +23,7 @@ mod web_surface_frame;
mod web_surface_geometry;
mod web_surface_image;
mod web_surface_keyboard;
mod web_surface_permissions;
mod web_surface_state;
mod web_surface_view;
@@ -4,13 +4,14 @@ use gpui::{AnyElement, Bounds, Context, Pixels, Point};
use crate::services::{
ProfileDataMode,
servo_sidecar::{ServoSidecarError, SidecarSnapshot},
servo_sidecar::{ServoSidecarError, SidecarSitePermission, SidecarSnapshot},
};
use super::{
ElyShell,
web_surface_frame::WebSurfaceFrame,
web_surface_geometry::{WebSurfaceClickPoint, WebSurfaceScrollOffset, WebSurfaceSize},
web_surface_permissions::sidecar_site_permissions_for_tab,
web_surface_state::{WebSurfaceRequest, WebSurfaceState},
web_surface_view::{
render_failed_web_surface, render_loading_web_surface, render_ready_web_surface,
@@ -37,8 +38,9 @@ impl ElyShell {
let Some(profile_data_mode) = profile_data_mode_for(tab, snapshot) else {
return render_failed_web_surface(tab, "Profile context is unavailable.", state_entity);
};
let site_permissions = sidecar_site_permissions_for_tab(tab, snapshot);
self.ensure_external_web_frame(tab, profile_data_mode, cx);
self.ensure_external_web_frame(tab, profile_data_mode, site_permissions, cx);
match self.web_surfaces.state(tab.id()) {
Some(WebSurfaceState::Ready(frame)) => {
@@ -60,6 +62,7 @@ impl ElyShell {
&mut self,
tab: &BrowserTab,
profile_data_mode: ProfileDataMode,
site_permissions: Vec<SidecarSitePermission>,
cx: &mut Context<Self>,
) {
let Some(request) = self.web_surfaces.prepare_request(tab, profile_data_mode) else {
@@ -74,8 +77,9 @@ impl ElyShell {
click_point,
typed_text,
client,
snapshot_request,
mut snapshot_request,
} = request;
snapshot_request = snapshot_request.with_site_permissions(site_permissions);
let pending_frame = PendingWebSurfaceFrame {
tab_id,
requested_url,
@@ -0,0 +1,91 @@
use ely_browser_core::BrowserSnapshot;
use ely_domain::{BrowserTab, SiteOrigin};
use crate::services::servo_sidecar::SidecarSitePermission;
pub(super) fn sidecar_site_permissions_for_tab(
tab: &BrowserTab,
snapshot: &BrowserSnapshot,
) -> Vec<SidecarSitePermission> {
let Ok(Some(origin)) = SiteOrigin::from_url(tab.url()) else {
return Vec::new();
};
snapshot
.site_permissions
.iter()
.filter(|entry| entry.profile_id() == tab.profile_id())
.filter(|entry| entry.origin() == &origin)
.map(|entry| {
SidecarSitePermission::new(entry.origin().clone(), entry.feature(), entry.decision())
})
.collect()
}
#[cfg(test)]
mod tests {
use std::error::Error;
use ely_browser_core::{BrowserCore, BrowserSnapshot, InitialBrowserConfig};
use ely_domain::{
BrowserTab, SiteOrigin, SitePermissionDecision, SitePermissionFeature, UrlText,
};
use super::sidecar_site_permissions_for_tab;
#[test]
fn includes_matching_profile_and_origin_permissions() -> Result<(), Box<dyn Error>> {
let mut core = browser_core_for("https://example.com/page")?;
let origin = SiteOrigin::parse("https://example.com")?;
core.set_site_permission(
origin,
SitePermissionFeature::Camera,
SitePermissionDecision::AllowAlways,
)?;
let snapshot = core.snapshot()?;
let tab = active_tab(&snapshot)?;
let permissions = sidecar_site_permissions_for_tab(tab, &snapshot);
assert_eq!(permissions.len(), 1);
assert_eq!(permissions[0].origin().as_str(), "https://example.com");
assert_eq!(permissions[0].feature(), SitePermissionFeature::Camera);
assert_eq!(permissions[0].decision(), SitePermissionDecision::AllowAlways);
Ok(())
}
#[test]
fn filters_other_origins() -> Result<(), Box<dyn Error>> {
let mut core = browser_core_for("https://example.com/page")?;
core.set_site_permission(
SiteOrigin::parse("https://other.test")?,
SitePermissionFeature::Location,
SitePermissionDecision::AllowOnce,
)?;
let snapshot = core.snapshot()?;
let tab = active_tab(&snapshot)?;
assert!(sidecar_site_permissions_for_tab(tab, &snapshot).is_empty());
Ok(())
}
fn browser_core_for(url: &str) -> Result<BrowserCore, Box<dyn Error>> {
let mut core = BrowserCore::new(InitialBrowserConfig {
space_name: "Work".to_string(),
space_icon: "W".to_string(),
profile_name: "Default".to_string(),
new_tab_destination: Default::default(),
})?;
core.open_tab(UrlText::parse(url)?);
Ok(core)
}
fn active_tab(snapshot: &BrowserSnapshot) -> Result<&BrowserTab, Box<dyn Error>> {
snapshot
.tabs
.iter()
.find(|tab| tab.id() == &snapshot.active_tab_id)
.ok_or_else(|| std::io::Error::other("active tab missing").into())
}
}