our own message html processing to open links in new tab

This commit is contained in:
2025-02-11 23:17:39 -07:00
parent 0b928c171f
commit 0462340694
5 changed files with 220 additions and 11 deletions
Generated
+104 -8
View File
@@ -79,6 +79,12 @@ dependencies = [
"memchr",
]
[[package]]
name = "allocator-api2"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "alsa"
version = "0.9.1"
@@ -990,6 +996,23 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "cssparser"
version = "0.29.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa"
dependencies = [
"cssparser-macros",
"dtoa-short",
"itoa 1.0.11",
"matches",
"phf 0.10.1",
"proc-macro2",
"quote",
"smallvec",
"syn 1.0.109",
]
[[package]]
name = "cssparser-macros"
version = "0.6.1"
@@ -1772,6 +1795,12 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foldhash"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
[[package]]
name = "foreign-types"
version = "0.3.2"
@@ -2375,6 +2404,11 @@ name = "hashbrown"
version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3"
dependencies = [
"allocator-api2",
"equivalent",
"foldhash",
]
[[package]]
name = "headers"
@@ -2460,7 +2494,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29a4ec546a9a7e86b30ddc62c55f78055d7533cb617139ece68881e35cbc56e8"
dependencies = [
"lol_html",
"lol_html 1.2.1",
]
[[package]]
@@ -2918,11 +2952,11 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f29e4755b7b995046f510a7520c42b2fed58b77bd94d5a87a8eb43d2fd126da8"
dependencies = [
"cssparser",
"cssparser 0.27.2",
"html5ever",
"indexmap 1.9.3",
"matches",
"selectors",
"selectors 0.22.0",
]
[[package]]
@@ -3067,17 +3101,34 @@ checksum = "a4629ff9c2deeb7aad9b2d0f379fc41937a02f3b739f007732c46af40339dee5"
dependencies = [
"bitflags 2.6.0",
"cfg-if",
"cssparser",
"cssparser 0.27.2",
"encoding_rs",
"hashbrown 0.13.2",
"lazy_static",
"lazycell",
"memchr",
"mime",
"selectors",
"selectors 0.22.0",
"thiserror 1.0.69",
]
[[package]]
name = "lol_html"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b1058123f6262982b891dccc395cff0144d9439de366460b47fab719258b96e"
dependencies = [
"bitflags 2.6.0",
"cfg-if",
"cssparser 0.29.6",
"encoding_rs",
"hashbrown 0.15.1",
"memchr",
"mime",
"selectors 0.24.0",
"thiserror 2.0.3",
]
[[package]]
name = "longest-increasing-subsequence"
version = "0.1.0"
@@ -3380,6 +3431,7 @@ dependencies = [
"gloo-timers",
"html-purifier",
"js-sys",
"lol_html 2.2.0",
"markdown",
"merge-io",
"mumble-protocol-2x",
@@ -3998,7 +4050,7 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
dependencies = [
"phf_macros",
"phf_macros 0.8.0",
"phf_shared 0.8.0",
"proc-macro-hack",
]
@@ -4009,7 +4061,9 @@ version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259"
dependencies = [
"phf_macros 0.10.0",
"phf_shared 0.10.0",
"proc-macro-hack",
]
[[package]]
@@ -4066,6 +4120,20 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "phf_macros"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0"
dependencies = [
"phf_generator 0.10.0",
"phf_shared 0.10.0",
"proc-macro-hack",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "phf_shared"
version = "0.8.0"
@@ -5021,7 +5089,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe"
dependencies = [
"bitflags 1.3.2",
"cssparser",
"cssparser 0.27.2",
"derive_more",
"fxhash",
"log",
@@ -5029,11 +5097,29 @@ dependencies = [
"phf 0.8.0",
"phf_codegen 0.8.0",
"precomputed-hash",
"servo_arc",
"servo_arc 0.1.1",
"smallvec",
"thin-slice",
]
[[package]]
name = "selectors"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c37578180969d00692904465fb7f6b3d50b9a2b952b87c23d0e2e5cb5013416"
dependencies = [
"bitflags 1.3.2",
"cssparser 0.29.6",
"derive_more",
"fxhash",
"log",
"phf 0.8.0",
"phf_codegen 0.8.0",
"precomputed-hash",
"servo_arc 0.2.0",
"smallvec",
]
[[package]]
name = "semver"
version = "1.0.23"
@@ -5221,6 +5307,16 @@ dependencies = [
"stable_deref_trait",
]
[[package]]
name = "servo_arc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d52aa42f8fdf0fed91e5ce7f23d8138441002fa31dca008acf47e6fd4721f741"
dependencies = [
"nodrop",
"stable_deref_trait",
]
[[package]]
name = "sha1"
version = "0.10.6"
+1
View File
@@ -89,6 +89,7 @@ tracing-subscriber = { version = "0.3.18", features = ["ansi"] }
tracing = "0.1.40"
color-eyre = "0.6.3"
crossbeam-queue = "0.3.11"
lol_html = "2.2.0"
[features]
web = [
+1 -1
View File
@@ -212,9 +212,9 @@ pub fn Channel(id: ChannelId) -> Element {
summary {
span {
role: "button",
prevent_default: "onclick",
ondoubleclick: move |evt| {
evt.stop_propagation();
evt.prevent_default();
net.send(EnterChannel { channel: id, user })
},
"{state.name}"
+4 -2
View File
@@ -12,6 +12,7 @@ use futures::SinkExt as _;
use futures::StreamExt as _;
use futures_channel::mpsc::UnboundedSender;
pub use imp::spawn;
use msghtml::process_message_html;
use mumble_protocol::control::msgs;
use mumble_protocol::control::ControlCodec;
use mumble_protocol::control::ControlPacket;
@@ -30,6 +31,7 @@ use tracing::info;
pub mod app;
pub mod imp;
mod msghtml;
pub static CONFIG: Lazy<GuiConfig> = Lazy::new(|| imp::load_config().unwrap_or_default());
@@ -375,7 +377,7 @@ fn accept_packet(
} else {
None
},
dangerous_html: html_purifier::purifier(&text, Default::default()),
dangerous_html: process_message_html(&text),
raw: text,
});
}
@@ -387,7 +389,7 @@ fn accept_packet(
let text = u.get_welcome_text().to_string();
server.chat.push(Chat {
sender: None,
dangerous_html: html_purifier::purifier(&text, Default::default()),
dangerous_html: process_message_html(&text),
raw: text,
});
}
+110
View File
@@ -0,0 +1,110 @@
// This is a fork of https://github.com/mehmetcansahin/html-purifier
use lol_html::html_content::{Comment, Element};
use lol_html::{comments, element, rewrite_str, RewriteStrSettings};
pub struct AllowedElement {
pub name: &'static str,
pub attributes: &'static [&'static str],
}
const ALLOWED: &'static [AllowedElement] = &[
AllowedElement {
name: "div",
attributes: &[],
},
AllowedElement {
name: "b",
attributes: &[],
},
AllowedElement {
name: "strong",
attributes: &[],
},
AllowedElement {
name: "i",
attributes: &[],
},
AllowedElement {
name: "em",
attributes: &[],
},
AllowedElement {
name: "u",
attributes: &[],
},
AllowedElement {
name: "a",
attributes: &["href", "title"],
},
AllowedElement {
name: "ul",
attributes: &[],
},
AllowedElement {
name: "ol",
attributes: &[],
},
AllowedElement {
name: "li",
attributes: &[],
},
AllowedElement {
name: "p",
attributes: &["style"],
},
AllowedElement {
name: "br",
attributes: &[],
},
AllowedElement {
name: "span",
attributes: &["style"],
},
AllowedElement {
name: "img",
attributes: &["width", "height", "alt", "src"],
},
];
pub fn process_message_html(input: &str) -> String {
let element_handler = |el: &mut Element| {
let find = ALLOWED.iter().find(|e| e.name.eq(&el.tag_name()));
match find {
Some(find) => {
let remove_attributes = el
.attributes()
.iter()
.filter(|e| find.attributes.iter().any(|a| a.eq(&e.name())) == false)
.map(|m| m.name())
.collect::<Vec<String>>();
for attr in remove_attributes {
el.remove_attribute(&attr);
}
}
None => {
el.remove_and_keep_content();
}
}
if el.tag_name() == "a" {
el.set_attribute("target", "_blank");
}
Ok(())
};
let comment_handler = |c: &mut Comment| {
c.remove();
Ok(())
};
let output = rewrite_str(
input,
RewriteStrSettings {
element_content_handlers: vec![
element!("*", element_handler),
comments!("*", comment_handler),
],
..RewriteStrSettings::default()
},
)
.unwrap();
return output;
}