tower_cookies/
signed.rs

1use crate::Cookies;
2use cookie::{Cookie, Key};
3
4/// A child cookie jar that authenticates its cookies.
5/// It signs all the cookies added to it and verifies cookies retrieved from it.
6/// Any cookies stored in `SignedCookies` are provided integrity and authenticity. In other
7/// words, clients cannot tamper with the contents of a cookie nor can they fabricate cookie
8/// values, but the data is visible in plaintext.
9pub struct SignedCookies<'a> {
10    cookies: Cookies,
11    key: &'a Key,
12}
13
14impl<'a> SignedCookies<'a> {
15    /// Creates an instance of `SignedCookies` with parent `cookies` and key `key`. This method is
16    /// typically called indirectly via the `signed` method of [`Cookies`].
17    pub(crate) fn new(cookies: &Cookies, key: &'a Key) -> Self {
18        Self {
19            cookies: cookies.clone(),
20            key,
21        }
22    }
23
24    /// Adds cookie to the parent jar. The cookie’s value is signed assuring integrity and
25    /// authenticity.
26    pub fn add(&self, cookie: Cookie<'static>) {
27        let mut inner = self.cookies.inner.lock();
28        inner.changed = true;
29        inner.jar().signed_mut(self.key).add(cookie);
30    }
31
32    /// Returns `Cookie` with the `name` and verifies the authenticity and integrity of the
33    /// cookie’s value, returning a `Cookie` with the authenticated value. If the cookie cannot be
34    /// found, or the cookie fails to verify, None is returned.
35    pub fn get(&self, name: &str) -> Option<Cookie<'static>> {
36        let mut inner = self.cookies.inner.lock();
37        inner.jar().signed(self.key).get(name)
38    }
39
40    /// Removes the `cookie` from the parent jar.
41    pub fn remove(&self, cookie: Cookie<'static>) {
42        self.cookies.remove(cookie);
43    }
44}
45
46#[cfg(all(test, feature = "signed"))]
47mod tests {
48    use crate::Cookies;
49    use cookie::{Cookie, Key};
50
51    #[test]
52    fn get_absent() {
53        let key = Key::generate();
54        let cookies = Cookies::new(vec![]);
55        assert_eq!(cookies.signed(&key).get("foo"), None);
56    }
57
58    #[test]
59    fn add_get_signed() {
60        let key = Key::generate();
61        let cookies = Cookies::new(vec![]);
62        let cookie = Cookie::new("foo", "bar");
63        let signed = cookies.signed(&key);
64        signed.add(cookie.clone());
65        assert_eq!(signed.get("foo").unwrap(), cookie);
66    }
67
68    #[test]
69    fn add_signed_get_raw() {
70        let key = Key::generate();
71        let cookies = Cookies::new(vec![]);
72        let cookie = Cookie::new("foo", "bar");
73        cookies.signed(&key).add(cookie.clone());
74        assert_ne!(cookies.get("foo").unwrap(), cookie);
75    }
76
77    #[test]
78    fn add_raw_get_signed() {
79        let key = Key::generate();
80        let cookies = Cookies::new(vec![]);
81        let cookie = Cookie::new("foo", "bar");
82        cookies.add(cookie);
83        assert_eq!(cookies.signed(&key).get("foo"), None);
84    }
85
86    #[test]
87    fn messed_keys() {
88        let key1 = Key::generate();
89        let key2 = Key::generate();
90        let cookies = Cookies::new(vec![]);
91        let cookie = Cookie::new("foo", "bar");
92        cookies.signed(&key1).add(cookie);
93        assert_eq!(cookies.signed(&key2).get("foo"), None);
94    }
95
96    #[test]
97    fn remove() {
98        let key = Key::generate();
99        let cookies = Cookies::new(vec![]);
100        let signed = cookies.signed(&key);
101        signed.add(Cookie::new("foo", "bar"));
102        let cookie = signed.get("foo").unwrap();
103        signed.remove(cookie);
104        assert!(signed.get("foo").is_none());
105    }
106}