From 718bafe6503bf938caeb9267f710715ec59da168 Mon Sep 17 00:00:00 2001 From: Butter Cat Date: Fri, 11 Oct 2024 21:17:33 -0400 Subject: [PATCH 01/12] Split subscriptions and filters cookies into multiple cookies and make old cookies properly delete --- src/server.rs | 11 +++--- src/subreddit.rs | 94 +++++++++++++++++++++++++++++++++++++++--------- src/utils.rs | 65 ++++++++++++++++++++++++++------- 3 files changed, 137 insertions(+), 33 deletions(-) diff --git a/src/server.rs b/src/server.rs index f69d2007..076003ae 100644 --- a/src/server.rs +++ b/src/server.rs @@ -24,7 +24,7 @@ use std::{ str::{from_utf8, Split}, string::ToString, }; -use time::Duration; +use time::OffsetDateTime; use crate::dbg_msg; @@ -169,10 +169,11 @@ impl ResponseExt for Response { } fn remove_cookie(&mut self, name: String) { - let mut cookie = Cookie::from(name); - cookie.set_path("/"); - cookie.set_max_age(Duration::seconds(1)); - if let Ok(val) = header::HeaderValue::from_str(&cookie.to_string()) { + let removal_cookie = Cookie::build(name) + .path("/") + .http_only(true) + .expires(OffsetDateTime::now_utc()); + if let Ok(val) = header::HeaderValue::from_str(&removal_cookie.to_string()) { self.headers_mut().append("Set-Cookie", val); } } diff --git a/src/subreddit.rs b/src/subreddit.rs index a98455d9..41aae8bc 100644 --- a/src/subreddit.rs +++ b/src/subreddit.rs @@ -6,6 +6,7 @@ use crate::utils::{ use crate::{client::json, server::ResponseExt, RequestExt}; use cookie::Cookie; use hyper::{Body, Request, Response}; +use rinja::filters::format; use rinja::Template; use once_cell::sync::Lazy; @@ -209,6 +210,39 @@ pub fn can_access_quarantine(req: &Request, sub: &str) -> bool { setting(req, &format!("allow_quaran_{}", sub.to_lowercase())).parse().unwrap_or_default() } +// Join items in chunks of 3500 bytes in length for cookies +fn join_until_size_limit(vec: &[T]) -> Vec { + let mut result = Vec::new(); + let mut list = String::new(); + let mut current_size = 0; + + for item in vec { + // Size in bytes + let item_size = item.to_string().len(); + // Use 3500 bytes to leave us some headroom because the name and options of the cookie count towards the 4096 byte cap + if current_size + item_size > 3500 { + // Push current list to result vector + result.push(list); + + // Do a reset of the variables required to continue + list = String::new(); + current_size = 0; + } + // Add separator if not the first item + if !list.is_empty() { + list.push_str("+"); + } + // Add current item to list + list.push_str(&item.to_string()); + current_size += item_size; + } + // Make sure to push whatever the remaining subreddits are there into the result vector + result.push(list); + + // Return resulting vector + result +} + // Sub, filter, unfilter, or unsub by setting subscription cookie using response "Set-Cookie" header pub async fn subscriptions_filters(req: Request) -> Result, String> { let sub = req.param("sub").unwrap_or_default(); @@ -303,26 +337,54 @@ pub async fn subscriptions_filters(req: Request) -> Result, // Delete cookie if empty, else set if sub_list.is_empty() { - response.remove_cookie("subscriptions".to_string()); + // Start with first subcriptions cookie + let mut subcriptions_number = 1; + + // While whatever subcriptionsNUMBER cookie we're looking at has a value + while req.cookie(&format!("subcriptions{}", subcriptions_number)).is_some() { + // Remove that subcriptions cookie + response.remove_cookie(format!("subcriptions{}", subcriptions_number)); + + // Increment subcriptions cookie number + subcriptions_number += 1; + } } else { - response.insert_cookie( - Cookie::build(("subscriptions", sub_list.join("+"))) - .path("/") - .http_only(true) - .expires(OffsetDateTime::now_utc() + Duration::weeks(52)) - .into(), - ); + let mut subcriptions_number = 1; + for list in join_until_size_limit(&sub_list) { + response.insert_cookie( + Cookie::build((format!("subscriptions{}", subcriptions_number), list)) + .path("/") + .http_only(true) + .expires(OffsetDateTime::now_utc() + Duration::weeks(52)) + .into(), + ); + subcriptions_number += 1; + } } if filters.is_empty() { - response.remove_cookie("filters".to_string()); + // Start with first filters cookie + let mut filters_number = 1; + + // While whatever filtersNUMBER cookie we're looking at has a value + while req.cookie(&format!("filters{}", filters_number)).is_some() { + // Remove that filters cookie + response.remove_cookie(format!("filters{}", filters_number)); + + // Increment filters cookie number + filters_number += 1; + } } else { - response.insert_cookie( - Cookie::build(("filters", filters.join("+"))) - .path("/") - .http_only(true) - .expires(OffsetDateTime::now_utc() + Duration::weeks(52)) - .into(), - ); + let mut filters_number = 1; + for list in join_until_size_limit(&filters) { + response.insert_cookie( + Cookie::build((format!("filters{}", filters_number), list)) + .path("/") + .http_only(true) + .expires(OffsetDateTime::now_utc() + Duration::weeks(52)) + .into(), + ); + filters_number += 1; + } } Ok(response) diff --git a/src/utils.rs b/src/utils.rs index 6f977754..baf7a32c 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -9,6 +9,7 @@ use hyper::{Body, Request, Response}; use log::error; use once_cell::sync::Lazy; use regex::Regex; +use rinja::filters::format; use rinja::Template; use rust_embed::RustEmbed; use serde_json::Value; @@ -798,18 +799,58 @@ pub fn param(path: &str, value: &str) -> Option { // Retrieve the value of a setting by name pub fn setting(req: &Request, name: &str) -> String { // Parse a cookie value from request - req - .cookie(name) - .unwrap_or_else(|| { - // If there is no cookie for this setting, try receiving a default from the config - if let Some(default) = get_setting(&format!("REDLIB_DEFAULT_{}", name.to_uppercase())) { - Cookie::new(name, default) - } else { - Cookie::from(name) - } - }) - .value() - .to_string() + + // If this was called with "subscriptions" and the "subscriptions1" cookie has a value + if name == "subscriptions" && req.cookie("subscriptions1").is_some() { + // Create subscriptions string + let mut subscriptions = String::new(); + + // Start with first subscription cookie + let mut subscriptions_number = 1; + + // While whatever subscriptionsNUMBER cookie we're looking at has a value + while req.cookie(&format!("subscriptions{}", subscriptions_number)).is_some() { + // Push whatever subscriptionsNUMBER cookie we're looking at into the subscriptions string + subscriptions.push_str(&req.cookie(&format!("subscriptions{}", subscriptions_number)).unwrap().value().to_string()); + // Increment subscription cookie number + subscriptions_number += 1; + } + + // Return the subscriptions cookies as one large string + subscriptions + } else if name == "filters" && req.cookie("filters1").is_some() { // If this was called with "filters" and the "filters1" cookie has a value + // Create filters string + let mut filters = String::new(); + + // Start with first filters cookie + let mut filters_number = 1; + + // While whatever filtersNUMBER cookie we're looking at has a value + while req.cookie(&format!("filters{}", filters_number)).is_some() { + // Push whatever filtersNUMBER cookie we're looking at into the filters string + filters.push_str(&req.cookie(&format!("filters{}", filters_number)).unwrap().value().to_string()); + // Increment filters cookie number + filters_number += 1; + } + + // Return the filters cookies as one large string + filters + } else { // The above two still come to this if there was no existing value + req + .cookie(name) + .unwrap_or_else(|| { + // If there is no cookie for this setting, try receiving a default from the config + if let Some(default) = get_setting(&format!("REDLIB_DEFAULT_{}", name.to_uppercase())) { + Cookie::new(name, default) + } else { + Cookie::from(name) + } + }) + .value() + .to_string() + } + + } // Retrieve the value of a setting by name or the default value From 63683ead9dc8a0a5958ce3134ba99fb4eebe232c Mon Sep 17 00:00:00 2001 From: Butter Cat Date: Fri, 11 Oct 2024 21:31:27 -0400 Subject: [PATCH 02/12] Cleanup --- src/server.rs | 5 +---- src/subreddit.rs | 29 ++++++++++++++--------------- src/utils.rs | 15 ++++++++------- 3 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/server.rs b/src/server.rs index 076003ae..cb3bf463 100644 --- a/src/server.rs +++ b/src/server.rs @@ -169,10 +169,7 @@ impl ResponseExt for Response { } fn remove_cookie(&mut self, name: String) { - let removal_cookie = Cookie::build(name) - .path("/") - .http_only(true) - .expires(OffsetDateTime::now_utc()); + let removal_cookie = Cookie::build(name).path("/").http_only(true).expires(OffsetDateTime::now_utc()); if let Ok(val) = header::HeaderValue::from_str(&removal_cookie.to_string()) { self.headers_mut().append("Set-Cookie", val); } diff --git a/src/subreddit.rs b/src/subreddit.rs index 41aae8bc..60a9c011 100644 --- a/src/subreddit.rs +++ b/src/subreddit.rs @@ -6,7 +6,6 @@ use crate::utils::{ use crate::{client::json, server::ResponseExt, RequestExt}; use cookie::Cookie; use hyper::{Body, Request, Response}; -use rinja::filters::format; use rinja::Template; use once_cell::sync::Lazy; @@ -213,34 +212,34 @@ pub fn can_access_quarantine(req: &Request, sub: &str) -> bool { // Join items in chunks of 3500 bytes in length for cookies fn join_until_size_limit(vec: &[T]) -> Vec { let mut result = Vec::new(); - let mut list = String::new(); - let mut current_size = 0; + let mut list = String::new(); + let mut current_size = 0; - for item in vec { + for item in vec { // Size in bytes - let item_size = item.to_string().len(); + let item_size = item.to_string().len(); // Use 3500 bytes to leave us some headroom because the name and options of the cookie count towards the 4096 byte cap - if current_size + item_size > 3500 { + if current_size + item_size > 3500 { // Push current list to result vector result.push(list); // Do a reset of the variables required to continue - list = String::new(); + list = String::new(); current_size = 0; - } + } // Add separator if not the first item - if !list.is_empty() { - list.push_str("+"); - } + if !list.is_empty() { + list.push('+'); + } // Add current item to list - list.push_str(&item.to_string()); - current_size += item_size; - } + list.push_str(&item.to_string()); + current_size += item_size; + } // Make sure to push whatever the remaining subreddits are there into the result vector result.push(list); // Return resulting vector - result + result } // Sub, filter, unfilter, or unsub by setting subscription cookie using response "Set-Cookie" header diff --git a/src/utils.rs b/src/utils.rs index baf7a32c..032728fa 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -9,7 +9,6 @@ use hyper::{Body, Request, Response}; use log::error; use once_cell::sync::Lazy; use regex::Regex; -use rinja::filters::format; use rinja::Template; use rust_embed::RustEmbed; use serde_json::Value; @@ -811,14 +810,16 @@ pub fn setting(req: &Request, name: &str) -> String { // While whatever subscriptionsNUMBER cookie we're looking at has a value while req.cookie(&format!("subscriptions{}", subscriptions_number)).is_some() { // Push whatever subscriptionsNUMBER cookie we're looking at into the subscriptions string - subscriptions.push_str(&req.cookie(&format!("subscriptions{}", subscriptions_number)).unwrap().value().to_string()); + subscriptions.push_str(req.cookie(&format!("subscriptions{}", subscriptions_number)).unwrap().value()); // Increment subscription cookie number subscriptions_number += 1; } // Return the subscriptions cookies as one large string subscriptions - } else if name == "filters" && req.cookie("filters1").is_some() { // If this was called with "filters" and the "filters1" cookie has a value + } + // If this was called with "filters" and the "filters1" cookie has a value + else if name == "filters" && req.cookie("filters1").is_some() { // Create filters string let mut filters = String::new(); @@ -828,14 +829,16 @@ pub fn setting(req: &Request, name: &str) -> String { // While whatever filtersNUMBER cookie we're looking at has a value while req.cookie(&format!("filters{}", filters_number)).is_some() { // Push whatever filtersNUMBER cookie we're looking at into the filters string - filters.push_str(&req.cookie(&format!("filters{}", filters_number)).unwrap().value().to_string()); + filters.push_str(req.cookie(&format!("filters{}", filters_number)).unwrap().value()); // Increment filters cookie number filters_number += 1; } // Return the filters cookies as one large string filters - } else { // The above two still come to this if there was no existing value + } + // The above two still come to this if there was no existing value + else { req .cookie(name) .unwrap_or_else(|| { @@ -849,8 +852,6 @@ pub fn setting(req: &Request, name: &str) -> String { .value() .to_string() } - - } // Retrieve the value of a setting by name or the default value From 1e725e90ee5662ccc6a3c1ce543399fde97bd755 Mon Sep 17 00:00:00 2001 From: Butter Cat Date: Fri, 11 Oct 2024 21:55:16 -0400 Subject: [PATCH 03/12] Fix mispelling for removing subscription cookies --- src/subreddit.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/subreddit.rs b/src/subreddit.rs index 60a9c011..4b909ac8 100644 --- a/src/subreddit.rs +++ b/src/subreddit.rs @@ -336,19 +336,21 @@ pub async fn subscriptions_filters(req: Request) -> Result, // Delete cookie if empty, else set if sub_list.is_empty() { + // Start with first subcriptions cookie let mut subcriptions_number = 1; // While whatever subcriptionsNUMBER cookie we're looking at has a value - while req.cookie(&format!("subcriptions{}", subcriptions_number)).is_some() { + while req.cookie(&format!("subscriptions{}", subcriptions_number)).is_some() { // Remove that subcriptions cookie - response.remove_cookie(format!("subcriptions{}", subcriptions_number)); + response.remove_cookie(format!("subscriptions{}", subcriptions_number)); // Increment subcriptions cookie number subcriptions_number += 1; } } else { let mut subcriptions_number = 1; + for list in join_until_size_limit(&sub_list) { response.insert_cookie( Cookie::build((format!("subscriptions{}", subcriptions_number), list)) From e4b1406b4b5e1f9b9e2b998bb9d4acaafa979b81 Mon Sep 17 00:00:00 2001 From: Butter Cat Date: Fri, 11 Oct 2024 21:58:10 -0400 Subject: [PATCH 04/12] Fix many subscription misspellings --- src/subreddit.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/subreddit.rs b/src/subreddit.rs index 4b909ac8..c50b508f 100644 --- a/src/subreddit.rs +++ b/src/subreddit.rs @@ -337,29 +337,29 @@ pub async fn subscriptions_filters(req: Request) -> Result, // Delete cookie if empty, else set if sub_list.is_empty() { - // Start with first subcriptions cookie - let mut subcriptions_number = 1; + // Start with first subscriptions cookie + let mut subscriptions_number = 1; - // While whatever subcriptionsNUMBER cookie we're looking at has a value - while req.cookie(&format!("subscriptions{}", subcriptions_number)).is_some() { - // Remove that subcriptions cookie - response.remove_cookie(format!("subscriptions{}", subcriptions_number)); + // While whatever subscriptionsNUMBER cookie we're looking at has a value + while req.cookie(&format!("subscriptions{}", subscriptions_number)).is_some() { + // Remove that subscriptions cookie + response.remove_cookie(format!("subscriptions{}", subscriptions_number)); - // Increment subcriptions cookie number - subcriptions_number += 1; + // Increment subscriptions cookie number + subscriptions_number += 1; } } else { - let mut subcriptions_number = 1; + let mut subscriptions_number = 1; for list in join_until_size_limit(&sub_list) { response.insert_cookie( - Cookie::build((format!("subscriptions{}", subcriptions_number), list)) + Cookie::build((format!("subscriptions{}", subscriptions_number), list)) .path("/") .http_only(true) .expires(OffsetDateTime::now_utc() + Duration::weeks(52)) .into(), ); - subcriptions_number += 1; + subscriptions_number += 1; } } if filters.is_empty() { From 554c9f5d5623abc6e64facd55176dbcf8d0039dc Mon Sep 17 00:00:00 2001 From: Butter Cat Date: Fri, 11 Oct 2024 22:27:04 -0400 Subject: [PATCH 05/12] Fix subreddits and filters that were at the end and beginning of the cookies getting merged --- src/subreddit.rs | 3 +-- src/utils.rs | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/subreddit.rs b/src/subreddit.rs index c50b508f..cb70fa56 100644 --- a/src/subreddit.rs +++ b/src/subreddit.rs @@ -336,7 +336,6 @@ pub async fn subscriptions_filters(req: Request) -> Result, // Delete cookie if empty, else set if sub_list.is_empty() { - // Start with first subscriptions cookie let mut subscriptions_number = 1; @@ -350,7 +349,7 @@ pub async fn subscriptions_filters(req: Request) -> Result, } } else { let mut subscriptions_number = 1; - + for list in join_until_size_limit(&sub_list) { response.insert_cookie( Cookie::build((format!("subscriptions{}", subscriptions_number), list)) diff --git a/src/utils.rs b/src/utils.rs index 032728fa..72894cde 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -809,8 +809,15 @@ pub fn setting(req: &Request, name: &str) -> String { // While whatever subscriptionsNUMBER cookie we're looking at has a value while req.cookie(&format!("subscriptions{}", subscriptions_number)).is_some() { + /* If we're pushing something other than the first subscription cookie add a + between them + to make sure we don't merge the last item of the last list and the first item of the next list */ + if subscriptions_number != 1 { + subscriptions.push('+'); + } + // Push whatever subscriptionsNUMBER cookie we're looking at into the subscriptions string subscriptions.push_str(req.cookie(&format!("subscriptions{}", subscriptions_number)).unwrap().value()); + // Increment subscription cookie number subscriptions_number += 1; } @@ -828,8 +835,15 @@ pub fn setting(req: &Request, name: &str) -> String { // While whatever filtersNUMBER cookie we're looking at has a value while req.cookie(&format!("filters{}", filters_number)).is_some() { + /* If we're pushing something other than the first filters cookie add a + between them + to make sure we don't merge the last item of the last list and the first item of the next list */ + if filters_number != 1 { + filters.push('+'); + } + // Push whatever filtersNUMBER cookie we're looking at into the filters string filters.push_str(req.cookie(&format!("filters{}", filters_number)).unwrap().value()); + // Increment filters cookie number filters_number += 1; } From ea855b70d6ea9d665d3fc9f0f851b96a18dcf112 Mon Sep 17 00:00:00 2001 From: Butter Cat Date: Fri, 11 Oct 2024 22:46:20 -0400 Subject: [PATCH 06/12] Make join_until_size_limit take the +'s into account when calculating length --- src/subreddit.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/subreddit.rs b/src/subreddit.rs index cb70fa56..76174960 100644 --- a/src/subreddit.rs +++ b/src/subreddit.rs @@ -209,7 +209,7 @@ pub fn can_access_quarantine(req: &Request, sub: &str) -> bool { setting(req, &format!("allow_quaran_{}", sub.to_lowercase())).parse().unwrap_or_default() } -// Join items in chunks of 3500 bytes in length for cookies +// Join items in chunks of 4000 bytes in length for cookies fn join_until_size_limit(vec: &[T]) -> Vec { let mut result = Vec::new(); let mut list = String::new(); @@ -218,14 +218,13 @@ fn join_until_size_limit(vec: &[T]) -> Vec 3500 { + // Use 4000 bytes to leave us some headroom because the name and options of the cookie count towards the 4096 byte cap + if current_size + item_size > 4000 { // Push current list to result vector result.push(list); - // Do a reset of the variables required to continue + // Reset the list variable so we can continue with only new items list = String::new(); - current_size = 0; } // Add separator if not the first item if !list.is_empty() { @@ -233,7 +232,7 @@ fn join_until_size_limit(vec: &[T]) -> Vec Date: Sat, 12 Oct 2024 10:11:13 -0400 Subject: [PATCH 07/12] Start cookies without number to be backwards compatible --- src/subreddit.rs | 34 ++++++++++++++++++++++++---------- src/utils.rs | 22 ++++++++++++++++------ 2 files changed, 40 insertions(+), 16 deletions(-) diff --git a/src/subreddit.rs b/src/subreddit.rs index 76174960..57ec3ecd 100644 --- a/src/subreddit.rs +++ b/src/subreddit.rs @@ -335,7 +335,10 @@ pub async fn subscriptions_filters(req: Request) -> Result, // Delete cookie if empty, else set if sub_list.is_empty() { - // Start with first subscriptions cookie + // Remove subscriptions cookie + response.remove_cookie("subscriptions".to_string()); + + // Start with first numbered subscriptions cookie let mut subscriptions_number = 1; // While whatever subscriptionsNUMBER cookie we're looking at has a value @@ -347,21 +350,28 @@ pub async fn subscriptions_filters(req: Request) -> Result, subscriptions_number += 1; } } else { - let mut subscriptions_number = 1; + // Starting at 0 so we handle the subscription cookie without a number first + for (subscriptions_number, list) in join_until_size_limit(&sub_list).into_iter().enumerate() { + let subcriptions_cookie = if subscriptions_number == 0 { + "subscriptions".to_string() + } else { + format!("subscriptions{}", subscriptions_number) + }; - for list in join_until_size_limit(&sub_list) { response.insert_cookie( - Cookie::build((format!("subscriptions{}", subscriptions_number), list)) + Cookie::build((subcriptions_cookie, list)) .path("/") .http_only(true) .expires(OffsetDateTime::now_utc() + Duration::weeks(52)) .into(), ); - subscriptions_number += 1; } } if filters.is_empty() { - // Start with first filters cookie + // Remove filters cookie + response.remove_cookie("filters".to_string()); + + // Start with first numbered filters cookie let mut filters_number = 1; // While whatever filtersNUMBER cookie we're looking at has a value @@ -373,16 +383,20 @@ pub async fn subscriptions_filters(req: Request) -> Result, filters_number += 1; } } else { - let mut filters_number = 1; - for list in join_until_size_limit(&filters) { + for (filters_number, list) in join_until_size_limit(&filters).into_iter().enumerate() { + let filters_cookie = if filters_number == 0 { + "filters".to_string() + } else { + format!("filters{}", filters_number) + }; + response.insert_cookie( - Cookie::build((format!("filters{}", filters_number), list)) + Cookie::build((filters_cookie, list)) .path("/") .http_only(true) .expires(OffsetDateTime::now_utc() + Duration::weeks(52)) .into(), ); - filters_number += 1; } } diff --git a/src/utils.rs b/src/utils.rs index 72894cde..45e72e81 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -799,12 +799,17 @@ pub fn param(path: &str, value: &str) -> Option { pub fn setting(req: &Request, name: &str) -> String { // Parse a cookie value from request - // If this was called with "subscriptions" and the "subscriptions1" cookie has a value - if name == "subscriptions" && req.cookie("subscriptions1").is_some() { + // If this was called with "subscriptions" and the "subscriptions" cookie has a value + if name == "subscriptions" && req.cookie("subscriptions").is_some() { // Create subscriptions string let mut subscriptions = String::new(); - // Start with first subscription cookie + // Default subscriptions cookie + if req.cookie("subscriptions").is_some() { + subscriptions.push_str(req.cookie("subscriptions").unwrap().value()); + } + + // Start with first numbered subscription cookie let mut subscriptions_number = 1; // While whatever subscriptionsNUMBER cookie we're looking at has a value @@ -825,12 +830,17 @@ pub fn setting(req: &Request, name: &str) -> String { // Return the subscriptions cookies as one large string subscriptions } - // If this was called with "filters" and the "filters1" cookie has a value - else if name == "filters" && req.cookie("filters1").is_some() { + // If this was called with "filters" and the "filters" cookie has a value + else if name == "filters" && req.cookie("filters").is_some() { // Create filters string let mut filters = String::new(); - // Start with first filters cookie + // Default filters cookie + if req.cookie("filters").is_some() { + filters.push_str(req.cookie("filters").unwrap().value()); + } + + // Start with first numbered filters cookie let mut filters_number = 1; // While whatever filtersNUMBER cookie we're looking at has a value From 72ec208c1744ba4ba48c8530f12179e2bf6f9394 Mon Sep 17 00:00:00 2001 From: Butter Cat Date: Sat, 12 Oct 2024 20:00:53 -0400 Subject: [PATCH 08/12] Fix old split cookies not being removed and subreddits/filters between cookies occasionally getting merged --- src/subreddit.rs | 61 ++++++++++++++++++++++++++---------------------- src/utils.rs | 12 ---------- 2 files changed, 33 insertions(+), 40 deletions(-) diff --git a/src/subreddit.rs b/src/subreddit.rs index 57ec3ecd..75291fae 100644 --- a/src/subreddit.rs +++ b/src/subreddit.rs @@ -220,6 +220,9 @@ fn join_until_size_limit(vec: &[T]) -> Vec 4000 { + // If last item add a seperator on the end of the list so it's interpreted properly in tanden with the next cookie + list.push('+'); + // Push current list to result vector result.push(list); @@ -236,7 +239,7 @@ fn join_until_size_limit(vec: &[T]) -> Vec) -> Result, let mut response = redirect(&path); - // Delete cookie if empty, else set - if sub_list.is_empty() { - // Remove subscriptions cookie - response.remove_cookie("subscriptions".to_string()); + // Cookies always need to be removed, either the sub list is already empty, or we're setting new ones and need to start with a clean slate. - // Start with first numbered subscriptions cookie - let mut subscriptions_number = 1; + // Remove subscriptions cookie + response.remove_cookie("subscriptions".to_string()); - // While whatever subscriptionsNUMBER cookie we're looking at has a value - while req.cookie(&format!("subscriptions{}", subscriptions_number)).is_some() { - // Remove that subscriptions cookie - response.remove_cookie(format!("subscriptions{}", subscriptions_number)); + // Start with first numbered subscriptions cookie + let mut subscriptions_number = 1; - // Increment subscriptions cookie number - subscriptions_number += 1; - } - } else { + // While whatever subscriptionsNUMBER cookie we're looking at has a value + while req.cookie(&format!("subscriptions{}", subscriptions_number)).is_some() { + // Remove that subscriptions cookie + response.remove_cookie(format!("subscriptions{}", subscriptions_number)); + + // Increment subscriptions cookie number + subscriptions_number += 1; + } + // Subscribe to subs if list isn't empty + if !sub_list.is_empty() { // Starting at 0 so we handle the subscription cookie without a number first for (subscriptions_number, list) in join_until_size_limit(&sub_list).into_iter().enumerate() { let subcriptions_cookie = if subscriptions_number == 0 { @@ -367,22 +371,23 @@ pub async fn subscriptions_filters(req: Request) -> Result, ); } } - if filters.is_empty() { - // Remove filters cookie - response.remove_cookie("filters".to_string()); - // Start with first numbered filters cookie - let mut filters_number = 1; + // Remove filters cookie + response.remove_cookie("filters".to_string()); - // While whatever filtersNUMBER cookie we're looking at has a value - while req.cookie(&format!("filters{}", filters_number)).is_some() { - // Remove that filters cookie - response.remove_cookie(format!("filters{}", filters_number)); + // Start with first numbered filters cookie + let mut filters_number = 1; - // Increment filters cookie number - filters_number += 1; - } - } else { + // While whatever filtersNUMBER cookie we're looking at has a value + while req.cookie(&format!("filters{}", filters_number)).is_some() { + // Remove that filters cookie + response.remove_cookie(format!("filters{}", filters_number)); + + // Increment filters cookie number + filters_number += 1; + } + // Add filters if the list isn't empty + if !filters.is_empty() { for (filters_number, list) in join_until_size_limit(&filters).into_iter().enumerate() { let filters_cookie = if filters_number == 0 { "filters".to_string() diff --git a/src/utils.rs b/src/utils.rs index 45e72e81..51a77215 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -814,12 +814,6 @@ pub fn setting(req: &Request, name: &str) -> String { // While whatever subscriptionsNUMBER cookie we're looking at has a value while req.cookie(&format!("subscriptions{}", subscriptions_number)).is_some() { - /* If we're pushing something other than the first subscription cookie add a + between them - to make sure we don't merge the last item of the last list and the first item of the next list */ - if subscriptions_number != 1 { - subscriptions.push('+'); - } - // Push whatever subscriptionsNUMBER cookie we're looking at into the subscriptions string subscriptions.push_str(req.cookie(&format!("subscriptions{}", subscriptions_number)).unwrap().value()); @@ -845,12 +839,6 @@ pub fn setting(req: &Request, name: &str) -> String { // While whatever filtersNUMBER cookie we're looking at has a value while req.cookie(&format!("filters{}", filters_number)).is_some() { - /* If we're pushing something other than the first filters cookie add a + between them - to make sure we don't merge the last item of the last list and the first item of the next list */ - if filters_number != 1 { - filters.push('+'); - } - // Push whatever filtersNUMBER cookie we're looking at into the filters string filters.push_str(req.cookie(&format!("filters{}", filters_number)).unwrap().value()); From f0603e8fe42a65cca9539e6407f4524b1552a515 Mon Sep 17 00:00:00 2001 From: Butter Cat Date: Sat, 12 Oct 2024 20:25:32 -0400 Subject: [PATCH 09/12] Make updating subscription/filters cookies safer --- src/subreddit.rs | 84 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 58 insertions(+), 26 deletions(-) diff --git a/src/subreddit.rs b/src/subreddit.rs index 75291fae..8598c5c1 100644 --- a/src/subreddit.rs +++ b/src/subreddit.rs @@ -338,22 +338,27 @@ pub async fn subscriptions_filters(req: Request) -> Result, // Cookies always need to be removed, either the sub list is already empty, or we're setting new ones and need to start with a clean slate. - // Remove subscriptions cookie - response.remove_cookie("subscriptions".to_string()); + + // Subscribe to subs if list isn't empty + if sub_list.is_empty() { + // Remove subscriptions cookie + response.remove_cookie("subscriptions".to_string()); - // Start with first numbered subscriptions cookie - let mut subscriptions_number = 1; + // Start with first numbered subscriptions cookie + let mut subscriptions_number = 1; - // While whatever subscriptionsNUMBER cookie we're looking at has a value - while req.cookie(&format!("subscriptions{}", subscriptions_number)).is_some() { - // Remove that subscriptions cookie - response.remove_cookie(format!("subscriptions{}", subscriptions_number)); + // While whatever subscriptionsNUMBER cookie we're looking at has a value + while req.cookie(&format!("subscriptions{}", subscriptions_number)).is_some() { + // Remove that subscriptions cookie + response.remove_cookie(format!("subscriptions{}", subscriptions_number)); + + // Increment subscriptions cookie number + subscriptions_number += 1; + } + } else { + // Start at 0 to keep track of what number we need to start deleting old subscription cookies from + let mut subscriptions_number_to_delete_from = 0; - // Increment subscriptions cookie number - subscriptions_number += 1; - } - // Subscribe to subs if list isn't empty - if !sub_list.is_empty() { // Starting at 0 so we handle the subscription cookie without a number first for (subscriptions_number, list) in join_until_size_limit(&sub_list).into_iter().enumerate() { let subcriptions_cookie = if subscriptions_number == 0 { @@ -369,25 +374,41 @@ pub async fn subscriptions_filters(req: Request) -> Result, .expires(OffsetDateTime::now_utc() + Duration::weeks(52)) .into(), ); + + subscriptions_number_to_delete_from += 1; + } + + // While whatever subscriptionsNUMBER cookie we're looking at has a value + while req.cookie(&format!("subscriptions{}", subscriptions_number_to_delete_from)).is_some() { + // Remove that subscriptions cookie + response.remove_cookie(format!("subscriptions{}", subscriptions_number_to_delete_from)); + + // Increment subscriptions cookie number + subscriptions_number_to_delete_from += 1; } } - // Remove filters cookie - response.remove_cookie("filters".to_string()); + + // Add filters if the list isn't empty + if filters.is_empty() { + // Remove filters cookie + response.remove_cookie("filters".to_string()); - // Start with first numbered filters cookie - let mut filters_number = 1; + // Start with first numbered filters cookie + let mut filters_number = 1; - // While whatever filtersNUMBER cookie we're looking at has a value - while req.cookie(&format!("filters{}", filters_number)).is_some() { - // Remove that filters cookie - response.remove_cookie(format!("filters{}", filters_number)); + // While whatever filtersNUMBER cookie we're looking at has a value + while req.cookie(&format!("filters{}", filters_number)).is_some() { + // Remove that filters cookie + response.remove_cookie(format!("filters{}", filters_number)); + + // Increment filters cookie number + filters_number += 1; + } + } else { + // Start at 0 to keep track of what number we need to start deleting old filters cookies from + let mut filters_number_to_delete_from = 0; - // Increment filters cookie number - filters_number += 1; - } - // Add filters if the list isn't empty - if !filters.is_empty() { for (filters_number, list) in join_until_size_limit(&filters).into_iter().enumerate() { let filters_cookie = if filters_number == 0 { "filters".to_string() @@ -402,6 +423,17 @@ pub async fn subscriptions_filters(req: Request) -> Result, .expires(OffsetDateTime::now_utc() + Duration::weeks(52)) .into(), ); + + filters_number_to_delete_from += 1; + } + + // While whatever filtersNUMBER cookie we're looking at has a value + while req.cookie(&format!("filters{}", filters_number_to_delete_from)).is_some() { + // Remove that filters cookie + response.remove_cookie(format!("filters{}", filters_number_to_delete_from)); + + // Increment filters cookie number + filters_number_to_delete_from += 1; } } From 69b7450c7ce2a464d5a869ddd496feb98d3807f0 Mon Sep 17 00:00:00 2001 From: Butter Cat Date: Sat, 12 Oct 2024 20:29:37 -0400 Subject: [PATCH 10/12] Small cleanup --- src/subreddit.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/subreddit.rs b/src/subreddit.rs index 8598c5c1..a7658d73 100644 --- a/src/subreddit.rs +++ b/src/subreddit.rs @@ -239,7 +239,7 @@ fn join_until_size_limit(vec: &[T]) -> Vec) -> Result, let mut response = redirect(&path); - // Cookies always need to be removed, either the sub list is already empty, or we're setting new ones and need to start with a clean slate. - - - // Subscribe to subs if list isn't empty + // If sub_list is empty remove all subscriptions cookies, otherwise update them and remove old ones if sub_list.is_empty() { // Remove subscriptions cookie response.remove_cookie("subscriptions".to_string()); @@ -388,8 +385,7 @@ pub async fn subscriptions_filters(req: Request) -> Result, } } - - // Add filters if the list isn't empty + // If filters is empty remove all filters cookies, otherwise update them and remove old ones if filters.is_empty() { // Remove filters cookie response.remove_cookie("filters".to_string()); From 2657be22b153699c7f5c630d1ec972fdabcf3280 Mon Sep 17 00:00:00 2001 From: Butter Cat Date: Sun, 13 Oct 2024 11:28:49 -0400 Subject: [PATCH 11/12] Make restore properly add new subscriptions/filters cookies and delete old unused subscriptions/filters cookies --- src/settings.rs | 116 ++++++++++++++++++++++++++++++++++++++++++++++- src/subreddit.rs | 2 +- 2 files changed, 116 insertions(+), 2 deletions(-) diff --git a/src/settings.rs b/src/settings.rs index 5db1a032..8805d1e9 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; // CRATES use crate::server::ResponseExt; +use crate::subreddit::join_until_size_limit; use crate::utils::{redirect, template, Preferences}; use cookie::Cookie; use futures_lite::StreamExt; @@ -116,7 +117,7 @@ fn set_cookies_method(req: Request, remove_cookies: bool) -> Response response.insert_cookie( Cookie::build((name.to_owned(), value.clone())) @@ -133,6 +134,119 @@ fn set_cookies_method(req: Request, remove_cookies: bool) -> Response = subscriptions.expect("Subscriptions").split('+').map(str::to_string).collect(); + + // Start at 0 to keep track of what number we need to start deleting old subscription cookies from + let mut subscriptions_number_to_delete_from = 0; + + // Starting at 0 so we handle the subscription cookie without a number first + for (subscriptions_number, list) in join_until_size_limit(&sub_list).into_iter().enumerate() { + let subcriptions_cookie = if subscriptions_number == 0 { + "subscriptions".to_string() + } else { + format!("subscriptions{}", subscriptions_number) + }; + + response.insert_cookie( + Cookie::build((subcriptions_cookie, list)) + .path("/") + .http_only(true) + .expires(OffsetDateTime::now_utc() + Duration::weeks(52)) + .into(), + ); + + subscriptions_number_to_delete_from += 1; + } + + // While subscriptionsNUMBER= is in the string of cookies add a response removing that cookie + while cookies_string.contains(&format!("subscriptions{subscriptions_number_to_delete_from}=")) { + // Remove that subscriptions cookie + response.remove_cookie(format!("subscriptions{subscriptions_number_to_delete_from}")); + + // Increment subscriptions cookie number + subscriptions_number_to_delete_from += 1; + } + } else { + // Remove unnumbered subscriptions cookie + response.remove_cookie("subscriptions".to_string()); + + // Starts at one to deal with the first numbered subscription cookie and onwards + let mut subscriptions_number_to_delete_from = 1; + + // While subscriptionsNUMBER= is in the string of cookies add a response removing that cookie + while cookies_string.contains(&format!("subscriptions{subscriptions_number_to_delete_from}=")) { + // Remove that subscriptions cookie + response.remove_cookie(format!("subscriptions{subscriptions_number_to_delete_from}")); + + // Increment subscriptions cookie number + subscriptions_number_to_delete_from += 1; + } + } + + // If there are filters to restore set them and delete any old filters cookies, otherwise delete them all + if filters.is_some() { + let filters_list: Vec = filters.expect("Filters").split('+').map(str::to_string).collect(); + + // Start at 0 to keep track of what number we need to start deleting old subscription cookies from + let mut filters_number_to_delete_from = 0; + + // Starting at 0 so we handle the subscription cookie without a number first + for (filters_number, list) in join_until_size_limit(&filters_list).into_iter().enumerate() { + let filters_cookie = if filters_number == 0 { + "filters".to_string() + } else { + format!("filters{}", filters_number) + }; + + response.insert_cookie( + Cookie::build((filters_cookie, list)) + .path("/") + .http_only(true) + .expires(OffsetDateTime::now_utc() + Duration::weeks(52)) + .into(), + ); + + filters_number_to_delete_from += 1; + } + + // While filtersNUMBER= is in the string of cookies add a response removing that cookie + while cookies_string.contains(&format!("filters{filters_number_to_delete_from}=")) { + // Remove that filters cookie + response.remove_cookie(format!("filters{filters_number_to_delete_from}")); + + // Increment filters cookie number + filters_number_to_delete_from += 1; + } + } else { + // Remove unnumbered filters cookie + response.remove_cookie("filters".to_string()); + + // Starts at one to deal with the first numbered subscription cookie and onwards + let mut filters_number_to_delete_from = 1; + + // While filtersNUMBER= is in the string of cookies add a response removing that cookie + while cookies_string.contains(&format!("filters{filters_number_to_delete_from}=")) { + // Remove that sfilters cookie + response.remove_cookie(format!("filters{filters_number_to_delete_from}")); + + // Increment filters cookie number + filters_number_to_delete_from += 1; + } + } + response } diff --git a/src/subreddit.rs b/src/subreddit.rs index a7658d73..9d605bab 100644 --- a/src/subreddit.rs +++ b/src/subreddit.rs @@ -210,7 +210,7 @@ pub fn can_access_quarantine(req: &Request, sub: &str) -> bool { } // Join items in chunks of 4000 bytes in length for cookies -fn join_until_size_limit(vec: &[T]) -> Vec { +pub fn join_until_size_limit(vec: &[T]) -> Vec { let mut result = Vec::new(); let mut list = String::new(); let mut current_size = 0; From fc3ebf0fd4ffe29b6fa22f2cfb9dfed9b202a577 Mon Sep 17 00:00:00 2001 From: Butter Cat Date: Tue, 31 Dec 2024 14:47:48 -0500 Subject: [PATCH 12/12] Fix misspellings on variable name --- src/settings.rs | 4 ++-- src/subreddit.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/settings.rs b/src/settings.rs index 147be2a4..34718c28 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -157,14 +157,14 @@ fn set_cookies_method(req: Request, remove_cookies: bool) -> Response) -> Result, // Starting at 0 so we handle the subscription cookie without a number first for (subscriptions_number, list) in join_until_size_limit(&sub_list).into_iter().enumerate() { - let subcriptions_cookie = if subscriptions_number == 0 { + let subscriptions_cookie = if subscriptions_number == 0 { "subscriptions".to_string() } else { format!("subscriptions{}", subscriptions_number) }; response.insert_cookie( - Cookie::build((subcriptions_cookie, list)) + Cookie::build((subscriptions_cookie, list)) .path("/") .http_only(true) .expires(OffsetDateTime::now_utc() + Duration::weeks(52))