Remove 'CookieJar::get_private_pending()'.

This commit removes the 'CookieJar::get_private_pending()' method in
favor of the already existing and correct 'CookieJar::get_pending()'
method. Previously, the 'CookieJar::get_private_pending()' method
attempted to decrypt the value of a pending cookie, which in reality is
plaintext, thus failing. Because the pending value is plaintext, the
'CookieJar::get_pending()' method suffices.

Documentation has been updated to refer to 'CookieJar::get_pending()'.

Fixes #2063.
This commit is contained in:
arlecchino 2022-01-17 15:49:48 +01:00 committed by Sergio Benitez
parent 442b668a7a
commit 1ba41b3990
4 changed files with 128 additions and 39 deletions

View File

@ -39,7 +39,7 @@ pear = "0.2.3"
pin-project-lite = "0.2"
memchr = "2"
stable-pattern = "0.1"
cookie = { version = "0.16.0", features = ["secure", "percent-encode"] }
cookie = { version = "0.16.0", features = ["percent-encode", "secure"] }
state = "0.5.1"
[dependencies.x509-parser]

View File

@ -19,9 +19,8 @@ pub use self::cookie::{Cookie, SameSite, Iter};
/// Changes to a `CookieJar` are _not_ visible via the normal [`get()`] and
/// [`get_private()`] methods. This is typically the desired effect as a
/// `CookieJar` always reflects the cookies in an incoming request. In cases
/// where this is not desired, the [`get_pending()`] and
/// [`get_private_pending()`] methods are available, which always return the
/// latest changes.
/// where this is not desired, the [`get_pending()`] method is available, which
/// always returns the latest changes.
///
/// ```rust
/// # #[macro_use] extern crate rocket;
@ -61,16 +60,14 @@ pub use self::cookie::{Cookie, SameSite, Iter};
/// A type of `&CookieJar` can be retrieved via its `FromRequest` implementation
/// as a request guard or via the [`Request::cookies()`] method. Individual
/// cookies can be retrieved via the [`get()`] and [`get_private()`] methods.
/// Pending changes can be observed via the [`get_pending()`] and
/// [`get_private_pending()`] methods. Cookies can be added or removed via the
/// [`add()`], [`add_private()`], [`remove()`], and [`remove_private()`]
/// methods.
/// Pending changes can be observed via the [`get_pending()`] method. Cookies
/// can be added or removed via the [`add()`], [`add_private()`], [`remove()`],
/// and [`remove_private()`] methods.
///
/// [`Request::cookies()`]: crate::Request::cookies()
/// [`get()`]: #method.get
/// [`get_private()`]: #method.get_private
/// [`get_pending()`]: #method.get_pending
/// [`get_private_pending()`]: #method.get_private_pending
/// [`add()`]: #method.add
/// [`add_private()`]: #method.add_private
/// [`remove()`]: #method.remove
@ -223,7 +220,7 @@ impl<'a> CookieJar<'a> {
///
/// **Note:** This method _does not_ obverse changes made via additions and
/// removals to the cookie jar. To observe those changes, use
/// [`CookieJar::get_private_pending()`].
/// [`CookieJar::get_pending()`].
///
/// # Example
///
@ -243,8 +240,12 @@ impl<'a> CookieJar<'a> {
}
/// Returns a reference to the _original or pending_ `Cookie` inside this
/// container with the name `name`. If no such cookie exists, returns
/// `None`.
/// container with the name `name`, irrespective of whether the cookie was
/// private or not. If no such cookie exists, returns `None`.
///
/// This _does not_ return cookies sent by the client in a request. To
/// retrieve usch cookies, using [`CookieJar::get()`] or
/// [`CookieJar::get_private()`].
///
/// # Example
///
@ -270,29 +271,6 @@ impl<'a> CookieJar<'a> {
self.get(name).cloned()
}
/// Retrives the _original or pending_ `Cookie` inside this collection with
/// the name `name` and authenticates and decrypts the cookie's value. If
/// the cookie cannot be found, or the cookie fails to authenticate or
/// decrypt, `None` is returned.
///
/// # Example
///
/// ```rust
/// # #[macro_use] extern crate rocket;
/// use rocket::http::{Cookie, CookieJar};
///
/// #[get("/")]
/// fn handler(jar: &CookieJar<'_>) {
/// let pending_cookie = jar.get_private_pending("name");
/// }
/// ```
#[cfg(feature = "secrets")]
#[cfg_attr(nightly, doc(cfg(feature = "secrets")))]
pub fn get_private_pending(&self, name: &str) -> Option<Cookie<'static>> {
let cookie = self.get_pending(name)?;
self.jar.private(&self.config.secret_key.key).decrypt(cookie)
}
/// Adds `cookie` to this collection.
///
/// Unless a value is set for the given property, the following defaults are

View File

@ -0,0 +1,112 @@
#![cfg(feature = "secrets")]
#![deny(warnings)]
use rocket::http::{Cookie, CookieJar, SameSite};
use rocket::{get, post, routes};
#[post("/")]
fn cookie_add_private(jar: &CookieJar<'_>) {
let mut cookie_a = Cookie::new("a", "v1");
jar.add(cookie_a.clone());
let mut cookie_b = Cookie::new("b", "v2");
jar.add_private(cookie_b.clone());
jar.add(Cookie::new("c", "v3"));
// private: CookieJar::set_defaults(&mut cookie_a);
cookie_a.set_path("/");
cookie_a.set_same_site(SameSite::Strict);
assert_eq!(jar.get_pending(cookie_a.name()), Some(cookie_a));
// private: CookieJar::set_private_defaults(&mut cookie_b);
cookie_b.set_path("/");
cookie_b.set_same_site(SameSite::Strict);
cookie_b.set_http_only(true);
let expires = time::OffsetDateTime::now_utc() + time::Duration::weeks(1);
cookie_b.set_expires(expires);
let mut cookie_b_pending = jar
.get_pending(cookie_b.name())
.expect("cookie_b_pending None");
cookie_b_pending.set_expires(expires);
assert_eq!(cookie_b_pending, cookie_b);
}
#[get("/")]
fn cookie_get_private(jar: &CookieJar<'_>) -> String {
let (a, b, c) = (jar.get("a"), jar.get_private("b"), jar.get("c"));
assert_ne!(a, b.as_ref());
assert_ne!(a, c);
assert_ne!(b.as_ref(), c);
format!(
"{}{}{}",
a.unwrap().value(),
b.unwrap().value(),
c.unwrap().value()
)
}
/// For test if we got really a private cookie
#[get("/oh-no")]
fn cookie_get(jar: &CookieJar<'_>) -> String {
let (a, b, c) = (jar.get("a"), jar.get("b"), jar.get("c"));
format!(
"{}{}{}",
a.unwrap().value(),
b.unwrap().value(),
c.unwrap().value()
)
}
#[cfg(test)]
mod cookies_private_tests {
use super::*;
use rocket::local::blocking::Client;
use rocket::{Build, Rocket};
fn rocket() -> Rocket<Build> {
rocket::build().mount(
"/",
routes![cookie_add_private, cookie_get, cookie_get_private],
)
}
#[test]
fn test_cookie_add_private() {
let client = Client::debug(rocket()).unwrap();
let response = client.post("/").dispatch();
let cookies = response.cookies();
assert_eq!(cookies.iter().count(), 3);
assert_eq!(cookies.get("a").unwrap().value(), "v1");
assert_eq!(cookies.get_private("b").unwrap().value(), "v2");
assert_ne!(cookies.get("b").unwrap().value(), "v2");
assert_eq!(cookies.get("c").unwrap().value(), "v3");
}
#[test]
fn test_cookie_get_private() {
let client = Client::debug(rocket()).unwrap();
let response = client
.get("/")
.cookie(Cookie::new("a", "Cookie"))
.private_cookie(Cookie::new("b", " tastes "))
.cookie(Cookie::new("c", "good!"))
.dispatch();
assert_eq!(response.into_string().unwrap(), "Cookie tastes good!");
}
/// Test if we got really a private cookie
#[test]
fn test_cookie_get_ohno() {
let client = Client::debug(rocket()).unwrap();
let response = client
.get("/oh-no")
.cookie(Cookie::new("a", "Cookie"))
.private_cookie(Cookie::new("b", " tastes "))
.cookie(Cookie::new("c", "good!"))
.dispatch();
assert_ne!(response.into_string().unwrap(), "Cookie tastes good!");
}
}

View File

@ -531,9 +531,9 @@ rocket = { version = "0.5.0-rc.1", features = ["secrets"] }
```
The API for retrieving, adding, and removing private cookies is identical except
methods are suffixed with `_private`. These methods are: [`get_private`],
[`get_private_pending`], [`add_private`], and [`remove_private`]. An example of
their usage is below:
that most methods are suffixed with `_private`. These methods are:
[`get_private`], [`get_pending`], [`add_private`], and [`remove_private`]. An
example of their usage is below:
```rust
# #[macro_use] extern crate rocket;
@ -576,7 +576,6 @@ For more information on configuration, see the [Configuration](../configuration)
section of the guide.
[`get_private`]: @api/rocket/http/struct.CookieJar.html#method.get_private
[`get_private_pending`]: @api/rocket/http/struct.CookieJar.html#method.get_private_pending
[`add_private`]: @api/rocket/http/struct.CookieJar.html#method.add_private
[`remove_private`]: @api/rocket/http/struct.CookieJar.html#method.remove_private