Fix HTML encoding in templating (#404)
This commit is contained in:
parent
7e07ca3df1
commit
322aa97a18
12 changed files with 33 additions and 47 deletions
11
src/post.rs
11
src/post.rs
|
@ -1,6 +1,5 @@
|
|||
// CRATES
|
||||
use crate::client::json;
|
||||
use crate::esc;
|
||||
use crate::server::RequestExt;
|
||||
use crate::subreddit::{can_access_quarantine, quarantine};
|
||||
use crate::utils::{
|
||||
|
@ -13,7 +12,7 @@ use std::collections::HashSet;
|
|||
|
||||
// STRUCTS
|
||||
#[derive(Template)]
|
||||
#[template(path = "post.html", escape = "none")]
|
||||
#[template(path = "post.html")]
|
||||
struct PostTemplate {
|
||||
comments: Vec<Comment>,
|
||||
post: Post,
|
||||
|
@ -111,7 +110,7 @@ async fn parse_post(json: &serde_json::Value) -> Post {
|
|||
// Build a post using data parsed from Reddit post API
|
||||
Post {
|
||||
id: val(post, "id"),
|
||||
title: esc!(post, "title"),
|
||||
title: val(post, "title"),
|
||||
community: val(post, "subreddit"),
|
||||
body,
|
||||
author: Author {
|
||||
|
@ -122,7 +121,7 @@ async fn parse_post(json: &serde_json::Value) -> Post {
|
|||
post["data"]["author_flair_richtext"].as_array(),
|
||||
post["data"]["author_flair_text"].as_str(),
|
||||
),
|
||||
text: esc!(post, "link_flair_text"),
|
||||
text: val(post, "link_flair_text"),
|
||||
background_color: val(post, "author_flair_background_color"),
|
||||
foreground_color: val(post, "author_flair_text_color"),
|
||||
},
|
||||
|
@ -146,7 +145,7 @@ async fn parse_post(json: &serde_json::Value) -> Post {
|
|||
post["data"]["link_flair_richtext"].as_array(),
|
||||
post["data"]["link_flair_text"].as_str(),
|
||||
),
|
||||
text: esc!(post, "link_flair_text"),
|
||||
text: val(post, "link_flair_text"),
|
||||
background_color: val(post, "link_flair_background_color"),
|
||||
foreground_color: if val(post, "link_flair_text_color") == "dark" {
|
||||
"black".to_string()
|
||||
|
@ -218,7 +217,7 @@ fn parse_comments(json: &serde_json::Value, post_link: &str, post_author: &str,
|
|||
data["author_flair_richtext"].as_array(),
|
||||
data["author_flair_text"].as_str(),
|
||||
),
|
||||
text: esc!(&comment, "link_flair_text"),
|
||||
text: val(&comment, "link_flair_text"),
|
||||
background_color: val(&comment, "author_flair_background_color"),
|
||||
foreground_color: val(&comment, "author_flair_text_color"),
|
||||
},
|
||||
|
|
|
@ -29,7 +29,7 @@ struct Subreddit {
|
|||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "search.html", escape = "none")]
|
||||
#[template(path = "search.html")]
|
||||
struct SearchTemplate {
|
||||
posts: Vec<Post>,
|
||||
subreddits: Vec<Subreddit>,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
// CRATES
|
||||
use crate::esc;
|
||||
use crate::utils::{
|
||||
catch_random, error, filter_posts, format_num, format_url, get_filters, param, redirect, rewrite_urls, setting, template, val, Post, Preferences, Subreddit,
|
||||
};
|
||||
|
@ -11,7 +10,7 @@ use time::{Duration, OffsetDateTime};
|
|||
|
||||
// STRUCTS
|
||||
#[derive(Template)]
|
||||
#[template(path = "subreddit.html", escape = "none")]
|
||||
#[template(path = "subreddit.html")]
|
||||
struct SubredditTemplate {
|
||||
sub: Subreddit,
|
||||
posts: Vec<Post>,
|
||||
|
@ -28,7 +27,7 @@ struct SubredditTemplate {
|
|||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "wiki.html", escape = "none")]
|
||||
#[template(path = "wiki.html")]
|
||||
struct WikiTemplate {
|
||||
sub: String,
|
||||
wiki: String,
|
||||
|
@ -38,7 +37,7 @@ struct WikiTemplate {
|
|||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "wall.html", escape = "none")]
|
||||
#[template(path = "wall.html")]
|
||||
struct WallTemplate {
|
||||
title: String,
|
||||
sub: String,
|
||||
|
@ -408,9 +407,9 @@ async fn subreddit(sub: &str, quarantined: bool) -> Result<Subreddit, String> {
|
|||
let icon = if community_icon.is_empty() { val(&res, "icon_img") } else { community_icon.to_string() };
|
||||
|
||||
Ok(Subreddit {
|
||||
name: esc!(&res, "display_name"),
|
||||
title: esc!(&res, "title"),
|
||||
description: esc!(&res, "public_description"),
|
||||
name: val(&res, "display_name"),
|
||||
title: val(&res, "title"),
|
||||
description: val(&res, "public_description"),
|
||||
info: rewrite_urls(&val(&res, "description_html")),
|
||||
// moderators: moderators_list(sub, quarantined).await.unwrap_or_default(),
|
||||
icon: format_url(&icon),
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
// CRATES
|
||||
use crate::client::json;
|
||||
use crate::esc;
|
||||
use crate::server::RequestExt;
|
||||
use crate::utils::{error, filter_posts, format_url, get_filters, param, template, Post, Preferences, User};
|
||||
use askama::Template;
|
||||
|
@ -9,7 +8,7 @@ use time::{macros::format_description, OffsetDateTime};
|
|||
|
||||
// STRUCTS
|
||||
#[derive(Template)]
|
||||
#[template(path = "user.html", escape = "none")]
|
||||
#[template(path = "user.html")]
|
||||
struct UserTemplate {
|
||||
user: User,
|
||||
posts: Vec<Post>,
|
||||
|
@ -102,11 +101,11 @@ async fn user(name: &str) -> Result<User, String> {
|
|||
// Parse the JSON output into a User struct
|
||||
User {
|
||||
name: res["data"]["name"].as_str().unwrap_or(name).to_owned(),
|
||||
title: esc!(about("title")),
|
||||
title: about("title"),
|
||||
icon: format_url(&about("icon_img")),
|
||||
karma: res["data"]["total_karma"].as_i64().unwrap_or(0),
|
||||
created: created.format(format_description!("[month repr:short] [day] '[year repr:last_two]")).unwrap_or_default(),
|
||||
banner: esc!(about("banner_img")),
|
||||
banner: about("banner_img"),
|
||||
description: about("public_description"),
|
||||
}
|
||||
})
|
||||
|
|
27
src/utils.rs
27
src/utils.rs
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// CRATES
|
||||
//
|
||||
use crate::{client::json, esc, server::RequestExt};
|
||||
use crate::{client::json, server::RequestExt};
|
||||
use askama::Template;
|
||||
use cookie::Cookie;
|
||||
use hyper::{Body, Request, Response};
|
||||
|
@ -42,7 +42,7 @@ impl FlairPart {
|
|||
Self {
|
||||
flair_part_type: value("e").to_string(),
|
||||
value: match value("e") {
|
||||
"text" => esc!(value("t")),
|
||||
"text" => value("t").to_string(),
|
||||
"emoji" => format_url(value("u")),
|
||||
_ => String::new(),
|
||||
},
|
||||
|
@ -55,7 +55,7 @@ impl FlairPart {
|
|||
"text" => match text_flair {
|
||||
Some(text) => vec![Self {
|
||||
flair_part_type: "text".to_string(),
|
||||
value: esc!(text),
|
||||
value: text.to_string(),
|
||||
}],
|
||||
None => Vec::new(),
|
||||
},
|
||||
|
@ -241,7 +241,7 @@ impl Post {
|
|||
let (rel_time, created) = time(data["created_utc"].as_f64().unwrap_or_default());
|
||||
let score = data["score"].as_i64().unwrap_or_default();
|
||||
let ratio: f64 = data["upvote_ratio"].as_f64().unwrap_or(1.0) * 100.0;
|
||||
let title = esc!(post, "title");
|
||||
let title = val(post, "title");
|
||||
|
||||
// Determine the type of media along with the media URL
|
||||
let (post_type, media, gallery) = Media::parse(data).await;
|
||||
|
@ -266,7 +266,7 @@ impl Post {
|
|||
data["author_flair_richtext"].as_array(),
|
||||
data["author_flair_text"].as_str(),
|
||||
),
|
||||
text: esc!(post, "link_flair_text"),
|
||||
text: val(post, "link_flair_text"),
|
||||
background_color: val(post, "author_flair_background_color"),
|
||||
foreground_color: val(post, "author_flair_text_color"),
|
||||
},
|
||||
|
@ -294,7 +294,7 @@ impl Post {
|
|||
data["link_flair_richtext"].as_array(),
|
||||
data["link_flair_text"].as_str(),
|
||||
),
|
||||
text: esc!(post, "link_flair_text"),
|
||||
text: val(post, "link_flair_text"),
|
||||
background_color: val(post, "link_flair_background_color"),
|
||||
foreground_color: if val(post, "link_flair_text_color") == "dark" {
|
||||
"black".to_string()
|
||||
|
@ -320,7 +320,7 @@ impl Post {
|
|||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "comment.html", escape = "none")]
|
||||
#[template(path = "comment.html")]
|
||||
// Comment with content, post, score and data/time that it was posted
|
||||
pub struct Comment {
|
||||
pub id: String,
|
||||
|
@ -396,7 +396,7 @@ impl Awards {
|
|||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "error.html", escape = "none")]
|
||||
#[template(path = "error.html")]
|
||||
pub struct ErrorTemplate {
|
||||
pub msg: String,
|
||||
pub prefs: Preferences,
|
||||
|
@ -678,17 +678,6 @@ pub fn val(j: &Value, k: &str) -> String {
|
|||
j["data"][k].as_str().unwrap_or_default().to_string()
|
||||
}
|
||||
|
||||
// Escape < and > to accurately render HTML
|
||||
#[macro_export]
|
||||
macro_rules! esc {
|
||||
($f:expr) => {
|
||||
$f.replace('&', "&").replace('<', "<").replace('>', ">")
|
||||
};
|
||||
($j:expr, $k:expr) => {
|
||||
$j["data"][$k].as_str().unwrap_or_default().to_string().replace('<', "<").replace('>', ">")
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// NETWORKING
|
||||
//
|
||||
|
|
|
@ -32,9 +32,9 @@
|
|||
{% if is_filtered %}
|
||||
<div class="comment_body_filtered {% if highlighted %}highlighted{% endif %}">(Filtered content)</div>
|
||||
{% else %}
|
||||
<div class="comment_body {% if highlighted %}highlighted{% endif %}">{{ body }}</div>
|
||||
<div class="comment_body {% if highlighted %}highlighted{% endif %}">{{ body|safe }}</div>
|
||||
{% endif %}
|
||||
<blockquote class="replies">{% for c in replies -%}{{ c.render().unwrap() }}{%- endfor %}
|
||||
<blockquote class="replies">{% for c in replies -%}{{ c.render().unwrap()|safe }}{%- endfor %}
|
||||
</blockquote>
|
||||
</details>
|
||||
</div>
|
||||
|
|
|
@ -110,7 +110,7 @@
|
|||
{% endif %}
|
||||
|
||||
<!-- POST BODY -->
|
||||
<div class="post_body">{{ post.body }}</div>
|
||||
<div class="post_body">{{ post.body|safe }}</div>
|
||||
<div class="post_score" title="{{ post.score.1 }}">{{ post.score.0 }}<span class="label"> Upvotes</span></div>
|
||||
<div class="post_footer">
|
||||
<ul id="post_links">
|
||||
|
@ -144,7 +144,7 @@
|
|||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{{ c.render().unwrap() }}
|
||||
{{ c.render().unwrap()|safe }}
|
||||
</div>
|
||||
{%- endfor %}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
{% endif %}
|
||||
{% for subreddit in subreddits %}
|
||||
<a href="{{ subreddit.url }}" class="search_subreddit">
|
||||
<div class="search_subreddit_left">{% if subreddit.icon != "" %}<img loading="lazy" src="{{ subreddit.icon }}" alt="r/{{ subreddit.name }} icon">{% endif %}</div>
|
||||
<div class="search_subreddit_left">{% if subreddit.icon != "" %}<img loading="lazy" src="{{ subreddit.icon|safe }}" alt="r/{{ subreddit.name }} icon">{% endif %}</div>
|
||||
<div class="search_subreddit_right">
|
||||
<p class="search_subreddit_header">
|
||||
<span class="search_subreddit_name">r/{{ subreddit.name }}</span>
|
||||
|
|
|
@ -127,7 +127,7 @@
|
|||
<details class="panel" id="sidebar">
|
||||
<summary id="sidebar_label">Sidebar</summary>
|
||||
<div id="sidebar_contents">
|
||||
{{ sub.info }}
|
||||
{{ sub.info|safe }}
|
||||
{# <hr>
|
||||
<h2>Moderators</h2>
|
||||
<br>
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
<a class="comment_link" href="{{ post.permalink }}">COMMENT</a>
|
||||
<span class="created" title="{{ post.created }}">{{ post.rel_time }}</span>
|
||||
</summary>
|
||||
<p class="comment_body">{{ post.body }}</p>
|
||||
<p class="comment_body">{{ post.body|safe }}</p>
|
||||
</details>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -138,7 +138,7 @@
|
|||
|
||||
<div class="post_score" title="{{ post.score.1 }}">{{ post.score.0 }}<span class="label"> Upvotes</span></div>
|
||||
<div class="post_body post_preview">
|
||||
{{ post.body }}
|
||||
{{ post.body|safe }}
|
||||
</div>
|
||||
<div class="post_footer">
|
||||
<a href="{{ post.permalink }}" class="post_comments" title="{{ post.comments.1 }} comments">{{ post.comments.0 }} comments</a>
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
<div>Wiki</div>
|
||||
</div>
|
||||
<div id="wiki">
|
||||
{{ wiki }}
|
||||
{{ wiki|safe }}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
|
Loading…
Reference in a new issue