Rocket - Multi-counter using secure cookies (in the client)
examples/rocket/multi-counter-using-encrypted-cookies/Cargo.toml
[package] name = "multi-counter-using-encrypted-cookies" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] rocket = { version = "0.5", features = ["secrets"] }
examples/rocket/multi-counter-using-encrypted-cookies/Rocket.toml
[debug] secret_key = "qqrqdOg7fX4YNaDFzXf1mu6050BQ9okssS5sKkZFMVsd" [release] secret_key = "dOg7fX4YNaDFzXf1mu6050BQ9okssS5sKkZFMVsdpXg="
examples/rocket/multi-counter-using-encrypted-cookies/src/main.rs
#[macro_use] extern crate rocket; use rocket::http::CookieJar; #[get("/")] fn index(cookies: &CookieJar<'_>) -> String { let counter: u32 = match cookies.get_private("counter") { Some(cookie) => match cookie.value().parse() { Ok(val) => val, Err(_) => { eprintln!("Invalid value {} for the 'counter' cookie.", cookie.value()); 0 } }, None => 0, }; let counter = counter + 1; cookies.add_private(("counter", counter.to_string())); format!("Counter: {}", counter) } #[launch] fn rocket() -> _ { rocket::build().mount("/", routes![index]) } #[cfg(test)] mod tests;
examples/rocket/multi-counter-using-encrypted-cookies/src/tests.rs
use rocket::http::Status; use rocket::local::blocking::Client; #[test] fn test_without_cookie() { let client = Client::tracked(super::rocket()).unwrap(); let client = client; let response = client.get("/").dispatch(); assert_eq!(response.status(), Status::Ok); // "counter=C3YSnaksM52BVeYOPjvcOp7pNRAez5ZB8aq+a+A%3D; HttpOnly; SameSite=Strict; Path=/; Expires=Mon, 15 Jan 2024 06:44:15 GMT" let cookie = response.headers().get_one("set-cookie").unwrap(); assert!(cookie.contains("counter=")); assert!(cookie.contains("; HttpOnly; SameSite=Strict; Path=/; Expires=")); assert_eq!(response.into_string(), Some("Counter: 1".into())); } #[test] fn test_with_cookie() { let client = Client::tracked(super::rocket()).unwrap(); let response = client.get("/").private_cookie(("counter", "41")).dispatch(); assert_eq!(response.status(), Status::Ok); assert_eq!(response.into_string(), Some("Counter: 42".into())); } #[test] fn test_with_bad_cookie() { let client = Client::tracked(super::rocket()).unwrap(); let response = client .get("/") .private_cookie(("counter", "bla")) .dispatch(); assert_eq!(response.status(), Status::Ok); assert_eq!(response.into_string(), Some("Counter: 1".into())); } // I was expecting this too to work, but it does not, I get back "Counter 1" for the second request as well. // #[test] // fn test_counter() { // let client = Client::tracked(super::rocket()).unwrap(); // let client = client; // let response = client.get("/").dispatch(); // assert_eq!(response.status(), Status::Ok); // // "counter=C3YSnaksM52BVeYOPjvcOp7pNRAez5ZB8aq+a+A%3D; HttpOnly; SameSite=Strict; Path=/; Expires=Mon, 15 Jan 2024 06:44:15 GMT" // let cookie = response.headers().get_one("set-cookie").unwrap(); // assert!(cookie.contains("counter=")); // assert!(cookie.contains("; HttpOnly; SameSite=Strict; Path=/; Expires=")); // let (head, _tail) = cookie.split_once(';').unwrap(); // let (_head, tail) = head.split_once('=').unwrap(); // let cookie_str = tail.to_string(); // assert_eq!(response.into_string(), Some("Counter: 1".into())); // //assert_eq!(cookie_str, ""); // let response = client.get("/").cookie(("counter", cookie_str)).dispatch(); // assert_eq!(response.into_string(), Some("Counter: 2".into())); // }