diff --git a/lib/philomena_web/markdown_renderer.ex b/lib/philomena_web/markdown_renderer.ex index 7caff5c9..0b108008 100644 --- a/lib/philomena_web/markdown_renderer.ex +++ b/lib/philomena_web/markdown_renderer.ex @@ -75,8 +75,7 @@ defmodule PhilomenaWeb.MarkdownRenderer do defp render_representations(images, conn) do loaded_images = load_images(images) - images - |> Enum.map(fn group -> + Map.new(images, fn group -> img = loaded_images[Enum.at(group, 0)] text = "#{Enum.at(group, 0)}#{Enum.at(group, 1)}" @@ -131,8 +130,7 @@ defmodule PhilomenaWeb.MarkdownRenderer do |> Phoenix.HTML.Safe.to_iodata() |> IO.iodata_to_binary() - [text, string_contents] + {text, string_contents} end) - |> Map.new(fn [id, html] -> {id, html} end) end end diff --git a/native/philomena/Cargo.lock b/native/philomena/Cargo.lock index 0ca74719..495a6815 100644 --- a/native/philomena/Cargo.lock +++ b/native/philomena/Cargo.lock @@ -260,7 +260,9 @@ version = "0.3.0" dependencies = [ "base64", "comrak", + "http", "jemallocator", + "regex", "ring", "rustler", "url", diff --git a/native/philomena/Cargo.toml b/native/philomena/Cargo.toml index 942d39bc..20cb3b9b 100644 --- a/native/philomena/Cargo.toml +++ b/native/philomena/Cargo.toml @@ -10,11 +10,13 @@ path = "src/lib.rs" crate-type = ["dylib"] [dependencies] -comrak = { git = "https://github.com/philomena-dev/comrak", branch = "main", default-features = false } -jemallocator = { version = "0.5.0", features = ["disable_initial_exec_tls"] } -rustler = "0.28" -ring = "0.16" base64 = "0.21" +comrak = { git = "https://github.com/philomena-dev/comrak", branch = "main", default-features = false } +http = "0.2" +jemallocator = { version = "0.5.0", features = ["disable_initial_exec_tls"] } +regex = "1" +ring = "0.16" +rustler = "0.28" url = "2.3" [profile.release] diff --git a/native/philomena/src/camo.rs b/native/philomena/src/camo.rs index df47a2e8..c79f12e1 100644 --- a/native/philomena/src/camo.rs +++ b/native/philomena/src/camo.rs @@ -11,7 +11,7 @@ fn trusted_host(mut url: Url) -> Option { Some(url.to_string()) } -fn untrusted_host(url: Url, camo_host: String, camo_key: String) -> Option { +fn untrusted_host(url: Url, camo_host: &str, camo_key: &str) -> Option { let camo_url = format!("https://{}", camo_host); let key = hmac::Key::new(hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY, camo_key.as_ref()); let tag = hmac::sign(&key, url.to_string().as_bytes()); @@ -27,20 +27,24 @@ fn untrusted_host(url: Url, camo_host: String, camo_key: String) -> Option Option { +pub fn image_url(uri: &str) -> Option { let cdn_host = env::var("CDN_HOST").ok()?; - let camo_host = env::var("CAMO_HOST").unwrap_or_else(|_| String::from("")); - let camo_key = env::var("CAMO_KEY").unwrap_or_else(|_| String::from("")); + let camo_host = env::var("CAMO_HOST").unwrap_or_else(|_| "".into()); + let camo_key = env::var("CAMO_KEY").unwrap_or_else(|_| "".into()); if camo_key.is_empty() { - return Some(uri); + return Some(uri.into()); } - let url = Url::parse(&uri).ok()?; + let url = Url::parse(uri).ok()?; match url.host_str() { Some(hostname) if hostname == cdn_host || hostname == camo_host => trusted_host(url), - Some(_) => untrusted_host(url, camo_host, camo_key), - None => Some(String::from("")), + Some(_) => untrusted_host(url, &camo_host, &camo_key), + None => Some("".into()), } } + +pub fn image_url_careful(uri: &str) -> String { + image_url(uri).unwrap_or_else(|| "".into()) +} diff --git a/native/philomena/src/domains.rs b/native/philomena/src/domains.rs new file mode 100644 index 00000000..c90ddb6f --- /dev/null +++ b/native/philomena/src/domains.rs @@ -0,0 +1,14 @@ +use std::env; + +pub fn get() -> Option> { + if let Ok(domains) = env::var("SITE_DOMAINS") { + return Some( + domains + .split(',') + .map(|s| s.to_string()) + .collect::>(), + ); + } + + None +} diff --git a/native/philomena/src/lib.rs b/native/philomena/src/lib.rs index f5317aa3..bcbadcb6 100644 --- a/native/philomena/src/lib.rs +++ b/native/philomena/src/lib.rs @@ -1,7 +1,8 @@ use jemallocator::Jemalloc; -use rustler::Term; +use std::collections::HashMap; mod camo; +mod domains; mod markdown; #[global_allocator] @@ -15,18 +16,18 @@ rustler::init! { // Markdown NIF wrappers. #[rustler::nif(schedule = "DirtyCpu")] -fn markdown_to_html(input: String, reps: Term) -> String { +fn markdown_to_html(input: &str, reps: HashMap) -> String { markdown::to_html(input, reps) } #[rustler::nif(schedule = "DirtyCpu")] -fn markdown_to_html_unsafe(input: String, reps: Term) -> String { +fn markdown_to_html_unsafe(input: &str, reps: HashMap) -> String { markdown::to_html_unsafe(input, reps) } // Camo NIF wrappers. #[rustler::nif] -fn camo_image_url(input: String) -> String { - camo::image_url(input).unwrap_or_else(|| String::from("")) +fn camo_image_url(input: &str) -> String { + camo::image_url_careful(input) } diff --git a/native/philomena/src/markdown.rs b/native/philomena/src/markdown.rs index c92e6a0f..a927a6e5 100644 --- a/native/philomena/src/markdown.rs +++ b/native/philomena/src/markdown.rs @@ -1,11 +1,9 @@ -use crate::camo; -use comrak::ComrakOptions; -use rustler::{MapIterator, Term}; +use crate::{camo, domains}; +use comrak::Options; use std::collections::HashMap; -use std::env; -fn common_options() -> ComrakOptions { - let mut options = ComrakOptions::default(); +fn common_options() -> Options { + let mut options = Options::default(); options.extension.autolink = true; options.extension.table = true; options.extension.description_lists = true; @@ -16,47 +14,24 @@ fn common_options() -> ComrakOptions { options.render.hardbreaks = true; options.render.github_pre_lang = true; - options.extension.camoifier = Some(|s| camo::image_url(s).unwrap_or_else(|| String::from(""))); - - if let Ok(domains) = env::var("SITE_DOMAINS") { - options.extension.philomena_domains = Some( - domains - .split(',') - .map(|s| s.to_string()) - .collect::>(), - ); - } + options.extension.camoifier = Some(|s| camo::image_url_careful(&s)); + options.extension.philomena_domains = domains::get(); options } -fn map_to_hashmap(map: Term) -> Option> { - Some( - MapIterator::new(map)? - .map(|(key, value)| { - let key: String = key.decode().unwrap_or_else(|_| String::from("")); - let value: String = value.decode().unwrap_or_else(|_| String::from("")); - - (key, value) - }) - .collect(), - ) -} - -pub fn to_html(input: String, reps: Term) -> String { +pub fn to_html(input: &str, reps: HashMap) -> String { let mut options = common_options(); options.render.escape = true; + options.extension.philomena_replacements = Some(reps); - options.extension.philomena_replacements = map_to_hashmap(reps); - - comrak::markdown_to_html(&input, &options) + comrak::markdown_to_html(input, &options) } -pub fn to_html_unsafe(input: String, reps: Term) -> String { +pub fn to_html_unsafe(input: &str, reps: HashMap) -> String { let mut options = common_options(); options.render.unsafe_ = true; + options.extension.philomena_replacements = Some(reps); - options.extension.philomena_replacements = map_to_hashmap(reps); - - comrak::markdown_to_html(&input, &options) + comrak::markdown_to_html(input, &options) }