Skip to content

Commit

Permalink
web: don't use carets (<,>) in URLs
Browse files Browse the repository at this point in the history
Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>
  • Loading branch information
epilys committed Jan 26, 2024
1 parent 4bc6062 commit acb26c5
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 12 deletions.
27 changes: 27 additions & 0 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,33 @@ impl StripCarets for &str {
}
}

/// Trait for stripping carets ('<','>') from Message IDs inplace.
pub trait StripCaretsInplace {
/// If `self` is surrounded by carets, strip them.
fn strip_carets_inplace(self) -> Self;
}

impl StripCaretsInplace for &str {
fn strip_carets_inplace(self) -> Self {
let mut self_ref = self.trim();
if self_ref.starts_with('<') && self_ref.ends_with('>') {
self_ref = &self_ref[1..self_ref.len().saturating_sub(1)];
}
self_ref
}
}

impl StripCaretsInplace for String {
fn strip_carets_inplace(mut self) -> Self {
if self.starts_with('<') && self.ends_with('>') {
self.drain(0..1);
let len = self.len();
self.drain(len.saturating_sub(1)..len);
}
self
}
}

use percent_encoding::CONTROLS;
pub use percent_encoding::{utf8_percent_encode, AsciiSet};

Expand Down
2 changes: 1 addition & 1 deletion core/src/posts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,7 @@ impl Connection {
) -> Result<Option<DbVal<Post>>> {
let mut stmt = self.connection.prepare(
"SELECT *, strftime('%Y-%m', CAST(timestamp AS INTEGER), 'unixepoch') AS month_year \
FROM post WHERE list = ? AND message_id = ?;",
FROM post WHERE list = ?1 AND (message_id = ?2 OR concat('<', ?2, '>') = message_id);",
)?;
let ret = stmt
.query_row(rusqlite::params![&list_pk, &message_id], |row| {
Expand Down
8 changes: 4 additions & 4 deletions web/src/lists.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

use chrono::TimeZone;
use indexmap::IndexMap;
use mailpot::models::Post;
use mailpot::{models::Post, StripCarets, StripCaretsInplace};

use super::*;

Expand Down Expand Up @@ -228,7 +228,7 @@ pub async fn list_post(
list_obj.set_safety(list_owners.as_slice(), &state.conf.administrators);

let context = minijinja::context! {
canonical_url => ListPostPath(ListPathIdentifier::from(list.id.clone()), msg_id.to_string()).to_crumb(),
canonical_url => ListPostPath(ListPathIdentifier::from(list.id.clone()), msg_id.to_string().strip_carets_inplace()).to_crumb(),
page_title => subject_ref,
description => &list.description,
list => Value::from_object(list_obj),
Expand All @@ -239,8 +239,8 @@ pub async fn list_post(
to => &envelope.field_to_to_string(),
subject => &envelope.subject(),
trimmed_subject => subject_ref,
in_reply_to => &envelope.in_reply_to_display().map(|r| r.to_string().as_str().strip_carets().to_string()),
references => &envelope.references().into_iter().map(|m| m.to_string().as_str().strip_carets().to_string()).collect::<Vec<String>>(),
in_reply_to => &envelope.in_reply_to_display().map(|r| r.to_string().strip_carets_inplace()),
references => &envelope.references().into_iter().map(|m| m.to_string().strip_carets_inplace()).collect::<Vec<String>>(),
message_id => msg_id,
message => post.message,
timestamp => post.timestamp,
Expand Down
11 changes: 4 additions & 7 deletions web/src/typed_paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,13 +177,10 @@ macro_rules! list_post_impl {
msg_id: Value,
) -> std::result::Result<Value, Error> {
urlize(state, {
let Some(msg_id) = msg_id.as_str().map(|s| {
if s.starts_with('<') && s.ends_with('>') {
s.to_string()
} else {
format!("<{s}>")
}
}) else {
let Some(msg_id) = msg_id
.as_str()
.map(|s| s.to_string().strip_carets_inplace())
else {
return Err(Error::new(
minijinja::ErrorKind::UnknownMethod,
"Second argument of list_post_path must be a string.",
Expand Down

0 comments on commit acb26c5

Please sign in to comment.