Add site permission settings

This commit is contained in:
2026-05-08 01:24:10 -04:00
parent b91f2c0ca1
commit 84149ea4df
16 changed files with 1064 additions and 3 deletions
+2 -1
View File
@@ -1,4 +1,4 @@
use ely_domain::{BrowserTab, DomainError, PluginId, UrlText};
use ely_domain::{BrowserTab, DomainError, PluginId, SiteOrigin, UrlText};
use url::Url;
use crate::CoreError;
@@ -24,6 +24,7 @@ fn internal_page_title(url: &str) -> Option<&'static str> {
"ely://task-manager" => Some("Task Manager"),
"ely://plugins" => Some("Plugin Marketplace"),
url if plugin_detail_route_id(url).is_some() => Some("Plugin Details"),
url if SiteOrigin::from_site_route(url).ok().flatten().is_some() => Some("Site Settings"),
"ely://about" => Some("About ELY Browser"),
"ely://settings" => Some("Settings"),
"ely://settings/plugins" => Some("Plugin Settings"),
+11 -2
View File
@@ -2,8 +2,8 @@ use std::collections::BTreeMap;
use ely_domain::{
ArchivedTab, BookmarkEntry, BrowserTab, DomainError, DownloadEntry, DownloadPolicy,
HistoryEntry, Profile, ProfileId, ProfileKind, ReadingListEntry, Space, SpaceId, SyncStatus,
TabId, UrlText,
HistoryEntry, Profile, ProfileId, ProfileKind, ReadingListEntry, SitePermissionAuditEvent,
SitePermissionEntry, Space, SpaceId, SyncStatus, TabId, UrlText,
};
use crate::CoreError;
@@ -15,6 +15,7 @@ mod history;
mod plugins;
mod profiles;
mod reading_list;
mod site_permissions;
mod sync;
mod tabs;
@@ -47,6 +48,8 @@ pub struct BrowserSnapshot {
pub archived_tabs: Vec<ArchivedTab>,
pub bookmarks: Vec<BookmarkEntry>,
pub reading_list: Vec<ReadingListEntry>,
pub site_permissions: Vec<SitePermissionEntry>,
pub site_permission_audit_events: Vec<SitePermissionAuditEvent>,
pub download_entries: Vec<DownloadEntry>,
pub history_entries: Vec<HistoryEntry>,
pub installed_plugins: Vec<InstalledPlugin>,
@@ -71,6 +74,8 @@ pub struct BrowserCore {
archived_tabs: Vec<ArchivedTab>,
bookmarks: Vec<BookmarkEntry>,
reading_list: Vec<ReadingListEntry>,
site_permissions: Vec<SitePermissionEntry>,
site_permission_audit_events: Vec<SitePermissionAuditEvent>,
download_entries: Vec<DownloadEntry>,
history_entries: Vec<HistoryEntry>,
installed_plugins: Vec<InstalledPlugin>,
@@ -117,6 +122,8 @@ impl BrowserCore {
archived_tabs: Vec::new(),
bookmarks: Vec::new(),
reading_list: Vec::new(),
site_permissions: Vec::new(),
site_permission_audit_events: Vec::new(),
download_entries: Vec::new(),
history_entries: Vec::new(),
installed_plugins: Vec::new(),
@@ -200,6 +207,8 @@ impl BrowserCore {
archived_tabs: self.archived_tabs.clone(),
bookmarks: self.visible_bookmarks(),
reading_list: self.visible_reading_list(),
site_permissions: self.visible_site_permissions(),
site_permission_audit_events: self.visible_site_permission_audit_events(),
download_entries: self.visible_downloads(),
history_entries: self.visible_history(),
installed_plugins: self.installed_plugins.clone(),
@@ -146,6 +146,13 @@ impl BrowserCore {
self.open_tab(plugins_url()?);
Ok(true)
}
"site-settings" | "open-site-settings" | "open site settings" => {
let Some(url) = self.active_tab_site_settings_url()? else {
return Ok(false);
};
self.open_tab(url);
Ok(true)
}
"about" | "open-about" | "open about" => {
self.open_tab(about_url()?);
Ok(true)
@@ -0,0 +1,158 @@
use std::time::SystemTime;
use ely_domain::{
ProfileId, SiteOrigin, SitePermissionAuditAction, SitePermissionAuditEvent,
SitePermissionDecision, SitePermissionEntry, SitePermissionFeature, UrlText,
};
use crate::CoreError;
use super::BrowserCore;
impl BrowserCore {
pub fn set_site_permission(
&mut self,
origin: SiteOrigin,
feature: SitePermissionFeature,
decision: SitePermissionDecision,
) -> Result<(), CoreError> {
let profile_id = self.active_profile_id.clone();
self.set_site_permission_for_profile(&profile_id, origin, feature, decision)
}
pub fn revoke_site_permission(
&mut self,
origin: &SiteOrigin,
feature: SitePermissionFeature,
) -> Result<(), CoreError> {
let profile_id = self.active_profile_id.clone();
self.revoke_site_permission_for_profile(&profile_id, origin, feature)
}
pub fn active_tab_site_settings_url(&self) -> Result<Option<UrlText>, CoreError> {
let active_tab = self.active_tab()?;
let Some(origin) = SiteOrigin::from_url(active_tab.url())? else {
return Ok(None);
};
origin.site_settings_url().map(Some).map_err(CoreError::from)
}
pub(super) fn visible_site_permissions(&self) -> Vec<SitePermissionEntry> {
self.site_permissions
.iter()
.filter(|entry| entry.profile_id() == &self.active_profile_id)
.cloned()
.collect()
}
pub(super) fn visible_site_permission_audit_events(&self) -> Vec<SitePermissionAuditEvent> {
self.site_permission_audit_events
.iter()
.filter(|event| event.profile_id() == &self.active_profile_id)
.cloned()
.collect()
}
fn set_site_permission_for_profile(
&mut self,
profile_id: &ProfileId,
origin: SiteOrigin,
feature: SitePermissionFeature,
decision: SitePermissionDecision,
) -> Result<(), CoreError> {
self.require_profile(profile_id)?;
if let Some(entry) = self.site_permission_entry_mut(profile_id, &origin, feature) {
if entry.decision() == decision {
return Ok(());
}
entry.set_decision(decision);
} else {
self.site_permissions.push(SitePermissionEntry::new(
profile_id.clone(),
origin.clone(),
feature,
decision,
));
}
self.record_site_permission_audit_event(
profile_id.clone(),
origin,
feature,
SitePermissionAuditAction::Set(decision),
);
Ok(())
}
fn revoke_site_permission_for_profile(
&mut self,
profile_id: &ProfileId,
origin: &SiteOrigin,
feature: SitePermissionFeature,
) -> Result<(), CoreError> {
self.require_profile(profile_id)?;
let Some(index) = self.site_permission_entry_index(profile_id, origin, feature) else {
return Ok(());
};
let entry = self.site_permissions.remove(index);
self.record_site_permission_audit_event(
profile_id.clone(),
entry.origin().clone(),
feature,
SitePermissionAuditAction::Revoked,
);
Ok(())
}
fn require_profile(&self, profile_id: &ProfileId) -> Result<(), CoreError> {
if self.profiles.iter().any(|profile| profile.id() == profile_id) {
return Ok(());
}
Err(CoreError::ProfileNotFound { id: profile_id.clone() })
}
fn site_permission_entry_mut(
&mut self,
profile_id: &ProfileId,
origin: &SiteOrigin,
feature: SitePermissionFeature,
) -> Option<&mut SitePermissionEntry> {
self.site_permissions.iter_mut().find(|entry| {
entry.profile_id() == profile_id
&& entry.origin() == origin
&& entry.feature() == feature
})
}
fn site_permission_entry_index(
&self,
profile_id: &ProfileId,
origin: &SiteOrigin,
feature: SitePermissionFeature,
) -> Option<usize> {
self.site_permissions.iter().position(|entry| {
entry.profile_id() == profile_id
&& entry.origin() == origin
&& entry.feature() == feature
})
}
fn record_site_permission_audit_event(
&mut self,
profile_id: ProfileId,
origin: SiteOrigin,
feature: SitePermissionFeature,
action: SitePermissionAuditAction,
) {
self.site_permission_audit_events.push(SitePermissionAuditEvent::new(
profile_id,
origin,
feature,
action,
SystemTime::now(),
));
}
}
@@ -30,6 +30,11 @@ impl BrowserCore {
self.profiles.len(),
SyncObjectState::LocalOnly,
),
SyncObjectStatus::new(
SyncObjectKind::SitePermissions,
self.site_permissions.len(),
SyncObjectState::LocalOnly,
),
SyncObjectStatus::new(
SyncObjectKind::History,
self.history_entries.len(),