Pass site permission grants to sidecar snapshots
This commit is contained in:
@@ -10,7 +10,7 @@ use ely_domain::ProfileId;
|
||||
use serde::Deserialize;
|
||||
use thiserror::Error;
|
||||
|
||||
pub use super::servo_sidecar_request::SidecarSnapshotRequest;
|
||||
pub use super::servo_sidecar_request::{SidecarSitePermission, SidecarSnapshotRequest};
|
||||
|
||||
use super::{
|
||||
servo_profile_data::{
|
||||
@@ -112,6 +112,9 @@ impl ServoSidecarClient {
|
||||
if let Some(typed_text) = request.typed_text.as_deref() {
|
||||
command.arg("--type-text").arg(typed_text);
|
||||
}
|
||||
for permission in &request.site_permissions {
|
||||
command.arg("--site-permission").arg(permission.to_arg());
|
||||
}
|
||||
|
||||
let mut child = command
|
||||
.stdout(Stdio::piped())
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use ely_domain::{ProfileId, UrlText};
|
||||
use ely_domain::{ProfileId, SiteOrigin, SitePermissionDecision, SitePermissionFeature, UrlText};
|
||||
|
||||
use super::ProfileDataMode;
|
||||
|
||||
@@ -13,6 +13,7 @@ pub struct SidecarSnapshotRequest {
|
||||
pub(in crate::services) scroll_y: i32,
|
||||
pub(in crate::services) click_point: Option<SidecarClickPoint>,
|
||||
pub(in crate::services) typed_text: Option<String>,
|
||||
pub(in crate::services) site_permissions: Vec<SidecarSitePermission>,
|
||||
}
|
||||
|
||||
impl SidecarSnapshotRequest {
|
||||
@@ -28,6 +29,7 @@ impl SidecarSnapshotRequest {
|
||||
scroll_y: 0,
|
||||
click_point: None,
|
||||
typed_text: None,
|
||||
site_permissions: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +58,12 @@ impl SidecarSnapshotRequest {
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_site_permissions(mut self, site_permissions: Vec<SidecarSitePermission>) -> Self {
|
||||
self.site_permissions = site_permissions;
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn typed_text_for_test(&self) -> Option<&str> {
|
||||
self.typed_text.as_deref()
|
||||
@@ -77,3 +85,45 @@ pub(in crate::services) struct SidecarClickPoint {
|
||||
pub(in crate::services) x: u32,
|
||||
pub(in crate::services) y: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct SidecarSitePermission {
|
||||
origin: SiteOrigin,
|
||||
feature: SitePermissionFeature,
|
||||
decision: SitePermissionDecision,
|
||||
}
|
||||
|
||||
impl SidecarSitePermission {
|
||||
#[must_use]
|
||||
pub fn new(
|
||||
origin: SiteOrigin,
|
||||
feature: SitePermissionFeature,
|
||||
decision: SitePermissionDecision,
|
||||
) -> Self {
|
||||
Self { origin, feature, decision }
|
||||
}
|
||||
|
||||
pub(in crate::services) fn to_arg(&self) -> String {
|
||||
serde_json::json!({
|
||||
"origin": self.origin.as_str(),
|
||||
"feature": self.feature.as_str(),
|
||||
"decision": self.decision.as_str(),
|
||||
})
|
||||
.to_string()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn origin(&self) -> &SiteOrigin {
|
||||
&self.origin
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn feature(&self) -> SitePermissionFeature {
|
||||
self.feature
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn decision(&self) -> SitePermissionDecision {
|
||||
self.decision
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user