Skip to content

Commit

Permalink
feat(crypto-helper): asn1: implement node options, improve styling, b…
Browse files Browse the repository at this point in the history
…ehavious, etc
  • Loading branch information
TheBestTvarynka committed Dec 7, 2023
1 parent cb00d0f commit 1a2ea9f
Show file tree
Hide file tree
Showing 10 changed files with 148 additions and 47 deletions.
40 changes: 30 additions & 10 deletions public/styles/asn1/node.scss
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@

.terminal-asn1-node {
display: inline-flex;
gap: 0.5em;
gap: 0.2em;
align-items: center;
cursor: crosshair;
}

.asn1-constructor-header {
display: inline-flex;
gap: 0.5em;
gap: 0.2em;
}

.asn1-constructor-body {
display: flex;
flex-direction: column;
justify-content: center;
gap: 0.1em;
gap: 0;

padding-left: 1.5em;
border-left: 2px solid #70a66c;
Expand All @@ -37,18 +37,20 @@

.asn-bool-true {
border: none;
border-radius: 0.2em;
padding: 0.2em;
border-radius: 0.1em;
padding: 0.1em 0.2em 0.1em 0.2em;
background-color: #0e7e4a;
color: #e1da97;
font-size: 0.9em;
}

.asn-bool-false {
border: none;
border-radius: 0.2em;
padding: 0.2em;
border-radius: 0.1em;
padding: 0.1em 0.2em 0.1em 0.2em;
background-color: #ba0021;
color: #f5bdb6;
font-size: 0.9em;
}

.hover_node {
Expand Down Expand Up @@ -79,21 +81,39 @@
}

.asn1-node-options-container {

height: 80%;
//position: absolute;
//top: 0;
//right: 0.3em;
}

.asn1-node-options {
display: flex;
flex-direction: column;
justify-content: flex-start;
gap: 0.3em;
font-size: 0.8em;
width: max-content;
position: absolute;
left: 0;
bottom: 0.5em;
bottom: 0;

background: #dbcfbf;
color: #50437f;
padding: 0.3em;
border: 2px solid transparent;
padding: 0.5em;
border-radius: 0.3em;
transition: all 0.4s;
}

.asn1-node-options:hover {
border: 2px solid #94897b;
}

.asn1-node-container {
display: inline-flex;
}

.asn1-node-options-name {
cursor: pointer;
}
2 changes: 1 addition & 1 deletion public/styles/jwt.scss
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
}

.jwt-util-button {
font-size: 0.7em;
font-size: 0.9em;
color: #e0e0e0;
background-color: #403735;
padding: 0.2em 0.4em 0.2em 0.4em;
Expand Down
4 changes: 4 additions & 0 deletions src/asn1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ pub const TEST_ASN1: &[u8] = &[
156, 243, 148, 132, 139, 241, 150, 160, 154, 241, 169, 185, 175, 226, 128, 174, 226, 128, 174, 0, 70, 45,
];

pub fn compare_ids(asn1_node_id: u64, cur_node: &Option<u64>) -> bool {
matches!(cur_node, Some(node_id) if *node_id == asn1_node_id)
}

pub enum HighlightAction {
Show(u64),
Hide(u64),
Expand Down
6 changes: 1 addition & 5 deletions src/asn1/hex_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use web_sys::MouseEvent;
use yew::virtual_dom::VNode;
use yew::{classes, function_component, html, Callback, Classes, Html, Properties};

use crate::asn1::HighlightAction;
use crate::asn1::{compare_ids, HighlightAction};

#[derive(PartialEq, Properties, Clone)]
pub struct HexViewerProps {
Expand Down Expand Up @@ -48,10 +48,6 @@ fn format_bytes(
});
}

fn compare_ids(asn1_node_id: u64, cur_node: &Option<u64>) -> bool {
matches!(cur_node, Some(node_id) if *node_id == asn1_node_id)
}

fn build_hex_bytes(
raw: &[u8],
asn1: &Asn1<'_>,
Expand Down
44 changes: 39 additions & 5 deletions src/asn1/node_options.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
use yew::{function_component, html, use_state, Callback, Html, Properties};
use yew_hooks::use_clipboard;
use yew_notifications::{use_notification, Notification, NotificationType};

#[derive(PartialEq, Properties, Clone)]
pub struct NodeOptionsProps {
pub name: String,
pub node_bytes: Vec<u8>,
pub offset: usize,
pub length_len: usize,
pub data_len: usize,
Expand All @@ -13,24 +17,54 @@ pub fn node_options(props: &NodeOptionsProps) -> Html {

let flag = *show_options;
let show_options_setter = show_options.setter();

let onclick = Callback::from(move |_| {
show_options_setter.set(!flag);
});

let show_options_setter = show_options.setter();
let onmouseleave = Callback::from(move |_| {
show_options_setter.set(false);
});

let clipboard = use_clipboard();
let notifications = use_notification::<Notification>();
let value_raw = props.node_bytes[props.length_len + 1..].to_vec();
let copy_value = Callback::from(move |_| {
clipboard.write_text(hex::encode(&value_raw));

notifications.spawn(Notification::from_description_and_type(
NotificationType::Info,
"Value data copied.",
));
});

let clipboard = use_clipboard();
let notifications = use_notification::<Notification>();
let node_raw = props.node_bytes.clone();
let copy_node = Callback::from(move |_| {
clipboard.write_text(hex::encode(&node_raw));

notifications.spawn(Notification::from_description_and_type(
NotificationType::Info,
"Node data copied.",
));
});

html! {
<div class="asn1-node-options-container">
{if *show_options {html! {
<div style="position: relative">
<div class="asn1-node-options">
<div class="asn1-node-options" {onmouseleave}>
<span>{format!("Offset: {}", props.offset)}</span>
<span>{format!("Length: {}+{}", props.length_len, props.data_len)}</span>
<div class="horizontal">
<button class="jwt-util-button" onclick={copy_value}>{"Value hex"}</button>
<button class="jwt-util-button" onclick={copy_node}>{"Node hex"}</button>
</div>
</div>
</div>
}} else {html! {}}}
<button class="asn1-button-with-icon" {onclick}>
<img src="/public/img/icons/more_vertical.png" />
</button>
<span class="asn1-node-options-name" {onclick}>{props.name.clone()}</span>
</div>
}
}
24 changes: 12 additions & 12 deletions src/asn1/scheme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ pub struct Asn1NodeProps {

#[function_component(Asn1Node)]
pub fn asn1_node(props: &Asn1NodeProps) -> Html {
fn compare_ids(id: u64, cur_id: &Option<u64>) -> Classes {
fn get_node_class(id: u64, cur_id: &Option<u64>) -> Classes {
match cur_id {
Some(cur_id) if *cur_id == id => {
classes!("hover_node")
classes!("hover_node", "asn1-node-container")
}
_ => classes!(""),
_ => classes!("asn1-node-container"),
}
}

Expand All @@ -45,7 +45,7 @@ pub fn asn1_node(props: &Asn1NodeProps) -> Html {
});

html! {
<div class={compare_ids(props.id, &props.cur_id)} {onmouseenter} {onmouseleave}>
<div class={get_node_class(props.id, &props.cur_id)} {onmouseenter} {onmouseleave}>
{props.children.clone()}
</div>
}
Expand All @@ -60,42 +60,42 @@ pub fn build_asn1_schema(asn1: &Asn1<'_>, cur_id: &Option<u64>, set_cur_node: &C
},
Asn1Type::Utf8String(utf8) => html! {
<Asn1Node id={utf8.id()} {cur_id} set_cur_node={set_cur_node.clone()}>
<Utf8StringNode node={utf8.to_owned()} />
<Utf8StringNode node={utf8.to_owned()} meta={asn1.raw_entity_data().to_owned()} />
</Asn1Node>
},
Asn1Type::Sequence(sequence) => html! {
<Asn1Node id={sequence.id()} {cur_id} set_cur_node={set_cur_node.clone()}>
<SequenceNode node={sequence.to_owned()} cur_node={cur_id} set_cur_node={set_cur_node.clone()} />
<SequenceNode node={sequence.to_owned()} cur_node={cur_id} set_cur_node={set_cur_node.clone()} meta={asn1.raw_entity_data().to_owned()} />
</Asn1Node>
},
Asn1Type::BitString(bit) => html! {
<Asn1Node id={bit.id()} {cur_id} set_cur_node={set_cur_node.clone()}>
<BitStringNode node={bit.to_owned()} />
<BitStringNode node={bit.to_owned()} meta={asn1.raw_entity_data().to_owned()} />
</Asn1Node>
},
Asn1Type::Bool(boolean) => html! {
<Asn1Node id={boolean.id()} {cur_id} set_cur_node={set_cur_node.clone()}>
<BoolNode node={boolean.to_owned()} />
<BoolNode node={boolean.to_owned()} meta={asn1.raw_entity_data().to_owned()} />
</Asn1Node>
},
Asn1Type::BmpString(bmp) => html! {
<Asn1Node id={bmp.id()} {cur_id} set_cur_node={set_cur_node.clone()}>
<BmpStringNode node={bmp.to_owned()} />
<BmpStringNode node={bmp.to_owned()} meta={asn1.raw_entity_data().to_owned()} />
</Asn1Node>
},
Asn1Type::Null(null) => html! {
<Asn1Node id={null.id()} {cur_id} set_cur_node={set_cur_node.clone()}>
<NullNode />
<NullNode meta={asn1.raw_entity_data().to_owned()} />
</Asn1Node>
},
Asn1Type::ExplicitTag(explicit) => html! {
<Asn1Node id={explicit.id()} {cur_id} set_cur_node={set_cur_node.clone()}>
<ExplicitTagNode node={explicit.to_owned()} cur_node={cur_id} set_cur_node={set_cur_node.clone()} />
<ExplicitTagNode node={explicit.to_owned()} cur_node={cur_id} set_cur_node={set_cur_node.clone()} meta={asn1.raw_entity_data().to_owned()} />
</Asn1Node>
},
Asn1Type::ApplicationTag(application) => html! {
<Asn1Node id={application.id()} {cur_id} set_cur_node={set_cur_node.clone()}>
<ApplicationTagNode node={application.to_owned()} cur_node={cur_id} set_cur_node={set_cur_node.clone()} />
<ApplicationTagNode node={application.to_owned()} cur_node={cur_id} set_cur_node={set_cur_node.clone()} meta={asn1.raw_entity_data().to_owned()} />
</Asn1Node>
},
}
Expand Down
24 changes: 20 additions & 4 deletions src/asn1/scheme/primitive.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
use asn1_parser::Bool;
use asn1_parser::{Bool, OwnedRawAsn1EntityData};
use yew::{function_component, html, Html, Properties};

use crate::asn1::node_options::NodeOptions;

#[derive(PartialEq, Properties, Clone)]
pub struct BoolNodeProps {
pub node: Bool,
pub meta: OwnedRawAsn1EntityData,
}

#[function_component(BoolNode)]
pub fn bool(props: &BoolNodeProps) -> Html {
let offset = props.meta.tag_position();
let length_len = props.meta.length_range().len();
let data_len = props.meta.data_range().len();

html! {
<div class="terminal-asn1-node">
<span>{"Bool"}</span>
<NodeOptions node_bytes={props.meta.raw_bytes().to_vec()} {offset} {length_len} {data_len} name={String::from("Bool")}/>
{if props.node.value() {html! {
<span class="asn-bool-true">{"true"}</span>
}} else {html! {
Expand All @@ -20,11 +27,20 @@ pub fn bool(props: &BoolNodeProps) -> Html {
}
}

#[derive(PartialEq, Properties, Clone)]
pub struct NullNodeProps {
pub meta: OwnedRawAsn1EntityData,
}

#[function_component(NullNode)]
pub fn null() -> Html {
pub fn null(props: &NullNodeProps) -> Html {
let offset = props.meta.tag_position();
let length_len = props.meta.length_range().len();
let data_len = props.meta.data_range().len();

html! {
<div class="terminal-asn1-node">
<span>{"Null"}</span>
<NodeOptions node_bytes={props.meta.raw_bytes().to_vec()} {offset} {length_len} {data_len} name={String::from("Null")}/>
</div>
}
}
10 changes: 8 additions & 2 deletions src/asn1/scheme/sequence.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use asn1_parser::OwnedSequence;
use asn1_parser::{OwnedRawAsn1EntityData, OwnedSequence};
use yew::{function_component, html, Callback, Html, Properties};

use crate::asn1::node_options::NodeOptions;
use crate::asn1::scheme::build_asn1_schema;
use crate::asn1::HighlightAction;

Expand All @@ -9,6 +10,7 @@ pub struct SequenceNodeProps {
pub node: OwnedSequence,
pub cur_node: Option<u64>,
pub set_cur_node: Callback<HighlightAction>,
pub meta: OwnedRawAsn1EntityData,
}

#[function_component(SequenceNode)]
Expand All @@ -21,10 +23,14 @@ pub fn sequence(props: &SequenceNodeProps) -> Html {
.map(|f| build_asn1_schema(f, &props.cur_node, set_cur_node))
.collect::<Vec<_>>();

let offset = props.meta.tag_position();
let length_len = props.meta.length_range().len();
let data_len = props.meta.data_range().len();

html! {
<div style="cursor: crosshair">
<div class="asn1-constructor-header">
<span>{"Sequence"}</span>
<NodeOptions node_bytes={props.meta.raw_bytes().to_vec()} {offset} {length_len} {data_len} name={String::from("Sequence")}/>
<span class="asn1-node-info-label">{format!("({} fields)", fields.len())}</span>
</div>
<div class="asn1-constructor-body">
Expand Down
Loading

0 comments on commit 1a2ea9f

Please sign in to comment.