Skip to main content

routing/
rights.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::error::RightsRoutingError;
6use fidl_fuchsia_io as fio;
7use moniker::ExtendedMoniker;
8#[cfg(feature = "serde")]
9use serde::{Deserialize, Serialize, de::Deserializer, ser::Serializer};
10use std::fmt;
11
12/// Opaque rights type to define new traits like PartialOrd on.
13#[derive(Debug, PartialEq, Eq, Clone, Copy)]
14pub struct Rights(fio::Operations);
15
16impl Rights {
17    /// Ensures the next walk state of rights satisfies a monotonic increasing sequence. Used to
18    /// verify the expectation that no right requested from a use, offer, or expose is missing as
19    /// capability routing walks from the capability's consumer to its provider.
20    pub fn validate_next(
21        &self,
22        next_rights: &Self,
23        moniker: ExtendedMoniker,
24    ) -> Result<(), RightsRoutingError> {
25        if next_rights.0.contains(self.0) {
26            Ok(())
27        } else {
28            Err(RightsRoutingError::Invalid { moniker, requested: *self, provided: *next_rights })
29        }
30    }
31}
32
33/// Allows creating rights from fio::Operations.
34impl From<fio::Operations> for Rights {
35    fn from(rights: fio::Operations) -> Self {
36        Rights(rights)
37    }
38}
39
40impl From<Rights> for fio::Flags {
41    fn from(rights: Rights) -> Self {
42        fio::Flags::from_bits_retain(rights.0.bits())
43    }
44}
45
46impl Into<u64> for Rights {
47    fn into(self) -> u64 {
48        self.0.bits()
49    }
50}
51
52impl Into<fio::Operations> for Rights {
53    fn into(self) -> fio::Operations {
54        let Self(ops) = self;
55        ops
56    }
57}
58
59impl fmt::Display for Rights {
60    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61        let Self(rights) = &self;
62        match *rights {
63            fio::R_STAR_DIR => write!(f, "r*"),
64            fio::W_STAR_DIR => write!(f, "w*"),
65            fio::X_STAR_DIR => write!(f, "x*"),
66            fio::RW_STAR_DIR => write!(f, "rw*"),
67            fio::RX_STAR_DIR => write!(f, "rx*"),
68            ops => write!(f, "{:?}", ops),
69        }
70    }
71}
72
73#[cfg(feature = "serde")]
74impl Serialize for Rights {
75    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
76    where
77        S: Serializer,
78    {
79        let Self(rights) = self;
80        rights.bits().serialize(serializer)
81    }
82}
83
84#[cfg(feature = "serde")]
85impl<'de> Deserialize<'de> for Rights {
86    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
87    where
88        D: Deserializer<'de>,
89    {
90        let bits: u64 = Deserialize::deserialize(deserializer)?;
91        let rights = fio::Operations::from_bits(bits)
92            .ok_or_else(|| serde::de::Error::custom("invalid value for fuchsia.io/Operations"))?;
93        Ok(Self(rights))
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100    use assert_matches::assert_matches;
101
102    #[test]
103    fn validate_next() {
104        assert_matches!(
105            Rights(fio::Operations::empty())
106                .validate_next(&Rights(fio::R_STAR_DIR,), ExtendedMoniker::ComponentManager),
107            Ok(())
108        );
109        assert_matches!(
110            Rights(fio::Operations::READ_BYTES | fio::Operations::GET_ATTRIBUTES,)
111                .validate_next(&Rights(fio::R_STAR_DIR), ExtendedMoniker::ComponentManager),
112            Ok(())
113        );
114        let provided = fio::Operations::READ_BYTES | fio::Operations::GET_ATTRIBUTES;
115        assert_eq!(
116            Rights(fio::R_STAR_DIR)
117                .validate_next(&Rights(provided), ExtendedMoniker::ComponentManager),
118            Err(RightsRoutingError::Invalid {
119                moniker: ExtendedMoniker::ComponentManager,
120                requested: Rights::from(fio::R_STAR_DIR),
121                provided: Rights::from(provided),
122            })
123        );
124        let provided = fio::Operations::READ_BYTES | fio::Operations::GET_ATTRIBUTES;
125        assert_eq!(
126            Rights(fio::Operations::WRITE_BYTES)
127                .validate_next(&Rights(provided), ExtendedMoniker::ComponentManager),
128            Err(RightsRoutingError::Invalid {
129                moniker: ExtendedMoniker::ComponentManager,
130                requested: Rights::from(fio::Operations::WRITE_BYTES),
131                provided: Rights::from(provided),
132            })
133        );
134    }
135}