Allow well-formed bread.command events on the emit bus
Docs already said any module or app could publish bread.command.<app>.<verb>, but command is reserved so both unsourced bread-emit and sourced App emit rejected the whole namespace. Keep command unclaimable as an app id; accept bread.command.<known-app>.<verb> (and let an app command another known app). Also ship bread-emit and bread-module-host, and give udev enumerate the same classification fields as a live add so boot-time devices are not all unknown.
This commit is contained in:
parent
a6973360bd
commit
d3517d1433
52 changed files with 26405 additions and 6811 deletions
|
|
@ -8,7 +8,9 @@ use std::sync::Arc;
|
|||
use std::time::Instant;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use bread_shared::apps::{event_domain, is_known_app, is_reserved_domain, validate_app_namespace};
|
||||
use bread_shared::apps::{
|
||||
event_domain, is_known_app, is_reserved_domain, validate_app_namespace, validate_command_event,
|
||||
};
|
||||
use bread_shared::{now_unix_ms, AdapterSource, BreadEvent, RawEvent};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::{json, Value};
|
||||
|
|
@ -34,7 +36,12 @@ mod module_host_bridge;
|
|||
/// *Since 1.6.0* — Workstream G's `module_host.*` methods (hello handshake
|
||||
/// plus the RPC bridge a `bread-module-host` child uses in place of direct
|
||||
/// in-process `bread.*` bindings).
|
||||
const API_VERSION: &str = "1.6.0";
|
||||
/// *Since 1.7.0* — well-formed `bread.command.<known-app>.<verb>` is an
|
||||
/// explicit exception to the reserved-domain reject on unsourced emit, and
|
||||
/// sourced `AdapterSource::App` emit may publish commands to another known
|
||||
/// app. `command` stays in `RESERVED_DOMAINS` so it cannot be claimed as
|
||||
/// an app id.
|
||||
const API_VERSION: &str = "1.7.0";
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Server {
|
||||
|
|
@ -325,13 +332,17 @@ impl Server {
|
|||
};
|
||||
// For a sibling-app source, `kind` is the full dotted event
|
||||
// name (e.g. "bread.clip.copied"), not a bare suffix — it
|
||||
// must live inside that app's own namespace.
|
||||
// must live inside that app's own namespace. Well-formed
|
||||
// `bread.command.<known-app>.<verb>` is the one exception:
|
||||
// an app may publish a command addressed to another known
|
||||
// app (see `validate_command_event`). Adapter namespaces
|
||||
// (`bread.power.*`, `bread.hyprland.*`, ...) stay rejected.
|
||||
if let AdapterSource::App(app) = &source {
|
||||
if !validate_app_namespace(app, kind) {
|
||||
if !validate_app_namespace(app, kind) && !validate_command_event(kind) {
|
||||
return Err((
|
||||
id,
|
||||
format!(
|
||||
"event '{kind}' is not in the '{app}' namespace (must start with 'bread.{app}.')"
|
||||
"event '{kind}' is not in the '{app}' namespace (must start with 'bread.{app}.') and is not a well-formed command event"
|
||||
),
|
||||
));
|
||||
}
|
||||
|
|
@ -363,7 +374,11 @@ impl Server {
|
|||
// `bread.hyprland.*`, ...) — otherwise this path would
|
||||
// let any same-UID process impersonate a real adapter
|
||||
// event with nothing downstream able to tell the
|
||||
// difference.
|
||||
// difference. Well-formed `bread.command.<known-app>.<verb>`
|
||||
// is the documented exception: the command bus is
|
||||
// supposed to be publishable by any module or
|
||||
// `bread-emit` caller. Other reserved domains, and
|
||||
// `bread.command.<not-an-app>.*`, stay rejected.
|
||||
let Some(event) = req.params.get("event").and_then(Value::as_str) else {
|
||||
return Err((id, "missing event name".to_string()));
|
||||
};
|
||||
|
|
@ -429,9 +444,9 @@ impl Server {
|
|||
/// impersonate a real adapter-owned event namespace.
|
||||
fn manual_emit(&self, event: &str, data: Value) -> std::result::Result<Value, String> {
|
||||
if let Some(domain) = event_domain(event) {
|
||||
if is_reserved_domain(domain) {
|
||||
if is_reserved_domain(domain) && !validate_command_event(event) {
|
||||
return Err(format!(
|
||||
"event '{event}' claims the reserved '{domain}' domain — manual emit cannot impersonate an adapter-owned event; use a custom event name, or a sourced emit if this should go through the normalizer"
|
||||
"event '{event}' claims the reserved '{domain}' domain — manual emit cannot impersonate an adapter-owned event; use a custom event name, a well-formed bread.command.<app>.<verb>, or a sourced emit if this should go through the normalizer"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue