From 2acf35d54d8fee89b4d4cbe6e3606f1ee7180a1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nadja=20von=20Reitzenstein=20=C4=8Cerpnjak?= Date: Fri, 24 May 2024 12:48:58 +0200 Subject: [PATCH] Implement new traits structure --- Cargo.lock | 10 +++ Cargo.toml | 3 + api/schema | 2 +- bffhd/capnp/mod.rs | 1 + bffhd/capnp/resource.rs | 42 +++++++++- bffhd/capnp/traits/claimable.rs | 7 ++ bffhd/capnp/traits/mod.rs | 2 + bffhd/capnp/traits/powerable.rs | 4 + bffhd/resources/state/value.rs | 10 +-- bffhd/utils/oid.rs | 141 +++++++++++++++++++++++--------- 10 files changed, 176 insertions(+), 46 deletions(-) create mode 100644 bffhd/capnp/traits/claimable.rs create mode 100644 bffhd/capnp/traits/mod.rs create mode 100644 bffhd/capnp/traits/powerable.rs diff --git a/Cargo.lock b/Cargo.lock index 4ac54b9..b64f8fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -489,6 +489,15 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "bffh-impl" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.58", +] + [[package]] name = "bitfield" version = "0.13.2" @@ -1052,6 +1061,7 @@ dependencies = [ "async-process", "async-trait", "backtrace", + "bffh-impl", "capnp", "capnp-rpc", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 2805841..648ed2d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,9 @@ miette = { version = "4.7.1", features = ["fancy"] } thiserror = "1.0.31" toml = "0.5.8" +# Compilation proc-macros +bffh-impl = { path = "modules/impl" } + # Well-known paths/dirs for e.g. cache dirs = "4.0.0" diff --git a/api/schema b/api/schema index cae56b0..879bc57 160000 --- a/api/schema +++ b/api/schema @@ -1 +1 @@ -Subproject commit cae56b00842362bd4599187b171ddf8a1030e248 +Subproject commit 879bc578b20433c527cea34a5821cdccec9ee587 diff --git a/bffhd/capnp/mod.rs b/bffhd/capnp/mod.rs index 282dd06..14e3867 100644 --- a/bffhd/capnp/mod.rs +++ b/bffhd/capnp/mod.rs @@ -30,6 +30,7 @@ mod resources; mod permissionsystem; mod user; mod user_system; +mod traits; pub struct APIServer { executor: Executor<'static>, diff --git a/bffhd/capnp/resource.rs b/bffhd/capnp/resource.rs index 2041840..ae50c7b 100644 --- a/bffhd/capnp/resource.rs +++ b/bffhd/capnp/resource.rs @@ -3,9 +3,16 @@ use crate::resources::modules::fabaccess::{ArchivedStatus, Status}; use crate::resources::Resource; use crate::session::SessionHandle; use api::resource_capnp::resource; -use api::claim_capnp::claimable; +use api::claim_capnp::{claimable, claim}; +use api::notify_capnp::notifiable; +use api::owned_capnp::owned; +use api::projects_capnp::project; use capnp::capability::Promise; +use capnp::Error; use capnp_rpc::pry; +use api::claim_capnp::claim::{DisownParams, DisownResults, TraitsParams, TraitsResults}; +use api::claim_capnp::claimable::{ClaimParams, ClaimResults}; +use api::owned_capnp::owned::{GetUserParams, GetUserResults}; #[derive(Clone)] pub struct Machine { @@ -26,5 +33,38 @@ impl Machine { impl claimable::Server for Machine { + fn claim(&mut self, params: ClaimParams, mut results: ClaimResults) -> Promise<(), Error> { + let project = params.get().and_then(|r| r.get_project()).ok(); + //self.resource.try_claim(); + let claim = Claim::new(self.session.clone(), project, self.resource.clone()); + pry!(results.get().set_ok(capnp_rpc::new_client(claim))); + Promise::ok(()) + } +} +pub struct Claim { + session: SessionHandle, + project: Option, + resource: Resource, +} +impl Claim { + fn new(session: SessionHandle, project: Option, resource: Resource) -> Self { + Self { session, project, resource } + } +} + +impl notifiable::Server for Claim {} + +impl owned::Server for Claim { + fn get_user(&mut self, _: GetUserParams, mut results: GetUserResults) -> Promise<(), Error> { + let owner = User::new_self(self.session.clone()); + results.get().set_owner(capnp_rpc::new_client(owner)); + Promise::ok(()) + } +} + +impl claim::Server for Claim { + fn traits(&mut self, _: TraitsParams, _: TraitsResults) -> Promise<(), Error> { + todo!() + } } \ No newline at end of file diff --git a/bffhd/capnp/traits/claimable.rs b/bffhd/capnp/traits/claimable.rs new file mode 100644 index 0000000..3712bcf --- /dev/null +++ b/bffhd/capnp/traits/claimable.rs @@ -0,0 +1,7 @@ +use crate::oid; +use crate::utils::oid::ObjectIdentifier; +use api::traits::claimable_capnp::trait_claimable; + +pub const CLAIMABLE_TRAIT_ID: ObjectIdentifier = oid!(1.3.6.1.4.1.61783.612.1.0); + + diff --git a/bffhd/capnp/traits/mod.rs b/bffhd/capnp/traits/mod.rs new file mode 100644 index 0000000..329f76e --- /dev/null +++ b/bffhd/capnp/traits/mod.rs @@ -0,0 +1,2 @@ +mod claimable; +mod powerable; \ No newline at end of file diff --git a/bffhd/capnp/traits/powerable.rs b/bffhd/capnp/traits/powerable.rs new file mode 100644 index 0000000..65d35ff --- /dev/null +++ b/bffhd/capnp/traits/powerable.rs @@ -0,0 +1,4 @@ +use crate::oid; +use crate::utils::oid::ObjectIdentifier; + +pub const TRAIT_ID_POWERABLE: ObjectIdentifier = oid!(1.3.6.1.4.1.61783.612.1.1); \ No newline at end of file diff --git a/bffhd/resources/state/value.rs b/bffhd/resources/state/value.rs index 9b62e2c..e75398b 100644 --- a/bffhd/resources/state/value.rs +++ b/bffhd/resources/state/value.rs @@ -132,7 +132,7 @@ pub trait SerializeDynOid { /// /// This OID will be serialized alongside the trait object and is used to retrieve the /// correct vtable when loading the state from DB. - fn archived_type_oid(&self) -> &'static ObjectIdentifier; + fn archived_type_oid(&self) -> &'static ObjectIdentifier<'static>; /// Serialize this type into a [`DynSerializer`](trait@DynSerializer) fn serialize_dynoid(&self, serializer: &mut dyn DynSerializer) -> Result; @@ -144,7 +144,7 @@ pub trait SerializeDynOid { /// providing the OID that is serialized alongside the state object to be able to correctly cast /// it when accessing state from the DB. pub trait TypeOid { - fn type_oid() -> &'static ObjectIdentifier; + fn type_oid() -> &'static ObjectIdentifier<'static>; fn type_name() -> &'static str; } @@ -153,7 +153,7 @@ where T: for<'a> Serialize, T::Archived: TypeOid, { - fn archived_type_oid(&self) -> &'static ObjectIdentifier { + fn archived_type_oid(&self) -> &'static ObjectIdentifier<'static> { Archived::::type_oid() } @@ -172,7 +172,7 @@ impl ArchivePointee for dyn ArchivedStateValue { impl ArchiveUnsized for dyn SerializeStateValue { type Archived = dyn ArchivedStateValue; - type MetadataResolver = ::Resolver; + type MetadataResolver = as Archive>::Resolver; unsafe fn resolve_metadata( &self, @@ -203,7 +203,7 @@ impl SerializeUnsized for dyn Serializ #[derive(Debug)] pub struct ArchivedStateValueMetadata { - pub type_oid: Archived, + pub type_oid: Archived>, vtable_cache: AtomicUsize, } diff --git a/bffhd/utils/oid.rs b/bffhd/utils/oid.rs index a20afbb..18dc24d 100644 --- a/bffhd/utils/oid.rs +++ b/bffhd/utils/oid.rs @@ -52,6 +52,7 @@ //! [Object Identifiers]: https://en.wikipedia.org/wiki/Object_identifier //! [ITU]: https://en.wikipedia.org/wiki/International_Telecommunications_Union +use std::borrow::Cow; use crate::utils::varint::VarU128; use rkyv::ser::Serializer; use rkyv::vec::{ArchivedVec, VecResolver}; @@ -114,16 +115,16 @@ pub enum ObjectIdentifierError { /// Object Identifier (OID) #[derive(Clone, Eq, PartialEq, Hash)] #[repr(transparent)] -pub struct ObjectIdentifier { - nodes: Box<[u8]>, +pub struct ObjectIdentifier<'a> { + nodes: Cow<'a, [u8]>, } -impl ObjectIdentifier { +impl<'a> ObjectIdentifier<'a> { #[inline(always)] - pub const fn new_unchecked(nodes: Box<[u8]>) -> Self { + pub const fn new_unchecked(nodes: Cow<'a, [u8]>) -> Self { Self { nodes } } - pub fn from_box(nodes: Box<[u8]>) -> Result { + pub fn from_box(nodes: Cow<'a, [u8]>) -> Result { if nodes.len() < 1 { return Err(ObjectIdentifierError::IllegalRootNode); }; @@ -167,7 +168,7 @@ impl ObjectIdentifier { vec.extend_from_slice(var.as_bytes()) } Ok(Self { - nodes: vec.into_boxed_slice(), + nodes: Cow::from(vec), }) } @@ -175,28 +176,29 @@ impl ObjectIdentifier { pub fn root(&self) -> Result { ObjectIdentifierRoot::try_from(self.nodes[0] / 40) } + #[inline(always)] - pub const fn first_node(&self) -> u8 { - self.nodes[0] % 40 + pub fn first_node(&self) -> u8 { + self.nodes.as_ref()[0] % 40 } #[inline(always)] pub fn child_nodes(&self) -> &[u8] { &self.nodes[1..] } #[inline(always)] - pub const fn as_bytes(&self) -> &[u8] { + pub fn as_bytes(&self) -> &[u8] { &self.nodes } } -impl Deref for ObjectIdentifier { +impl Deref for ObjectIdentifier<'_> { type Target = [u8]; fn deref(&self) -> &Self::Target { &self.nodes } } -impl FromStr for ObjectIdentifier { +impl FromStr for ObjectIdentifier<'static> { type Err = ObjectIdentifierError; fn from_str(value: &str) -> Result { @@ -230,13 +232,13 @@ impl FromStr for ObjectIdentifier { } } -impl fmt::Display for ObjectIdentifier { +impl fmt::Display for ObjectIdentifier<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let show: String = self.into(); write!(f, "{}", show) } } -impl fmt::Debug for ObjectIdentifier { +impl fmt::Debug for ObjectIdentifier<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let show: String = self.into(); write!(f, "{}", show) @@ -266,7 +268,7 @@ impl fmt::Debug for ArchivedObjectIdentifier { } } -impl Archive for ObjectIdentifier { +impl Archive for ObjectIdentifier<'_> { type Archived = ArchivedObjectIdentifier; type Resolver = VecResolver; @@ -275,7 +277,7 @@ impl Archive for ObjectIdentifier { ArchivedVec::resolve_from_slice(self.nodes.as_ref(), pos + oid_pos, resolver, oid_out); } } -impl Archive for &'static ObjectIdentifier { +impl Archive for &'static ObjectIdentifier<'_> { type Archived = ArchivedObjectIdentifier; type Resolver = VecResolver; @@ -285,7 +287,7 @@ impl Archive for &'static ObjectIdentifier { } } -impl Serialize for ObjectIdentifier +impl Serialize for ObjectIdentifier<'_> where [u8]: rkyv::SerializeUnsized, { @@ -304,8 +306,8 @@ fn parse_string_first_node(first_child_node: &str) -> Result(value: S) -> Result +impl ObjectIdentifier<'static> { + fn from_string(value: S) -> Result where S: AsRef, { @@ -350,55 +352,55 @@ fn convert_to_string(nodes: &[u8]) -> Result { Ok(out) } -impl Into for &ObjectIdentifier { +impl Into for &ObjectIdentifier<'_> { fn into(self) -> String { convert_to_string(&self.nodes).expect("Valid OID object couldn't be serialized.") } } -impl Into for ObjectIdentifier { +impl Into for ObjectIdentifier <'_>{ fn into(self) -> String { (&self).into() } } -impl<'a> Into<&'a [u8]> for &'a ObjectIdentifier { +impl<'a> Into<&'a [u8]> for &'a ObjectIdentifier<'_> { fn into(self) -> &'a [u8] { &self.nodes } } -impl Into> for ObjectIdentifier { +impl Into> for ObjectIdentifier<'_> { fn into(self) -> Vec { - self.nodes.into_vec() + self.nodes.into() } } -impl TryFrom<&str> for ObjectIdentifier { +impl TryFrom<&str> for ObjectIdentifier<'static> { type Error = ObjectIdentifierError; - fn try_from(value: &str) -> Result { + fn try_from(value: &str) -> Result { ObjectIdentifier::from_string(value) } } -impl TryFrom for ObjectIdentifier { +impl TryFrom for ObjectIdentifier<'static> { type Error = ObjectIdentifierError; - fn try_from(value: String) -> Result { + fn try_from(value: String) -> Result { ObjectIdentifier::from_string(value) } } -impl TryFrom<&[u8]> for ObjectIdentifier { +impl<'a> TryFrom<&'a [u8]> for ObjectIdentifier<'a> { type Error = ObjectIdentifierError; - fn try_from(nodes: &[u8]) -> Result { - Self::from_box(nodes.into()) + fn try_from(nodes: &'a [u8]) -> Result { + Self::from_box(Cow::Borrowed(nodes)) } } -impl TryFrom> for ObjectIdentifier { +impl TryFrom> for ObjectIdentifier<'static> { type Error = ObjectIdentifierError; - fn try_from(value: Vec) -> Result { - Self::from_box(value.into_boxed_slice()) + fn try_from(value: Vec) -> Result { + Self::from_box(Cow::from(value)) } } @@ -410,17 +412,17 @@ mod serde_support { struct OidVisitor; impl<'de> de::Visitor<'de> for OidVisitor { - type Value = ObjectIdentifier; + type Value = ObjectIdentifier<'de>; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a valid buffer representing an OID") } - fn visit_bytes(self, v: &[u8]) -> Result + fn visit_borrowed_bytes(self, v: &'de [u8]) -> Result where E: de::Error, { - ObjectIdentifier::try_from(v).map_err(|err| { + ObjectIdentifier::try_from(v).map_err(move |err| { E::invalid_value( de::Unexpected::Other(match err { ObjectIdentifierError::IllegalRootNode => "illegal root node", @@ -449,8 +451,8 @@ mod serde_support { } } - impl<'de> de::Deserialize<'de> for ObjectIdentifier { - fn deserialize(deserializer: D) -> Result + impl<'de> de::Deserialize<'de> for ObjectIdentifier<'de> { + fn deserialize(deserializer: D) -> Result, D::Error> where D: de::Deserializer<'de>, { @@ -462,7 +464,7 @@ mod serde_support { } } - impl ser::Serialize for ObjectIdentifier { + impl ser::Serialize for ObjectIdentifier<'_> { fn serialize( &self, serializer: S, @@ -494,6 +496,67 @@ mod serde_support { } } +/// Helper macro to declare Object Identifiers at compile-time +/// +/// Since the DER encoded oids are not very readable we provide a +/// procedural macro `oid!`. The macro can be used the following ways: +/// +/// - `oid!(1.4.42.23)`: Create a const expression for the corresponding `Oid<'static>` +/// - `oid!(rel 42.23)`: Create a const expression for the corresponding relative `Oid<'static>` +/// - `oid!(raw 1.4.42.23)`/`oid!(raw rel 42.23)`: Obtain the DER encoded form as a byte array. +/// +/// # Comparing oids +/// +/// Comparing a parsed oid to a static oid is probably the most common +/// thing done with oids in your code. The `oid!` macro can be used in expression positions for +/// this purpose. For example +/// ``` +/// use diflouroborane::oid; +/// use diflouroborane::utils::oid::ObjectIdentifier; +/// +/// # let some_oid: ObjectIdentifier = oid!(1.2.456); +/// const SOME_STATIC_OID: ObjectIdentifier = oid!(1.2.456); +/// assert_eq!(some_oid, SOME_STATIC_OID) +/// ``` +/// To get a relative Oid use `oid!(rel 1.2)`. +/// +/// Because of limitations for procedural macros ([rust issue](https://github.com/rust-lang/rust/issues/54727)) +/// and constants used in patterns ([rust issue](https://github.com/rust-lang/rust/issues/31434)) +/// the `oid` macro can not directly be used in patterns, also not through constants. +/// You can do this, though: +/// ``` +/// # use diflouroborane::oid; +/// # use diflouroborane::utils::oid::ObjectIdentifier; +/// # let some_oid: ObjectIdentifier<'static> = oid!(1.2.456); +/// const SOME_OID: ObjectIdentifier<'static> = oid!(1.2.456); +/// if some_oid == SOME_OID || some_oid == oid!(1.2.456) { +/// println!("match"); +/// } +/// +/// // Alternatively, compare the DER encoded form directly: +/// const SOME_OID_RAW: &[u8] = &oid!(raw 1.2.456); +/// match some_oid.as_bytes() { +/// SOME_OID_RAW => println!("match"), +/// _ => panic!("no match"), +/// } +/// ``` +/// *Attention*, be aware that the latter version might not handle the case of a relative oid correctly. An +/// extra check might be necessary. +#[macro_export] +macro_rules! oid { + (raw $( $item:literal ).*) => { + ::bffh_impl::encode_oid!( $( $item ).* ) + }; + (raw $items:expr) => { + ::bffh_impl::encode_oid!($items) + }; + ($($item:literal ).*) => { + $crate::utils::oid::ObjectIdentifier::new_unchecked(::std::borrow::Cow::Borrowed( + &$crate::oid!(raw $( $item ).*), + )) + }; +} + #[cfg(test)] pub(crate) mod tests { use super::*;