diff --git a/public/styles/asn1/node.scss b/public/styles/asn1/node.scss index 8b0b4c54..dfc2b38d 100644 --- a/public/styles/asn1/node.scss +++ b/public/styles/asn1/node.scss @@ -4,7 +4,7 @@ gap: 0.2em; align-items: center; cursor: crosshair; - width: 100%; + width: calc(100% - 0.5em); } .asn1-constructor-header { @@ -37,6 +37,7 @@ background-color: #aab7ce; font-size: 0.7em; overflow: hidden; + text-overflow: ellipsis; } .asn-bool-true { diff --git a/public/styles/asn1/page.scss b/public/styles/asn1/page.scss index 564e3301..3e044724 100644 --- a/public/styles/asn1/page.scss +++ b/public/styles/asn1/page.scss @@ -8,6 +8,6 @@ .asn1-viewers { display: grid; grid-template-columns: 70% auto; - gap: 0.1em; + gap: 0.7em; width: 100%; } \ No newline at end of file diff --git a/src/asn1.rs b/src/asn1.rs index c4c1fc72..88e10660 100644 --- a/src/asn1.rs +++ b/src/asn1.rs @@ -10,12 +10,15 @@ use std::rc::Rc; use asn1_parser::{Asn1, Asn1Decoder}; use web_sys::KeyboardEvent; -use yew::{classes, function_component, html, use_reducer, use_state, Callback, Html, Reducible}; +use yew::{classes, function_component, html, use_effect_with_deps, use_reducer, use_state, Callback, Html, Reducible}; +use yew_hooks::{use_clipboard, use_location}; use yew_notifications::{use_notification, Notification, NotificationType}; use crate::asn1::asn1_viewer::Asn1Viewer; use crate::asn1::hex_view::HexViewer; use crate::common::ByteInput; +use crate::url_query_params; +use crate::url_query_params::generate_asn1_link; pub const TEST_ASN1: &[u8] = &[ 48, 87, 1, 1, 255, 1, 1, 0, 160, 17, 12, 15, 84, 98, 101, 66, 101, 115, 116, 84, 118, 97, 114, 121, 110, 107, 97, @@ -70,6 +73,8 @@ impl Reducible for Highlight { #[function_component(Asn1ParserPage)] pub fn asn1_parser_page() -> Html { + let notification_manager = use_notification::(); + let raw_asn1 = use_state(|| TEST_ASN1.to_vec()); let parsed_asn1 = use_state(|| Asn1::decode_buff(TEST_ASN1).unwrap()); @@ -100,6 +105,57 @@ pub fn asn1_parser_page() -> Html { parse_asn1.emit(()); }); + let location = use_location(); + let notifications = notification_manager.clone(); + let raw_asn1_setter = raw_asn1.setter(); + let asn1_setter = parsed_asn1.setter(); + use_effect_with_deps( + move |_: &[(); 0]| { + let query = &location.search; + + if query.len() < 2 { + return; + } + + match serde_qs::from_str(&query[1..]) { + Ok(asn1) => { + let url_query_params::Asn1 { asn1: asn1_data } = asn1; + match Asn1::decode_buff(&asn1_data) { + Ok(asn1) => { + log::debug!("parsed!"); + asn1_setter.set(asn1.to_owned_with_asn1(asn1.inner_asn1().to_owned())); + } + Err(error) => notifications.spawn(Notification::new( + NotificationType::Error, + "Invalid asn1 data", + error.message(), + Notification::NOTIFICATION_LIFETIME, + )), + }; + raw_asn1_setter.set(asn1_data); + } + Err(err) => notifications.spawn(Notification::new( + NotificationType::Error, + "Can not load data from url", + err.to_string(), + Notification::NOTIFICATION_LIFETIME, + )), + } + }, + [], + ); + + let clipboard = use_clipboard(); + let raw_asn1_data = (*raw_asn1).clone(); + let share_by_link = Callback::from(move |_| { + clipboard.write_text(generate_asn1_link(raw_asn1_data.clone())); + + notification_manager.spawn(Notification::from_description_and_type( + NotificationType::Info, + "link copied", + )); + }); + let raw_asn1_setter = raw_asn1.setter(); let ctx = use_reducer(Highlight::default); @@ -119,6 +175,9 @@ pub fn asn1_parser_page() -> Html {
{"(ctrl+enter)"} +
default_bytes(asn1_node_id, cur_node, set_cur_node, asn1, bytes, select_all), Asn1Type::UtcTime(_) => default_bytes(asn1_node_id, cur_node, set_cur_node, asn1, bytes, select_all), Asn1Type::GeneralizedTime(_) => default_bytes(asn1_node_id, cur_node, set_cur_node, asn1, bytes, select_all), - Asn1Type::BitString(_) => default_bytes(asn1_node_id, cur_node, set_cur_node, asn1, bytes, select_all), + Asn1Type::BitString(bit) => match bit.inner() { + Some(asn1) => build_hex_bytes(asn1, cur_node, set_cur_node.clone(), bytes, select_all), + None => default_bytes(asn1_node_id, cur_node, set_cur_node, asn1, bytes, select_all), + }, Asn1Type::BmpString(_) => default_bytes(asn1_node_id, cur_node, set_cur_node, asn1, bytes, select_all), Asn1Type::Bool(_) => default_bytes(asn1_node_id, cur_node, set_cur_node, asn1, bytes, select_all), Asn1Type::Null(_) => default_bytes(asn1_node_id, cur_node, set_cur_node, asn1, bytes, select_all), diff --git a/src/asn1/scheme/strings.rs b/src/asn1/scheme/strings.rs index f9cdd169..51fcea8b 100644 --- a/src/asn1/scheme/strings.rs +++ b/src/asn1/scheme/strings.rs @@ -26,7 +26,7 @@ pub fn octet_string(props: &OctetStringNodeProps) -> Html { match props.node.inner() { Some(asn1) => html! { -
+
{format!("({} bytes)", octets.len())} @@ -77,7 +77,7 @@ pub fn bit_string(props: &BitStringNodeProps) -> Html { match props.node.inner() { Some(asn1) => html! { -
+
{format!("({} bits)", bits_amount)} diff --git a/src/crypto_helper.rs b/src/crypto_helper.rs index c624cfdf..c4879b5c 100644 --- a/src/crypto_helper.rs +++ b/src/crypto_helper.rs @@ -4,7 +4,7 @@ mod info; mod input; mod macros; mod output; -mod serde; +pub mod serde; pub use algorithm::Algorithm; use info::Info; diff --git a/src/url_query_params.rs b/src/url_query_params.rs index 5e114e0b..7d7d6df6 100644 --- a/src/url_query_params.rs +++ b/src/url_query_params.rs @@ -1,5 +1,6 @@ use serde::{Deserialize, Serialize}; +use crate::crypto_helper::serde::{deserialize_bytes, serialize_bytes}; use crate::crypto_helper::Algorithm; const APP_HOST: &str = env!("APP_HOST"); @@ -26,3 +27,18 @@ pub fn generate_jwt_link(jwt: String) -> String { link } + +#[derive(Serialize, Deserialize)] +pub struct Asn1 { + #[serde(serialize_with = "serialize_bytes", deserialize_with = "deserialize_bytes")] + pub asn1: Vec, +} + +pub fn generate_asn1_link(asn1: Vec) -> String { + let mut link = APP_HOST.to_string(); + + link.push_str("/asn1/?"); + link.push_str(&serde_qs::to_string(&Asn1 { asn1 }).unwrap()); + + link +}