config: add sandbox client criteria
This commit is contained in:
parent
fd2163d658
commit
9bf79bf23c
20 changed files with 465 additions and 46 deletions
|
|
@ -81,7 +81,12 @@ pub enum ClientCriterionIpc {
|
|||
field: ClientCriterionStringField,
|
||||
regex: bool,
|
||||
},
|
||||
Sandboxed,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
pub enum ClientCriterionStringField {}
|
||||
pub enum ClientCriterionStringField {
|
||||
SandboxEngine,
|
||||
SandboxAppId,
|
||||
SandboxInstanceId,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
use {
|
||||
crate::{
|
||||
_private::{
|
||||
ClientCriterionIpc, Config, ConfigEntry, ConfigEntryGen, GenericCriterionIpc,
|
||||
PollableId, VERSION, WireMode, bincode_ops,
|
||||
ClientCriterionIpc, ClientCriterionStringField, Config, ConfigEntry, ConfigEntryGen,
|
||||
GenericCriterionIpc, PollableId, VERSION, WireMode, bincode_ops,
|
||||
ipc::{
|
||||
ClientMessage, InitMessage, Response, ServerFeature, ServerMessage, WorkspaceSource,
|
||||
},
|
||||
|
|
@ -1501,7 +1501,6 @@ impl ConfigClient {
|
|||
criterion: ClientCriterion<'_>,
|
||||
child: bool,
|
||||
) -> (ClientMatcher, bool) {
|
||||
#[expect(unused_macros)]
|
||||
macro_rules! string {
|
||||
($t:expr, $field:ident, $regex:expr) => {
|
||||
ClientCriterionIpc::String {
|
||||
|
|
@ -1530,15 +1529,20 @@ impl ConfigClient {
|
|||
destroy_matcher,
|
||||
)
|
||||
};
|
||||
#[expect(unused_variables)]
|
||||
let criterion = match criterion {
|
||||
ClientCriterion::Matcher(m) => return generic(GenericCriterion::Matcher(m)),
|
||||
ClientCriterion::Not(c) => return generic(GenericCriterion::Not(c)),
|
||||
ClientCriterion::All(c) => return generic(GenericCriterion::All(c)),
|
||||
ClientCriterion::Any(c) => return generic(GenericCriterion::Any(c)),
|
||||
ClientCriterion::Exactly(n, c) => return generic(GenericCriterion::Exactly(n, c)),
|
||||
ClientCriterion::SandboxEngine(t) => string!(t, SandboxEngine, false),
|
||||
ClientCriterion::SandboxEngineRegex(t) => string!(t, SandboxEngine, true),
|
||||
ClientCriterion::SandboxAppId(t) => string!(t, SandboxAppId, false),
|
||||
ClientCriterion::SandboxAppIdRegex(t) => string!(t, SandboxAppId, true),
|
||||
ClientCriterion::SandboxInstanceId(t) => string!(t, SandboxInstanceId, false),
|
||||
ClientCriterion::SandboxInstanceIdRegex(t) => string!(t, SandboxInstanceId, true),
|
||||
ClientCriterion::Sandboxed => ClientCriterionIpc::Sandboxed,
|
||||
};
|
||||
#[expect(unreachable_code)]
|
||||
let res = self.send_with_response(&ClientMessage::CreateClientMatcher { criterion });
|
||||
get_response!(
|
||||
res,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,20 @@ pub enum ClientCriterion<'a> {
|
|||
Any(&'a [ClientCriterion<'a>]),
|
||||
/// Matches if an exact number of the contained criteria match.
|
||||
Exactly(usize, &'a [ClientCriterion<'a>]),
|
||||
/// Matches the engine name of the client's sandbox verbatim.
|
||||
SandboxEngine(&'a str),
|
||||
/// Matches the engine name of the client's sandbox with a regular expression.
|
||||
SandboxEngineRegex(&'a str),
|
||||
/// Matches the app id of the client's sandbox verbatim.
|
||||
SandboxAppId(&'a str),
|
||||
/// Matches the app id of the client's sandbox with a regular expression.
|
||||
SandboxAppIdRegex(&'a str),
|
||||
/// Matches the instance id of the client's sandbox verbatim.
|
||||
SandboxInstanceId(&'a str),
|
||||
/// Matches the instance id of the client's sandbox with a regular expression.
|
||||
SandboxInstanceIdRegex(&'a str),
|
||||
/// Matches if the client is sandboxed.
|
||||
Sandboxed,
|
||||
}
|
||||
|
||||
impl ClientCriterion<'_> {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use {
|
|||
crate::{
|
||||
async_engine::SpawnedFuture,
|
||||
client::{CAPS_DEFAULT, ClientCaps},
|
||||
security_context_acceptor::AcceptorMetadata,
|
||||
state::State,
|
||||
utils::{errorfmt::ErrorFmt, oserror::OsError, xrd::xrd},
|
||||
},
|
||||
|
|
@ -170,6 +171,7 @@ impl Acceptor {
|
|||
}
|
||||
|
||||
async fn accept(fd: Rc<OwnedFd>, state: Rc<State>, effective_caps: ClientCaps) {
|
||||
let metadata = Rc::new(AcceptorMetadata::default());
|
||||
loop {
|
||||
let fd = match state.ring.accept(&fd, c::SOCK_CLOEXEC).await {
|
||||
Ok(fd) => fd,
|
||||
|
|
@ -179,9 +181,10 @@ async fn accept(fd: Rc<OwnedFd>, state: Rc<State>, effective_caps: ClientCaps) {
|
|||
}
|
||||
};
|
||||
let id = state.clients.id();
|
||||
if let Err(e) = state
|
||||
.clients
|
||||
.spawn(id, &state, fd, effective_caps, ClientCaps::all())
|
||||
if let Err(e) =
|
||||
state
|
||||
.clients
|
||||
.spawn(id, &state, fd, effective_caps, ClientCaps::all(), &metadata)
|
||||
{
|
||||
log::error!("Could not spawn a client: {}", ErrorFmt(e));
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ use {
|
|||
},
|
||||
leaks::Tracker,
|
||||
object::{Interface, Object, ObjectId, WL_DISPLAY_ID},
|
||||
security_context_acceptor::AcceptorMetadata,
|
||||
state::State,
|
||||
utils::{
|
||||
activation_token::ActivationToken,
|
||||
|
|
@ -125,6 +126,7 @@ impl Clients {
|
|||
socket: Rc<OwnedFd>,
|
||||
effective_caps: ClientCaps,
|
||||
bounding_caps: ClientCaps,
|
||||
acceptor: &Rc<AcceptorMetadata>,
|
||||
) -> Result<(), ClientError> {
|
||||
let Some((uid, pid)) = get_socket_creds(&socket) else {
|
||||
return Ok(());
|
||||
|
|
@ -138,6 +140,7 @@ impl Clients {
|
|||
effective_caps,
|
||||
bounding_caps,
|
||||
false,
|
||||
acceptor,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -152,6 +155,7 @@ impl Clients {
|
|||
effective_caps: ClientCaps,
|
||||
bounding_caps: ClientCaps,
|
||||
is_xwayland: bool,
|
||||
acceptor: &Rc<AcceptorMetadata>,
|
||||
) -> Result<Rc<Client>, ClientError> {
|
||||
let data = Rc::new_cyclic(|slf| Client {
|
||||
id,
|
||||
|
|
@ -183,6 +187,7 @@ impl Clients {
|
|||
focus_stealing_serial: Default::default(),
|
||||
changed_properties: Default::default(),
|
||||
destroyed: Default::default(),
|
||||
acceptor: acceptor.clone(),
|
||||
});
|
||||
track!(data, data);
|
||||
let display = Rc::new(WlDisplay::new(&data));
|
||||
|
|
@ -306,6 +311,7 @@ pub struct Client {
|
|||
pub focus_stealing_serial: Cell<Option<u64>>,
|
||||
pub changed_properties: Cell<ClMatcherChange>,
|
||||
pub destroyed: CopyHashMap<CritMatcherId, Weak<dyn CritDestroyListener<Rc<Self>>>>,
|
||||
pub acceptor: Rc<AcceptorMetadata>,
|
||||
}
|
||||
|
||||
pub const NUM_CACHED_SERIAL_RANGES: usize = 64;
|
||||
|
|
|
|||
|
|
@ -41,7 +41,8 @@ use {
|
|||
bincode::Options,
|
||||
jay_config::{
|
||||
_private::{
|
||||
ClientCriterionIpc, GenericCriterionIpc, PollableId, WireMode, bincode_ops,
|
||||
ClientCriterionIpc, ClientCriterionStringField, GenericCriterionIpc, PollableId,
|
||||
WireMode, bincode_ops,
|
||||
ipc::{ClientMessage, Response, ServerMessage, WorkspaceSource},
|
||||
},
|
||||
Axis, Direction, Workspace,
|
||||
|
|
@ -1868,7 +1869,6 @@ impl ConfigProxyHandler {
|
|||
field,
|
||||
regex,
|
||||
} => {
|
||||
#[expect(unused_variables)]
|
||||
let needle = match *regex {
|
||||
true => {
|
||||
let regex = Regex::new(string).map_err(CphError::InvalidRegex)?;
|
||||
|
|
@ -1876,8 +1876,15 @@ impl ConfigProxyHandler {
|
|||
}
|
||||
false => CritLiteralOrRegex::Literal(string.to_string()),
|
||||
};
|
||||
match *field {}
|
||||
match *field {
|
||||
ClientCriterionStringField::SandboxEngine => mgr.sandbox_engine(needle),
|
||||
ClientCriterionStringField::SandboxAppId => mgr.sandbox_app_id(needle),
|
||||
ClientCriterionStringField::SandboxInstanceId => {
|
||||
mgr.sandbox_instance_id(needle)
|
||||
}
|
||||
}
|
||||
}
|
||||
ClientCriterionIpc::Sandboxed => mgr.sandboxed(),
|
||||
};
|
||||
let cached = Rc::new(CachedCriterion {
|
||||
crit: criterion.clone(),
|
||||
|
|
|
|||
|
|
@ -84,7 +84,6 @@ pub trait CritMgrExt: CritMgr {
|
|||
upstream.not(self)
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
fn root<T>(&self, criterion: T) -> Rc<dyn CritUpstreamNode<Self::Target>>
|
||||
where
|
||||
T: CritRootCriterion<Self::Target>,
|
||||
|
|
|
|||
|
|
@ -4,16 +4,28 @@ use {
|
|||
crate::{
|
||||
client::{Client, ClientId},
|
||||
criteria::{
|
||||
CritDestroyListener, CritMatcherId, CritMatcherIds, CritUpstreamNode, FixedRootMatcher,
|
||||
RootMatcherMap,
|
||||
crit_graph::{CritMgr, CritTarget, CritTargetOwner, WeakCritTargetOwner},
|
||||
CritDestroyListener, CritLiteralOrRegex, CritMatcherId, CritMatcherIds, CritMgrExt,
|
||||
CritUpstreamNode, FixedRootMatcher, RootMatcherMap,
|
||||
clm::clm_matchers::{
|
||||
clmm_sandboxed::ClmMatchSandboxed,
|
||||
clmm_string::{
|
||||
ClmMatchSandboxAppId, ClmMatchSandboxEngine, ClmMatchSandboxInstanceId,
|
||||
},
|
||||
},
|
||||
crit_graph::{
|
||||
CritMgr, CritRoot, CritRootFixed, CritTarget, CritTargetOwner, WeakCritTargetOwner,
|
||||
},
|
||||
crit_leaf::{CritLeafEvent, CritLeafMatcher},
|
||||
crit_matchers::critm_constant::CritMatchConstant,
|
||||
},
|
||||
state::State,
|
||||
utils::{copyhashmap::CopyHashMap, hash_map_ext::HashMapExt, queue::AsyncQueue},
|
||||
},
|
||||
std::rc::{Rc, Weak},
|
||||
linearize::static_map,
|
||||
std::{
|
||||
marker::PhantomData,
|
||||
rc::{Rc, Weak},
|
||||
},
|
||||
};
|
||||
|
||||
bitflags! {
|
||||
|
|
@ -29,14 +41,18 @@ pub struct ClMatcherManager {
|
|||
changes: AsyncQueue<Rc<Client>>,
|
||||
leaf_events: Rc<AsyncQueue<CritLeafEvent<Rc<Client>>>>,
|
||||
constant: ClmFixedRootMatcher<CritMatchConstant<Rc<Client>>>,
|
||||
sandboxed: ClmFixedRootMatcher<ClmMatchSandboxed>,
|
||||
matchers: Rc<RootMatchers>,
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
type ClmRootMatcherMap<T> = RootMatcherMap<Rc<Client>, T>;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct RootMatchers {}
|
||||
pub struct RootMatchers {
|
||||
sandbox_app_id: ClmRootMatcherMap<ClmMatchSandboxAppId>,
|
||||
sandbox_engine: ClmRootMatcherMap<ClmMatchSandboxEngine>,
|
||||
sandbox_instance_id: ClmRootMatcherMap<ClmMatchSandboxInstanceId>,
|
||||
}
|
||||
|
||||
pub async fn handle_cl_changes(state: Rc<State>) {
|
||||
let mgr = &state.cl_matcher_manager;
|
||||
|
|
@ -56,14 +72,12 @@ pub async fn handle_cl_leaf_events(state: Rc<State>) {
|
|||
}
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub type ClmUpstreamNode = dyn CritUpstreamNode<Rc<Client>>;
|
||||
pub type ClmLeafMatcher = CritLeafMatcher<Rc<Client>>;
|
||||
|
||||
impl ClMatcherManager {
|
||||
pub fn new(ids: &Rc<CritMatcherIds>) -> Self {
|
||||
let matchers = Rc::new(RootMatchers::default());
|
||||
#[expect(unused_macros)]
|
||||
macro_rules! bool {
|
||||
($name:ident) => {{
|
||||
static_map! {
|
||||
|
|
@ -77,6 +91,7 @@ impl ClMatcherManager {
|
|||
}
|
||||
Self {
|
||||
constant: CritMatchConstant::create(&matchers, ids),
|
||||
sandboxed: bool!(ClmMatchSandboxed),
|
||||
changes: Default::default(),
|
||||
leaf_events: Default::default(),
|
||||
ids: ids.clone(),
|
||||
|
|
@ -109,7 +124,6 @@ impl ClMatcherManager {
|
|||
}
|
||||
return;
|
||||
}
|
||||
#[expect(unused_macros)]
|
||||
macro_rules! handlers {
|
||||
($name:ident) => {
|
||||
self.matchers
|
||||
|
|
@ -119,7 +133,6 @@ impl ClMatcherManager {
|
|||
.filter_map(|m| m.upgrade())
|
||||
};
|
||||
}
|
||||
#[expect(unused_macros)]
|
||||
macro_rules! fixed {
|
||||
($name:ident) => {
|
||||
self.$name[false].handle(data);
|
||||
|
|
@ -128,7 +141,6 @@ impl ClMatcherManager {
|
|||
}
|
||||
if changed.contains(CL_CHANGED_NEW) {
|
||||
changed |= ClMatcherChange::all();
|
||||
#[expect(unused_macros)]
|
||||
macro_rules! unconditional {
|
||||
($field:ident) => {
|
||||
for m in handlers!($field) {
|
||||
|
|
@ -136,9 +148,29 @@ impl ClMatcherManager {
|
|||
}
|
||||
};
|
||||
}
|
||||
unconditional!(sandbox_instance_id);
|
||||
unconditional!(sandbox_app_id);
|
||||
unconditional!(sandbox_engine);
|
||||
fixed!(sandboxed);
|
||||
self.constant[true].handle(data);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sandbox_engine(&self, string: CritLiteralOrRegex) -> Rc<ClmUpstreamNode> {
|
||||
self.root(ClmMatchSandboxEngine::new(string))
|
||||
}
|
||||
|
||||
pub fn sandbox_app_id(&self, string: CritLiteralOrRegex) -> Rc<ClmUpstreamNode> {
|
||||
self.root(ClmMatchSandboxAppId::new(string))
|
||||
}
|
||||
|
||||
pub fn sandbox_instance_id(&self, string: CritLiteralOrRegex) -> Rc<ClmUpstreamNode> {
|
||||
self.root(ClmMatchSandboxInstanceId::new(string))
|
||||
}
|
||||
|
||||
pub fn sandboxed(&self) -> Rc<ClmUpstreamNode> {
|
||||
self.sandboxed[true].clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl CritTarget for Rc<Client> {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#[expect(unused_macros)]
|
||||
macro_rules! fixed_root_criterion {
|
||||
($ty:ty, $field:ident) => {
|
||||
impl crate::criteria::crit_graph::CritFixedRootCriterionBase<Rc<crate::client::Client>>
|
||||
|
|
@ -17,3 +16,6 @@ macro_rules! fixed_root_criterion {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub mod clmm_sandboxed;
|
||||
pub mod clmm_string;
|
||||
|
|
|
|||
14
src/criteria/clm/clm_matchers/clmm_sandboxed.rs
Normal file
14
src/criteria/clm/clm_matchers/clmm_sandboxed.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
use {
|
||||
crate::{client::Client, criteria::crit_graph::CritFixedRootCriterion},
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
pub struct ClmMatchSandboxed(pub bool);
|
||||
|
||||
fixed_root_criterion!(ClmMatchSandboxed, sandboxed);
|
||||
|
||||
impl CritFixedRootCriterion<Rc<Client>> for ClmMatchSandboxed {
|
||||
fn matches(&self, data: &Rc<Client>) -> bool {
|
||||
data.acceptor.sandboxed
|
||||
}
|
||||
}
|
||||
79
src/criteria/clm/clm_matchers/clmm_string.rs
Normal file
79
src/criteria/clm/clm_matchers/clmm_string.rs
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
use {
|
||||
crate::{
|
||||
client::Client,
|
||||
criteria::{
|
||||
clm::{ClmRootMatcherMap, RootMatchers},
|
||||
crit_matchers::critm_string::{CritMatchString, StringAccess},
|
||||
},
|
||||
security_context_acceptor::AcceptorMetadata,
|
||||
},
|
||||
std::{marker::PhantomData, rc::Rc},
|
||||
};
|
||||
|
||||
pub type ClmMatchString<T> = CritMatchString<Rc<Client>, T>;
|
||||
|
||||
pub type ClmMatchSandboxEngine = ClmMatchString<AcceptorMetadataAccess<SandboxEngineField>>;
|
||||
pub type ClmMatchSandboxAppId = ClmMatchString<AcceptorMetadataAccess<SandboxAppIdField>>;
|
||||
pub type ClmMatchSandboxInstanceId = ClmMatchString<AcceptorMetadataAccess<SandboxInstanceIdField>>;
|
||||
|
||||
pub struct AcceptorMetadataAccess<T>(PhantomData<T>);
|
||||
|
||||
trait SandboxField: Sized + 'static {
|
||||
fn field(meta: &AcceptorMetadata) -> &Option<String>;
|
||||
fn nodes(
|
||||
roots: &RootMatchers,
|
||||
) -> &ClmRootMatcherMap<ClmMatchString<AcceptorMetadataAccess<Self>>>;
|
||||
}
|
||||
|
||||
pub struct SandboxEngineField;
|
||||
pub struct SandboxAppIdField;
|
||||
pub struct SandboxInstanceIdField;
|
||||
|
||||
impl<T> StringAccess<Rc<Client>> for AcceptorMetadataAccess<T>
|
||||
where
|
||||
T: SandboxField,
|
||||
{
|
||||
fn with_string(data: &Rc<Client>, f: impl FnOnce(&str) -> bool) -> bool {
|
||||
f(T::field(&data.acceptor).as_deref().unwrap_or_default())
|
||||
}
|
||||
|
||||
fn nodes(roots: &RootMatchers) -> &ClmRootMatcherMap<ClmMatchString<Self>> {
|
||||
T::nodes(roots)
|
||||
}
|
||||
}
|
||||
|
||||
impl SandboxField for SandboxEngineField {
|
||||
fn field(meta: &AcceptorMetadata) -> &Option<String> {
|
||||
&meta.sandbox_engine
|
||||
}
|
||||
|
||||
fn nodes(
|
||||
roots: &RootMatchers,
|
||||
) -> &ClmRootMatcherMap<ClmMatchString<AcceptorMetadataAccess<Self>>> {
|
||||
&roots.sandbox_engine
|
||||
}
|
||||
}
|
||||
|
||||
impl SandboxField for SandboxAppIdField {
|
||||
fn field(meta: &AcceptorMetadata) -> &Option<String> {
|
||||
&meta.app_id
|
||||
}
|
||||
|
||||
fn nodes(
|
||||
roots: &RootMatchers,
|
||||
) -> &ClmRootMatcherMap<ClmMatchString<AcceptorMetadataAccess<Self>>> {
|
||||
&roots.sandbox_app_id
|
||||
}
|
||||
}
|
||||
|
||||
impl SandboxField for SandboxInstanceIdField {
|
||||
fn field(meta: &AcceptorMetadata) -> &Option<String> {
|
||||
&meta.instance_id
|
||||
}
|
||||
|
||||
fn nodes(
|
||||
roots: &RootMatchers,
|
||||
) -> &ClmRootMatcherMap<ClmMatchString<AcceptorMetadataAccess<Self>>> {
|
||||
&roots.sandbox_instance_id
|
||||
}
|
||||
}
|
||||
|
|
@ -22,7 +22,6 @@ where
|
|||
}
|
||||
|
||||
impl<Target, A> CritMatchString<Target, A> {
|
||||
#[expect(dead_code)]
|
||||
pub fn new(string: CritLiteralOrRegex) -> Self {
|
||||
Self {
|
||||
string,
|
||||
|
|
|
|||
|
|
@ -24,9 +24,7 @@ linear_ids!(AcceptorIds, AcceptorId, u64);
|
|||
struct Acceptor {
|
||||
id: AcceptorId,
|
||||
state: Rc<State>,
|
||||
sandbox_engine: Option<String>,
|
||||
app_id: Option<String>,
|
||||
instance_id: Option<String>,
|
||||
metadata: Rc<AcceptorMetadata>,
|
||||
listen_fd: Rc<OwnedFd>,
|
||||
close_fd: Rc<OwnedFd>,
|
||||
caps: ClientCaps,
|
||||
|
|
@ -34,6 +32,14 @@ struct Acceptor {
|
|||
close_future: Cell<Option<SpawnedFuture<()>>>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct AcceptorMetadata {
|
||||
pub sandboxed: bool,
|
||||
pub sandbox_engine: Option<String>,
|
||||
pub app_id: Option<String>,
|
||||
pub instance_id: Option<String>,
|
||||
}
|
||||
|
||||
impl SecurityContextAcceptors {
|
||||
pub fn clear(&self) {
|
||||
for acceptor in self.acceptors.lock().drain_values() {
|
||||
|
|
@ -54,9 +60,12 @@ impl SecurityContextAcceptors {
|
|||
let acceptor = Rc::new(Acceptor {
|
||||
id: self.ids.next(),
|
||||
state: state.clone(),
|
||||
sandbox_engine,
|
||||
app_id,
|
||||
instance_id,
|
||||
metadata: Rc::new(AcceptorMetadata {
|
||||
sandboxed: true,
|
||||
sandbox_engine,
|
||||
app_id,
|
||||
instance_id,
|
||||
}),
|
||||
listen_fd: listen_fd.clone(),
|
||||
close_fd: close_fd.clone(),
|
||||
caps,
|
||||
|
|
@ -100,7 +109,10 @@ impl Acceptor {
|
|||
}
|
||||
};
|
||||
let id = s.clients.id();
|
||||
if let Err(e) = s.clients.spawn(id, s, fd, self.caps, self.caps) {
|
||||
if let Err(e) = s
|
||||
.clients
|
||||
.spawn(id, s, fd, self.caps, self.caps, &self.metadata)
|
||||
{
|
||||
log::error!("Could not spawn a client: {}", ErrorFmt(e));
|
||||
break;
|
||||
}
|
||||
|
|
@ -119,9 +131,9 @@ impl Display for Acceptor {
|
|||
write!(
|
||||
f,
|
||||
"{}/{}/{}",
|
||||
self.sandbox_engine.as_deref().unwrap_or(""),
|
||||
self.app_id.as_deref().unwrap_or(""),
|
||||
self.instance_id.as_deref().unwrap_or(""),
|
||||
self.metadata.sandbox_engine.as_deref().unwrap_or(""),
|
||||
self.metadata.app_id.as_deref().unwrap_or(""),
|
||||
self.metadata.instance_id.as_deref().unwrap_or(""),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use {
|
|||
wl_surface::x_surface::xwindow::{Xwindow, XwindowData},
|
||||
},
|
||||
io_uring::IoUringError,
|
||||
security_context_acceptor::AcceptorMetadata,
|
||||
state::State,
|
||||
user_session::import_environment,
|
||||
utils::{
|
||||
|
|
@ -179,6 +180,7 @@ async fn run(
|
|||
ClientCaps::all(),
|
||||
ClientCaps::all(),
|
||||
true,
|
||||
&Rc::new(AcceptorMetadata::default()),
|
||||
);
|
||||
let client = match client {
|
||||
Ok(c) => c,
|
||||
|
|
|
|||
|
|
@ -225,6 +225,13 @@ pub struct ClientRule {
|
|||
#[derive(Default, Debug, Clone)]
|
||||
pub struct ClientMatch {
|
||||
pub generic: GenericMatch<Self>,
|
||||
pub sandbox_engine: Option<String>,
|
||||
pub sandbox_engine_regex: Option<String>,
|
||||
pub sandbox_app_id: Option<String>,
|
||||
pub sandbox_app_id_regex: Option<String>,
|
||||
pub sandbox_instance_id: Option<String>,
|
||||
pub sandbox_instance_id_regex: Option<String>,
|
||||
pub sandboxed: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use {
|
|||
config::{
|
||||
ClientMatch, GenericMatch, MatchExactly,
|
||||
context::Context,
|
||||
extractor::{Extractor, ExtractorError, arr, n32, opt, str, val},
|
||||
extractor::{Extractor, ExtractorError, arr, bol, n32, opt, str, val},
|
||||
parser::{DataType, ParseResult, Parser, UnexpectedDataType},
|
||||
},
|
||||
toml::{
|
||||
|
|
@ -36,13 +36,38 @@ impl Parser for ClientMatchParser<'_> {
|
|||
table: &IndexMap<Spanned<String>, Spanned<Value>>,
|
||||
) -> ParseResult<Self> {
|
||||
let mut ext = Extractor::new(self.0, span, table);
|
||||
let ((name, not_val, all_val, any_val, exactly_val),) = ext.extract(((
|
||||
opt(str("name")),
|
||||
opt(val("not")),
|
||||
opt(arr("all")),
|
||||
opt(arr("any")),
|
||||
opt(val("exactly")),
|
||||
),))?;
|
||||
let (
|
||||
(
|
||||
name,
|
||||
not_val,
|
||||
all_val,
|
||||
any_val,
|
||||
exactly_val,
|
||||
sandboxed,
|
||||
sandbox_engine,
|
||||
sandbox_engine_regex,
|
||||
sandbox_app_id,
|
||||
sandbox_app_id_regex,
|
||||
),
|
||||
(sandbox_instance_id, sandbox_instance_id_regex),
|
||||
) = ext.extract((
|
||||
(
|
||||
opt(str("name")),
|
||||
opt(val("not")),
|
||||
opt(arr("all")),
|
||||
opt(arr("any")),
|
||||
opt(val("exactly")),
|
||||
opt(bol("sandboxed")),
|
||||
opt(str("sandbox-engine")),
|
||||
opt(str("sandbox-engine-regex")),
|
||||
opt(str("sandbox-app-id")),
|
||||
opt(str("sandbox-app-id-regex")),
|
||||
),
|
||||
(
|
||||
opt(str("sandbox-instance-id")),
|
||||
opt(str("sandbox-instance-id-regex")),
|
||||
),
|
||||
))?;
|
||||
let mut not = None;
|
||||
if let Some(value) = not_val {
|
||||
not = Some(Box::new(value.parse(&mut ClientMatchParser(self.0))?));
|
||||
|
|
@ -74,6 +99,13 @@ impl Parser for ClientMatchParser<'_> {
|
|||
any,
|
||||
exactly,
|
||||
},
|
||||
sandbox_engine: sandbox_engine.despan_into(),
|
||||
sandbox_engine_regex: sandbox_engine_regex.despan_into(),
|
||||
sandbox_app_id: sandbox_app_id.despan_into(),
|
||||
sandbox_app_id_regex: sandbox_app_id_regex.despan_into(),
|
||||
sandbox_instance_id: sandbox_instance_id.despan_into(),
|
||||
sandbox_instance_id_regex: sandbox_instance_id_regex.despan_into(),
|
||||
sandboxed: sandboxed.despan(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,9 +84,36 @@ impl Rule for ClientRule {
|
|||
|
||||
fn map_custom(
|
||||
_state: &Rc<State>,
|
||||
_all: &mut Vec<MatcherTemp<Self>>,
|
||||
_match_: &Self::Match,
|
||||
all: &mut Vec<MatcherTemp<Self>>,
|
||||
match_: &Self::Match,
|
||||
) -> Option<()> {
|
||||
let m = |c: ClientCriterion<'_>| MatcherTemp(c.to_matcher());
|
||||
macro_rules! value_ref {
|
||||
($ty:ident, $field:ident) => {
|
||||
if let Some(value) = &match_.$field {
|
||||
all.push(m(ClientCriterion::$ty(value)));
|
||||
}
|
||||
};
|
||||
}
|
||||
macro_rules! bool {
|
||||
($ty:ident, $field:ident) => {
|
||||
if let Some(value) = &match_.$field {
|
||||
let crit = ClientCriterion::$ty;
|
||||
let matcher = match value {
|
||||
false => m(ClientCriterion::Not(&crit)),
|
||||
true => m(crit),
|
||||
};
|
||||
all.push(matcher);
|
||||
}
|
||||
};
|
||||
}
|
||||
value_ref!(SandboxEngine, sandbox_engine);
|
||||
value_ref!(SandboxEngineRegex, sandbox_engine_regex);
|
||||
value_ref!(SandboxAppId, sandbox_app_id);
|
||||
value_ref!(SandboxAppIdRegex, sandbox_app_id_regex);
|
||||
value_ref!(SandboxInstanceId, sandbox_instance_id);
|
||||
value_ref!(SandboxInstanceIdRegex, sandbox_instance_id_regex);
|
||||
bool!(Sandboxed, sandboxed);
|
||||
Some(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -531,6 +531,34 @@
|
|||
"exactly": {
|
||||
"description": "Matches if a specific number of contained criteria match.\n\n- Example:\n\n ```toml\n # Matches any client that is either steam or sandboxed by flatpak but not both.\n [[clients]]\n match.exactly.num = 1\n match.exactly.list = [\n { sandbox-engine = \"org.flatpak\" },\n { sandbox-app-id = \"com.valvesoftware.Steam\" },\n ]\n ```\n",
|
||||
"$ref": "#/$defs/ClientMatchExactly"
|
||||
},
|
||||
"sandboxed": {
|
||||
"type": "boolean",
|
||||
"description": "Matches if the client is/isn't sandboxed.\n\n- Example:\n\n ```toml\n [[clients]]\n match.sandboxed = true\n ```\n"
|
||||
},
|
||||
"sandbox-engine": {
|
||||
"type": "string",
|
||||
"description": "Matches the engine name of the client's sandbox verbatim.\n\n- Example:\n\n ```toml\n [[clients]]\n match.sandbox-engine = \"org.flatpak\"\n ```\n"
|
||||
},
|
||||
"sandbox-engine-regex": {
|
||||
"type": "string",
|
||||
"description": "Matches the engine name of the client's sandbox with a regular expression.\n\n- Example:\n\n ```toml\n [[clients]]\n match.sandbox-engine = \"flatpak\"\n ```\n"
|
||||
},
|
||||
"sandbox-app-id": {
|
||||
"type": "string",
|
||||
"description": "Matches the app id of the client's sandbox verbatim.\n\n- Example:\n\n ```toml\n [[clients]]\n match.sandbox-app-id = \"com.spotify.Client\"\n ```\n"
|
||||
},
|
||||
"sandbox-app-id-regex": {
|
||||
"type": "string",
|
||||
"description": "Matches the app id of the client's sandbox with a regular expression.\n\n- Example:\n\n ```toml\n [[clients]]\n match.sandbox-app-id-regex = \"(?i)spotify\"\n ```\n"
|
||||
},
|
||||
"sandbox-instance-id": {
|
||||
"type": "string",
|
||||
"description": "Matches the instance id of the client's sandbox verbatim.\n"
|
||||
},
|
||||
"sandbox-instance-id-regex": {
|
||||
"type": "string",
|
||||
"description": "Matches the instance id of the client's sandbox with a regular expression.\n"
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
|
|
|
|||
|
|
@ -794,6 +794,83 @@ The table has the following fields:
|
|||
|
||||
The value of this field should be a [ClientMatchExactly](#types-ClientMatchExactly).
|
||||
|
||||
- `sandboxed` (optional):
|
||||
|
||||
Matches if the client is/isn't sandboxed.
|
||||
|
||||
- Example:
|
||||
|
||||
```toml
|
||||
[[clients]]
|
||||
match.sandboxed = true
|
||||
```
|
||||
|
||||
The value of this field should be a boolean.
|
||||
|
||||
- `sandbox-engine` (optional):
|
||||
|
||||
Matches the engine name of the client's sandbox verbatim.
|
||||
|
||||
- Example:
|
||||
|
||||
```toml
|
||||
[[clients]]
|
||||
match.sandbox-engine = "org.flatpak"
|
||||
```
|
||||
|
||||
The value of this field should be a string.
|
||||
|
||||
- `sandbox-engine-regex` (optional):
|
||||
|
||||
Matches the engine name of the client's sandbox with a regular expression.
|
||||
|
||||
- Example:
|
||||
|
||||
```toml
|
||||
[[clients]]
|
||||
match.sandbox-engine = "flatpak"
|
||||
```
|
||||
|
||||
The value of this field should be a string.
|
||||
|
||||
- `sandbox-app-id` (optional):
|
||||
|
||||
Matches the app id of the client's sandbox verbatim.
|
||||
|
||||
- Example:
|
||||
|
||||
```toml
|
||||
[[clients]]
|
||||
match.sandbox-app-id = "com.spotify.Client"
|
||||
```
|
||||
|
||||
The value of this field should be a string.
|
||||
|
||||
- `sandbox-app-id-regex` (optional):
|
||||
|
||||
Matches the app id of the client's sandbox with a regular expression.
|
||||
|
||||
- Example:
|
||||
|
||||
```toml
|
||||
[[clients]]
|
||||
match.sandbox-app-id-regex = "(?i)spotify"
|
||||
```
|
||||
|
||||
The value of this field should be a string.
|
||||
|
||||
- `sandbox-instance-id` (optional):
|
||||
|
||||
Matches the instance id of the client's sandbox verbatim.
|
||||
|
||||
The value of this field should be a string.
|
||||
|
||||
- `sandbox-instance-id-regex` (optional):
|
||||
|
||||
Matches the instance id of the client's sandbox with a regular expression.
|
||||
|
||||
The value of this field should be a string.
|
||||
|
||||
|
||||
<a name="types-ClientMatchExactly"></a>
|
||||
### `ClientMatchExactly`
|
||||
|
|
|
|||
|
|
@ -3167,6 +3167,76 @@ ClientMatch:
|
|||
{ sandbox-app-id = "com.valvesoftware.Steam" },
|
||||
]
|
||||
```
|
||||
sandboxed:
|
||||
kind: boolean
|
||||
required: false
|
||||
description: |
|
||||
Matches if the client is/isn't sandboxed.
|
||||
|
||||
- Example:
|
||||
|
||||
```toml
|
||||
[[clients]]
|
||||
match.sandboxed = true
|
||||
```
|
||||
sandbox-engine:
|
||||
kind: string
|
||||
required: false
|
||||
description: |
|
||||
Matches the engine name of the client's sandbox verbatim.
|
||||
|
||||
- Example:
|
||||
|
||||
```toml
|
||||
[[clients]]
|
||||
match.sandbox-engine = "org.flatpak"
|
||||
```
|
||||
sandbox-engine-regex:
|
||||
kind: string
|
||||
required: false
|
||||
description: |
|
||||
Matches the engine name of the client's sandbox with a regular expression.
|
||||
|
||||
- Example:
|
||||
|
||||
```toml
|
||||
[[clients]]
|
||||
match.sandbox-engine = "flatpak"
|
||||
```
|
||||
sandbox-app-id:
|
||||
kind: string
|
||||
required: false
|
||||
description: |
|
||||
Matches the app id of the client's sandbox verbatim.
|
||||
|
||||
- Example:
|
||||
|
||||
```toml
|
||||
[[clients]]
|
||||
match.sandbox-app-id = "com.spotify.Client"
|
||||
```
|
||||
sandbox-app-id-regex:
|
||||
kind: string
|
||||
required: false
|
||||
description: |
|
||||
Matches the app id of the client's sandbox with a regular expression.
|
||||
|
||||
- Example:
|
||||
|
||||
```toml
|
||||
[[clients]]
|
||||
match.sandbox-app-id-regex = "(?i)spotify"
|
||||
```
|
||||
sandbox-instance-id:
|
||||
kind: string
|
||||
required: false
|
||||
description: |
|
||||
Matches the instance id of the client's sandbox verbatim.
|
||||
sandbox-instance-id-regex:
|
||||
kind: string
|
||||
required: false
|
||||
description: |
|
||||
Matches the instance id of the client's sandbox with a regular expression.
|
||||
|
||||
|
||||
ClientMatchExactly:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue