Add site permission settings
This commit is contained in:
@@ -8,6 +8,9 @@ pub enum DomainError {
|
||||
#[error("invalid URL: {value}")]
|
||||
InvalidUrl { value: String },
|
||||
|
||||
#[error("invalid site origin: {value}")]
|
||||
InvalidSiteOrigin { value: String },
|
||||
|
||||
#[error("invalid file name: {value}")]
|
||||
InvalidFileName { value: String },
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ mod identifiers;
|
||||
mod plugin;
|
||||
mod profile;
|
||||
mod reading_list;
|
||||
mod site_permission;
|
||||
mod space;
|
||||
mod split;
|
||||
mod sync;
|
||||
@@ -32,6 +33,10 @@ pub use plugin::{
|
||||
};
|
||||
pub use profile::{Profile, ProfileKind};
|
||||
pub use reading_list::{ReadingListEntry, ReadingProgress};
|
||||
pub use site_permission::{
|
||||
SiteOrigin, SitePermissionAuditAction, SitePermissionAuditEvent, SitePermissionDecision,
|
||||
SitePermissionEntry, SitePermissionFeature,
|
||||
};
|
||||
pub use space::{ArchivePolicy, Space};
|
||||
pub use split::{SplitAxis, SplitLayout, SplitPane};
|
||||
pub use sync::{
|
||||
|
||||
@@ -0,0 +1,259 @@
|
||||
use std::time::SystemTime;
|
||||
|
||||
use url::Url;
|
||||
|
||||
use crate::{DomainError, ProfileId, UrlText};
|
||||
|
||||
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
||||
pub struct SiteOrigin(String);
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum SitePermissionFeature {
|
||||
Camera,
|
||||
Microphone,
|
||||
ScreenCapture,
|
||||
Location,
|
||||
Notifications,
|
||||
ClipboardRead,
|
||||
ClipboardWrite,
|
||||
Downloads,
|
||||
Popups,
|
||||
Autoplay,
|
||||
WebUsb,
|
||||
WebHid,
|
||||
WebSerial,
|
||||
StoragePersistence,
|
||||
InsecureContent,
|
||||
CertificateException,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum SitePermissionDecision {
|
||||
AllowOnce,
|
||||
AllowAlways,
|
||||
DenyAlways,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct SitePermissionEntry {
|
||||
profile_id: ProfileId,
|
||||
origin: SiteOrigin,
|
||||
feature: SitePermissionFeature,
|
||||
decision: SitePermissionDecision,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum SitePermissionAuditAction {
|
||||
Set(SitePermissionDecision),
|
||||
Revoked,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct SitePermissionAuditEvent {
|
||||
profile_id: ProfileId,
|
||||
origin: SiteOrigin,
|
||||
feature: SitePermissionFeature,
|
||||
action: SitePermissionAuditAction,
|
||||
created_at: SystemTime,
|
||||
}
|
||||
|
||||
impl SiteOrigin {
|
||||
pub fn parse(value: impl Into<String>) -> Result<Self, DomainError> {
|
||||
let value = value.into();
|
||||
let trimmed = value.trim();
|
||||
if trimmed.is_empty() {
|
||||
return Err(DomainError::EmptyField { field: "site_origin" });
|
||||
}
|
||||
|
||||
let url = Url::parse(trimmed)
|
||||
.map_err(|_| DomainError::InvalidSiteOrigin { value: trimmed.to_string() })?;
|
||||
site_origin_from_url(&url)
|
||||
}
|
||||
|
||||
pub fn from_url(url: &UrlText) -> Result<Option<Self>, DomainError> {
|
||||
let parsed = Url::parse(url.as_str())
|
||||
.map_err(|_| DomainError::InvalidUrl { value: url.as_str().to_string() })?;
|
||||
if !matches!(parsed.scheme(), "http" | "https") {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
site_origin_from_url(&parsed).map(Some)
|
||||
}
|
||||
|
||||
pub fn from_site_route(route: &str) -> Result<Option<Self>, DomainError> {
|
||||
let Some(origin) = route.strip_prefix("ely://site/") else {
|
||||
return Ok(None);
|
||||
};
|
||||
Self::parse(origin).map(Some)
|
||||
}
|
||||
|
||||
pub fn site_settings_url(&self) -> Result<UrlText, DomainError> {
|
||||
UrlText::parse(format!("ely://site/{}", self.as_str()))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn as_str(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl SitePermissionFeature {
|
||||
#[must_use]
|
||||
pub fn all() -> &'static [Self] {
|
||||
&[
|
||||
Self::Camera,
|
||||
Self::Microphone,
|
||||
Self::ScreenCapture,
|
||||
Self::Location,
|
||||
Self::Notifications,
|
||||
Self::ClipboardRead,
|
||||
Self::ClipboardWrite,
|
||||
Self::Downloads,
|
||||
Self::Popups,
|
||||
Self::Autoplay,
|
||||
Self::WebUsb,
|
||||
Self::WebHid,
|
||||
Self::WebSerial,
|
||||
Self::StoragePersistence,
|
||||
Self::InsecureContent,
|
||||
Self::CertificateException,
|
||||
]
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Camera => "camera",
|
||||
Self::Microphone => "microphone",
|
||||
Self::ScreenCapture => "screen-capture",
|
||||
Self::Location => "location",
|
||||
Self::Notifications => "notifications",
|
||||
Self::ClipboardRead => "clipboard-read",
|
||||
Self::ClipboardWrite => "clipboard-write",
|
||||
Self::Downloads => "downloads",
|
||||
Self::Popups => "popups",
|
||||
Self::Autoplay => "autoplay",
|
||||
Self::WebUsb => "webusb",
|
||||
Self::WebHid => "webhid",
|
||||
Self::WebSerial => "webserial",
|
||||
Self::StoragePersistence => "storage-persistence",
|
||||
Self::InsecureContent => "insecure-content",
|
||||
Self::CertificateException => "certificate-exception",
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn label(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Camera => "Camera",
|
||||
Self::Microphone => "Microphone",
|
||||
Self::ScreenCapture => "Screen capture",
|
||||
Self::Location => "Location",
|
||||
Self::Notifications => "Notifications",
|
||||
Self::ClipboardRead => "Clipboard read",
|
||||
Self::ClipboardWrite => "Clipboard write",
|
||||
Self::Downloads => "Downloads",
|
||||
Self::Popups => "Popups",
|
||||
Self::Autoplay => "Autoplay",
|
||||
Self::WebUsb => "WebUSB",
|
||||
Self::WebHid => "WebHID",
|
||||
Self::WebSerial => "WebSerial",
|
||||
Self::StoragePersistence => "Storage persistence",
|
||||
Self::InsecureContent => "Insecure content",
|
||||
Self::CertificateException => "Certificate exception",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SitePermissionDecision {
|
||||
#[must_use]
|
||||
pub fn label(&self) -> &'static str {
|
||||
match self {
|
||||
Self::AllowOnce => "Allow once",
|
||||
Self::AllowAlways => "Allow always",
|
||||
Self::DenyAlways => "Deny always",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SitePermissionEntry {
|
||||
#[must_use]
|
||||
pub fn new(
|
||||
profile_id: ProfileId,
|
||||
origin: SiteOrigin,
|
||||
feature: SitePermissionFeature,
|
||||
decision: SitePermissionDecision,
|
||||
) -> Self {
|
||||
Self { profile_id, origin, feature, decision }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn profile_id(&self) -> &ProfileId {
|
||||
&self.profile_id
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn origin(&self) -> &SiteOrigin {
|
||||
&self.origin
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn feature(&self) -> SitePermissionFeature {
|
||||
self.feature
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn decision(&self) -> SitePermissionDecision {
|
||||
self.decision
|
||||
}
|
||||
|
||||
pub fn set_decision(&mut self, decision: SitePermissionDecision) {
|
||||
self.decision = decision;
|
||||
}
|
||||
}
|
||||
|
||||
impl SitePermissionAuditEvent {
|
||||
#[must_use]
|
||||
pub fn new(
|
||||
profile_id: ProfileId,
|
||||
origin: SiteOrigin,
|
||||
feature: SitePermissionFeature,
|
||||
action: SitePermissionAuditAction,
|
||||
created_at: SystemTime,
|
||||
) -> Self {
|
||||
Self { profile_id, origin, feature, action, created_at }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn profile_id(&self) -> &ProfileId {
|
||||
&self.profile_id
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn origin(&self) -> &SiteOrigin {
|
||||
&self.origin
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn feature(&self) -> SitePermissionFeature {
|
||||
self.feature
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn action(&self) -> &SitePermissionAuditAction {
|
||||
&self.action
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn created_at(&self) -> SystemTime {
|
||||
self.created_at
|
||||
}
|
||||
}
|
||||
|
||||
fn site_origin_from_url(url: &Url) -> Result<SiteOrigin, DomainError> {
|
||||
if !matches!(url.scheme(), "http" | "https") || url.host_str().is_none() {
|
||||
return Err(DomainError::InvalidSiteOrigin { value: url.to_string() });
|
||||
}
|
||||
|
||||
Ok(SiteOrigin(url.origin().ascii_serialization()))
|
||||
}
|
||||
@@ -10,6 +10,7 @@ pub enum SyncObjectKind {
|
||||
Bookmarks,
|
||||
ReadingList,
|
||||
Profiles,
|
||||
SitePermissions,
|
||||
History,
|
||||
PluginSettings,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user