From 4173362ce1d7f41c3889fba7d049a719476a5d93 Mon Sep 17 00:00:00 2001 From: spikecodes <19519553+spikecodes@users.noreply.github.com> Date: Thu, 11 Mar 2021 20:15:26 -0800 Subject: [PATCH] Fix #148 --- Cargo.toml | 4 ++-- src/post.rs | 9 +++++---- src/subreddit.rs | 7 ++++--- src/user.rs | 7 ++++--- src/utils.rs | 30 ++++++++++++++++++++++++++---- 5 files changed, 41 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e2359f8..f0e039d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "libreddit" description = " Alternative private front-end to Reddit" license = "AGPL-3.0" repository = "https://github.com/spikecodes/libreddit" -version = "0.4.0" +version = "0.4.1" authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"] edition = "2018" @@ -14,7 +14,7 @@ async-std = { version = "1.9.0", features = ["attributes"] } async-tls = { version = "0.11.0", default-features = false, features = ["client"] } cached = "0.23.0" clap = { version = "2.33.3", default-features = false } -regex = "1.4.3" +regex = "1.4.4" serde = { version = "1.0.124", features = ["derive"] } serde_json = "1.0.64" tide = { version = "0.16.0", default-features = false, features = ["h1-server", "cookies"] } diff --git a/src/post.rs b/src/post.rs index a4f325e..87998d7 100644 --- a/src/post.rs +++ b/src/post.rs @@ -1,4 +1,5 @@ // CRATES +use crate::esc; use crate::utils::{ cookie, error, format_num, format_url, param, request, rewrite_urls, template, time, val, Author, Comment, Flags, Flair, FlairPart, Media, Post, Preferences, }; @@ -81,7 +82,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: val(post, "title"), + title: esc!(post, "title"), community: val(post, "subreddit"), body: rewrite_urls(&val(post, "selftext_html")).replace("\\", ""), author: Author { @@ -92,7 +93,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: val(post, "link_flair_text"), + text: esc!(post, "link_flair_text"), background_color: val(post, "author_flair_background_color"), foreground_color: val(post, "author_flair_text_color"), }, @@ -115,7 +116,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: val(post, "link_flair_text"), + text: esc!(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() @@ -191,7 +192,7 @@ async fn parse_comments(json: &serde_json::Value, post_link: &str, post_author: data["author_flair_richtext"].as_array(), data["author_flair_text"].as_str(), ), - text: val(&comment, "link_flair_text"), + text: esc!(&comment, "link_flair_text"), background_color: val(&comment, "author_flair_background_color"), foreground_color: val(&comment, "author_flair_text_color"), }, diff --git a/src/subreddit.rs b/src/subreddit.rs index aab3b67..fe464bd 100644 --- a/src/subreddit.rs +++ b/src/subreddit.rs @@ -1,4 +1,5 @@ // CRATES +use crate::esc; use crate::utils::{cookie, error, format_num, format_url, param, redirect, request, rewrite_urls, template, val, Post, Preferences, Subreddit}; use askama::Template; use tide::{http::Cookie, Request}; @@ -167,9 +168,9 @@ async fn subreddit(sub: &str) -> Result { let icon = if community_icon.is_empty() { val(&res, "icon_img") } else { community_icon.to_string() }; let sub = Subreddit { - name: val(&res, "display_name"), - title: val(&res, "title"), - description: val(&res, "public_description"), + name: esc!(&res, "display_name"), + title: esc!(&res, "title"), + description: esc!(&res, "public_description"), info: rewrite_urls(&val(&res, "description_html").replace("\\", "")), icon: format_url(&icon), members: format_num(members), diff --git a/src/user.rs b/src/user.rs index 28a50d1..47fa0c3 100644 --- a/src/user.rs +++ b/src/user.rs @@ -1,4 +1,5 @@ // CRATES +use crate::esc; use crate::utils::{error, format_url, param, request, template, Post, Preferences, User}; use askama::Template; use tide::Request; @@ -57,17 +58,17 @@ async fn user(name: &str) -> Result { // Grab creation date as unix timestamp let created: i64 = res["data"]["created"].as_f64().unwrap_or(0.0).round() as i64; - // nested_val function used to parse JSON from Reddit APIs + // Closure used to parse JSON from Reddit APIs let about = |item| res["data"]["subreddit"][item].as_str().unwrap_or_default().to_string(); // Parse the JSON output into a User struct Ok(User { name: name.to_string(), - title: about("title"), + title: esc!(about("title")), icon: format_url(&about("icon_img")), karma: res["data"]["total_karma"].as_i64().unwrap_or(0), created: OffsetDateTime::from_unix_timestamp(created).format("%b %d '%y"), - banner: about("banner_img"), + banner: esc!(about("banner_img")), description: about("public_description"), }) } diff --git a/src/utils.rs b/src/utils.rs index b8cc495..42ef14b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,6 +1,7 @@ // // CRATES // +use crate::esc; use askama::Template; use async_recursion::async_recursion; use async_std::{io, net::TcpStream, prelude::*}; @@ -227,14 +228,14 @@ 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 = val(post, "title"); + let title = esc!(post, "title"); // Determine the type of media along with the media URL let (post_type, media, gallery) = Media::parse(&data).await; posts.push(Self { id: val(post, "id"), - title: if title.is_empty() { fallback_title.to_owned() } else { title }, + title: esc!(if title.is_empty() { fallback_title.to_owned() } else { title }), community: val(post, "subreddit"), body: rewrite_urls(&val(post, "body_html")), author: Author { @@ -245,7 +246,7 @@ impl Post { data["author_flair_richtext"].as_array(), data["author_flair_text"].as_str(), ), - text: val(post, "link_flair_text"), + text: esc!(post, "link_flair_text"), background_color: val(post, "author_flair_background_color"), foreground_color: val(post, "author_flair_text_color"), }, @@ -272,7 +273,7 @@ impl Post { data["link_flair_richtext"].as_array(), data["link_flair_text"].as_str(), ), - text: val(post, "link_flair_text"), + text: esc!(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() @@ -486,6 +487,27 @@ pub fn val(j: &Value, k: &str) -> String { j["data"][k].as_str().unwrap_or_default().to_string() } +#[macro_export] +macro_rules! esc { + ($f:expr) => { + $f.replace('<', "<").replace('>', ">") + }; + ($j:expr, $k:expr) => { + $j["data"][$k].as_str().unwrap_or_default().to_string().replace('<', "<").replace('>', ">") + }; +} + +// Escape < and > to accurately render HTML +// pub fn esc(j: &Value, k: &str) -> String { +// val(j,k) +// // .replace('&', "&") +// .replace('<', "<") +// .replace('>', ">") +// // .replace('"', """) +// // .replace('\'', "'") +// // .replace('/', "/") +// } + // // NETWORKING //