Add comment sanitization and markdown rendering

main
Elnu 2 years ago
parent 1bea87f47f
commit 42d980f4cb

57
Cargo.lock generated

@ -701,6 +701,20 @@ dependencies = [
"libc",
]
[[package]]
name = "html5ever"
version = "0.25.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5c13fb08e5d4dfc151ee5e88bae63f7773d61852f3bdc73c9f4b9e1bde03148"
dependencies = [
"log",
"mac",
"markup5ever 0.10.1",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "html5ever"
version = "0.26.0"
@ -709,7 +723,7 @@ checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7"
dependencies = [
"log",
"mac",
"markup5ever",
"markup5ever 0.11.0",
"proc-macro2",
"quote",
"syn",
@ -858,6 +872,18 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "kuchiki"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ea8e9c6e031377cff82ee3001dc8026cdf431ed4e2e6b51f98ab8c73484a358"
dependencies = [
"cssparser",
"html5ever 0.25.2",
"matches",
"selectors",
]
[[package]]
name = "language-tags"
version = "0.3.2"
@ -929,6 +955,20 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
[[package]]
name = "markup5ever"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a24f40fb03852d1cdd84330cddcaf98e9ec08a7b7768e952fad3b4cf048ec8fd"
dependencies = [
"log",
"phf 0.8.0",
"phf_codegen 0.8.0",
"string_cache",
"string_cache_codegen",
"tendril",
]
[[package]]
name = "markup5ever"
version = "0.11.0"
@ -1496,6 +1536,18 @@ version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695"
[[package]]
name = "sanitize_html"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cd7ea46188a5c6961a44b4c25ed280ea85a1e0b6a129f9bbd81bbf87261c52b"
dependencies = [
"html5ever 0.25.2",
"kuchiki",
"lazy_static",
"regex",
]
[[package]]
name = "schannel"
version = "0.1.20"
@ -1521,7 +1573,7 @@ dependencies = [
"cssparser",
"ego-tree",
"getopts",
"html5ever",
"html5ever 0.26.0",
"matches",
"selectors",
"smallvec",
@ -1688,6 +1740,7 @@ dependencies = [
"md5",
"reqwest",
"rusqlite",
"sanitize_html",
"scraper",
"serde",
"serde_json",

@ -21,3 +21,4 @@ md5 = "0.7.0"
chrono = { version = "0.4.19", features = ["serde"] }
reqwest = "0.11.11"
scraper = "0.13.0"
sanitize_html = "0.7.0"

@ -6,4 +6,5 @@
<p>This is Page A.</p>
<div id="soudan"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/markdown-it/13.0.1/markdown-it.min.js" integrity="sha512-SYfDUYPg5xspsG6OOpXU366G8SZsdHOhqk/icdrYJ2E/WKZxPxze7d2HD3AyXpT7U22PZ5y74xRpqZ6A2bJ+kQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="/soudan.js"></script>

@ -6,4 +6,5 @@
<p>This is Page B.</h2>
<div id="soudan"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/markdown-it/13.0.1/markdown-it.min.js" integrity="sha512-SYfDUYPg5xspsG6OOpXU366G8SZsdHOhqk/icdrYJ2E/WKZxPxze7d2HD3AyXpT7U22PZ5y74xRpqZ6A2bJ+kQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="/soudan.js"></script>

@ -9,7 +9,7 @@ document.getElementById("soudan").innerHTML = `<h3>Make a comment</h3>
</form>
<h3 id="soudan-comments-header">Comments</h3>
<div id="soudan-comments"></div>`;
document.write(`<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>`);
const md = window.markdownit().disable("image");
const url = "http://127.0.0.1:8080";
const form = document.getElementById("soudan-comment-form");
const commentContainer = document.getElementById("soudan-comments");
@ -52,7 +52,7 @@ function reloadComments() {
html = "<p>No comments yet! Be the first to make one.</p>";
} else {
comments.forEach(comment => {
html += `<div><img class="soudan-avatar" src="https://www.gravatar.com/avatar/${comment.gravatar}"><div><b>${comment.author ? comment.author : "Anonymous"}</b> commented ${moment(new Date(comment.timestamp * 1000)).fromNow()}:<br><div>${comment.text}</div></div></div>`;
html += `<div><img class="soudan-avatar" src="https://www.gravatar.com/avatar/${comment.gravatar}"><div><b>${comment.author ? comment.author : "Anonymous"}</b> commented ${moment(new Date(comment.timestamp * 1000)).fromNow()}:<br><div>${md.render(comment.text)}</div></div></div>`;
});
}
commentContainer.innerHTML = html;

@ -14,6 +14,7 @@ use std::{
sync::{Mutex, MutexGuard},
};
use validator::Validate;
use sanitize_html::{sanitize_str, rules::predefined::DEFAULT, errors::SanitizeError};
struct AppState {
databases: HashMap<String, Mutex<Database>>,
@ -66,8 +67,21 @@ async fn post_comment(
) -> impl Responder {
match String::from_utf8(bytes.to_vec()) {
Ok(text) => {
let PostCommentsRequest { url, comment } = match serde_json::from_str(&text) {
Ok(req) => req,
let PostCommentsRequest { url, comment } = match serde_json::from_str::<PostCommentsRequest>(&text) {
Ok(mut req) => {
let mut sanitize_req = || -> Result<(), SanitizeError> {
req.comment.text = sanitize_str(&DEFAULT, &req.comment.text)?
.replace("&gt;", ">"); // required for markdown quotes
if let Some(ref mut author) = req.comment.author {
*author = sanitize_str(&DEFAULT, &author)?;
}
Ok(())
};
if let Err(_) = sanitize_req() {
return HttpResponse::InternalServerError().reason("failed to sanitize request").finish();
}
req
}
Err(_) => return HttpResponse::BadRequest().reason("invalid request body").finish(),
};
if comment.validate().is_err() {

Loading…
Cancel
Save