Author: Manos Pitsidianakis [manos@pitsidianak.is]
Hash: acb26c52dafbff17c0fde43f391839a2c77c63ce
Timestamp: Fri, 26 Jan 2024 14:13:40 +0000 (7 months ago)

+36 -12 +/-4 browse
web: don't use carets (<,>) in URLs
web: don't use carets (<,>) in URLs

Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>
1diff --git a/core/src/lib.rs b/core/src/lib.rs
2index 4f30b93..e56a80a 100644
3--- a/core/src/lib.rs
4+++ b/core/src/lib.rs
5 @@ -221,6 +221,33 @@ impl StripCarets for &str {
6 }
7 }
8
9+ /// Trait for stripping carets ('<','>') from Message IDs inplace.
10+ pub trait StripCaretsInplace {
11+ /// If `self` is surrounded by carets, strip them.
12+ fn strip_carets_inplace(self) -> Self;
13+ }
14+
15+ impl StripCaretsInplace for &str {
16+ fn strip_carets_inplace(self) -> Self {
17+ let mut self_ref = self.trim();
18+ if self_ref.starts_with('<') && self_ref.ends_with('>') {
19+ self_ref = &self_ref[1..self_ref.len().saturating_sub(1)];
20+ }
21+ self_ref
22+ }
23+ }
24+
25+ impl StripCaretsInplace for String {
26+ fn strip_carets_inplace(mut self) -> Self {
27+ if self.starts_with('<') && self.ends_with('>') {
28+ self.drain(0..1);
29+ let len = self.len();
30+ self.drain(len.saturating_sub(1)..len);
31+ }
32+ self
33+ }
34+ }
35+
36 use percent_encoding::CONTROLS;
37 pub use percent_encoding::{utf8_percent_encode, AsciiSet};
38
39 diff --git a/core/src/posts.rs b/core/src/posts.rs
40index 259afb8..d3525dd 100644
41--- a/core/src/posts.rs
42+++ b/core/src/posts.rs
43 @@ -658,7 +658,7 @@ impl Connection {
44 ) -> Result<Option<DbVal<Post>>> {
45 let mut stmt = self.connection.prepare(
46 "SELECT *, strftime('%Y-%m', CAST(timestamp AS INTEGER), 'unixepoch') AS month_year \
47- FROM post WHERE list = ? AND message_id = ?;",
48+ FROM post WHERE list = ?1 AND (message_id = ?2 OR concat('<', ?2, '>') = message_id);",
49 )?;
50 let ret = stmt
51 .query_row(rusqlite::params![&list_pk, &message_id], |row| {
52 diff --git a/web/src/lists.rs b/web/src/lists.rs
53index 82b3bba..f9d130e 100644
54--- a/web/src/lists.rs
55+++ b/web/src/lists.rs
56 @@ -19,7 +19,7 @@
57
58 use chrono::TimeZone;
59 use indexmap::IndexMap;
60- use mailpot::models::Post;
61+ use mailpot::{models::Post, StripCarets, StripCaretsInplace};
62
63 use super::*;
64
65 @@ -228,7 +228,7 @@ pub async fn list_post(
66 list_obj.set_safety(list_owners.as_slice(), &state.conf.administrators);
67
68 let context = minijinja::context! {
69- canonical_url => ListPostPath(ListPathIdentifier::from(list.id.clone()), msg_id.to_string()).to_crumb(),
70+ canonical_url => ListPostPath(ListPathIdentifier::from(list.id.clone()), msg_id.to_string().strip_carets_inplace()).to_crumb(),
71 page_title => subject_ref,
72 description => &list.description,
73 list => Value::from_object(list_obj),
74 @@ -239,8 +239,8 @@ pub async fn list_post(
75 to => &envelope.field_to_to_string(),
76 subject => &envelope.subject(),
77 trimmed_subject => subject_ref,
78- in_reply_to => &envelope.in_reply_to_display().map(|r| r.to_string().as_str().strip_carets().to_string()),
79- references => &envelope.references().into_iter().map(|m| m.to_string().as_str().strip_carets().to_string()).collect::<Vec<String>>(),
80+ in_reply_to => &envelope.in_reply_to_display().map(|r| r.to_string().strip_carets_inplace()),
81+ references => &envelope.references().into_iter().map(|m| m.to_string().strip_carets_inplace()).collect::<Vec<String>>(),
82 message_id => msg_id,
83 message => post.message,
84 timestamp => post.timestamp,
85 diff --git a/web/src/typed_paths.rs b/web/src/typed_paths.rs
86index c21656d..6e0b3de 100644
87--- a/web/src/typed_paths.rs
88+++ b/web/src/typed_paths.rs
89 @@ -177,13 +177,10 @@ macro_rules! list_post_impl {
90 msg_id: Value,
91 ) -> std::result::Result<Value, Error> {
92 urlize(state, {
93- let Some(msg_id) = msg_id.as_str().map(|s| {
94- if s.starts_with('<') && s.ends_with('>') {
95- s.to_string()
96- } else {
97- format!("<{s}>")
98- }
99- }) else {
100+ let Some(msg_id) = msg_id
101+ .as_str()
102+ .map(|s| s.to_string().strip_carets_inplace())
103+ else {
104 return Err(Error::new(
105 minijinja::ErrorKind::UnknownMethod,
106 "Second argument of list_post_path must be a string.",