1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/* Copyright (c) [2023] [Syswonder Community]
 *   [Rukos] is licensed under Mulan PSL v2.
 *   You can use this software according to the terms and conditions of the Mulan PSL v2.
 *   You may obtain a copy of Mulan PSL v2 at:
 *               http://license.coscl.org.cn/MulanPSL2
 *   THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 *   See the Mulan PSL v2 for more details.
 */

//! Provide basic [capability-based security].
//!
//! The wrapper type [`WithCap`] associates a **capability** to an object, that
//! is a set of access rights. When accessing the object, we must explicitly
//! specify the access capability, and it must not violate the capability
//! associated with the object at initialization.
//!
//! # Examples
//!
//! ```
//! use capability::{Cap, WithCap};
//!
//! let data = WithCap::new(42, Cap::READ | Cap::WRITE);
//!
//! // Access with the correct capability.
//! assert_eq!(data.access(Cap::READ).unwrap(), &42);
//! assert_eq!(data.access(Cap::WRITE).unwrap(), &42);
//! assert_eq!(data.access(Cap::READ | Cap::WRITE).unwrap(), &42);
//!
//! // Access with the incorrect capability.
//! assert!(data.access(Cap::EXECUTE).is_err());
//! assert!(data.access(Cap::READ | Cap::EXECUTE).is_err());
//! ```
//!
//! [capability-based security]:
//!     https://en.wikipedia.org/wiki/Capability-based_security
//!

#![no_std]

bitflags::bitflags! {
    /// Capabilities (access rights).
    #[derive(Default, Debug, Clone, Copy)]
    pub struct Cap: u32 {
        /// Readable access.
        const READ = 1 << 0;
        /// Writable access.
        const WRITE = 1 << 1;
        /// Executable access.
        const EXECUTE = 1 << 2;
    }
}

/// Error type for capability violation.
#[derive(Debug, Default, Eq, PartialEq)]
#[non_exhaustive]
pub struct CapError;

/// A wrapper that holds a type with a capability.
pub struct WithCap<T> {
    inner: T,
    cap: Cap,
}

impl<T> WithCap<T> {
    /// Create a new instance with the given capability.
    pub fn new(inner: T, cap: Cap) -> Self {
        Self { inner, cap }
    }

    /// Get the capability.
    pub const fn cap(&self) -> Cap {
        self.cap
    }

    /// Check if the inner data can be accessed with the given capability.
    ///
    /// # Examples
    ///
    /// ```
    /// use capability::{Cap, WithCap};
    ///
    /// let data = WithCap::new(42, Cap::READ);
    ///
    /// assert!(data.can_access(Cap::READ));
    /// assert!(!data.can_access(Cap::WRITE));
    /// ```
    pub const fn can_access(&self, cap: Cap) -> bool {
        self.cap.contains(cap)
    }

    /// Access the inner value without capability check.
    ///
    /// # Safety
    ///
    /// Caller must ensure not to violate the capability.
    pub unsafe fn access_unchecked(&self) -> &T {
        &self.inner
    }

    /// Access the inner value with the given capability, or return `CapError`
    /// if cannot access.
    ///
    /// # Examples
    ///
    /// ```
    /// use capability::{Cap, CapError, WithCap};
    ///
    /// let data = WithCap::new(42, Cap::READ);
    ///
    /// assert_eq!(data.access(Cap::READ).unwrap(), &42);
    /// assert_eq!(data.access(Cap::WRITE).err(), Some(CapError::default()));
    /// ```
    pub const fn access(&self, cap: Cap) -> Result<&T, CapError> {
        if self.can_access(cap) {
            Ok(&self.inner)
        } else {
            Err(CapError)
        }
    }

    /// Access the inner value with the given capability, or return the given
    /// `err` if cannot access.
    ///
    /// # Examples
    ///
    /// ```
    /// use capability::{Cap, WithCap};
    ///
    /// let data = WithCap::new(42, Cap::READ);
    ///
    /// assert_eq!(data.access_or_err(Cap::READ, "cannot read").unwrap(), &42);
    /// assert_eq!(data.access_or_err(Cap::WRITE, "cannot write").err(), Some("cannot write"));
    /// ```
    pub fn access_or_err<E>(&self, cap: Cap, err: E) -> Result<&T, E> {
        if self.can_access(cap) {
            Ok(&self.inner)
        } else {
            Err(err)
        }
    }
}

impl From<CapError> for axerrno::AxError {
    #[inline]
    fn from(_: CapError) -> Self {
        Self::PermissionDenied
    }
}