Skip to content

Commit

Permalink
Merge pull request #59 from TheBestTvarynka/local-storage
Browse files Browse the repository at this point in the history
Local storage support
  • Loading branch information
TheBestTvarynka authored Mar 1, 2024
2 parents b20bfc0 + 2b14b04 commit 0486f5e
Show file tree
Hide file tree
Showing 12 changed files with 120 additions and 28 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ members = [
yew = { version = "0.20", features = ["csr"] }
yew-router = "0.17.0"
yew-notifications = { git = "https://github.com/TheBestTvarynka/yew-notifications.git", features = ["standard-notification"] }
yew-hooks = "0.2.0"

# wasm
js-sys = "0.3.60"
Expand Down Expand Up @@ -47,7 +48,6 @@ sha1 = "0.10.5"
hmac-sha256 = "1.1.5"
hmac-sha512 = { version = "1.1.2", features = ["sha384"] }
rsa = "0.7.2"
yew-hooks = "0.2.0"
bcrypt = "0.14.0"
flate2 = { version = "1.0.26", features = ["zlib"] }

Expand Down
34 changes: 29 additions & 5 deletions src/asn1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ mod scheme;

use std::rc::Rc;

use asn1_parser::{Asn1, Asn1Decoder};
use asn1_parser::{Asn1, Asn1Decoder, Asn1Encoder};
use web_sys::KeyboardEvent;
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_hooks::{use_clipboard, use_local_storage, 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::common::{encode_bytes, ByteInput, BytesFormat};
use crate::url_query_params;
use crate::url_query_params::generate_asn1_link;

Expand All @@ -26,6 +26,7 @@ pub const TEST_ASN1: &[u8] = &[
48, 30, 160, 2, 5, 0, 161, 24, 30, 22, 0, 67, 0, 101, 0, 114, 0, 116, 0, 105, 0, 102, 0, 105, 0, 99, 0, 97, 0, 116,
0, 101,
];
const ASN1_LOCAL_STORAGE_KEY: &str = "ASN1_DATA";

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)
Expand Down Expand Up @@ -83,7 +84,7 @@ pub fn asn1_parser_page() -> Html {
let raw_data = (*raw_asn1).clone();
let parse_asn1 = Callback::from(move |_| match Asn1::decode_buff(&raw_data) {
Ok(asn1) => {
log::debug!("parsed!");
debug!("parsed!");
asn1_setter.set(asn1.to_owned_with_asn1(asn1.inner_asn1().to_owned()));
}
Err(error) => notifications.spawn(Notification::new(
Expand All @@ -109,11 +110,25 @@ pub fn asn1_parser_page() -> Html {
let notifications = notification_manager.clone();
let raw_asn1_setter = raw_asn1.setter();
let asn1_setter = parsed_asn1.setter();
let local_storage = use_local_storage::<String>(ASN1_LOCAL_STORAGE_KEY.to_owned());
use_effect_with_deps(
move |_: &[(); 0]| {
let query = &location.search;

if query.len() < 2 {
// URL query params is empty. We try to load ASN1 from local storage.
if let Some(raw_asn1) = (*local_storage).as_ref() {
if let Ok(bytes) = hex::decode(raw_asn1) {
match Asn1::decode_buff(&bytes) {
Ok(asn1) => {
asn1_setter.set(asn1.to_owned_with_asn1(asn1.inner_asn1().to_owned()));
}
Err(err) => {
error!("Can not decode asn1: {:?}", err);
}
}
}
}
return;
}

Expand All @@ -122,7 +137,6 @@ pub fn asn1_parser_page() -> Html {
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(
Expand All @@ -145,6 +159,16 @@ pub fn asn1_parser_page() -> Html {
[],
);

let local_storage = use_local_storage::<String>(ASN1_LOCAL_STORAGE_KEY.to_owned());
use_effect_with_deps(
move |asn1| {
let mut encoded = vec![0; asn1.needed_buf_size()];
asn1.encode_buff(&mut encoded).expect("ASN1 encoding should not fail");
local_storage.set(encode_bytes(encoded, BytesFormat::Hex));
},
parsed_asn1.clone(),
);

let clipboard = use_clipboard();
let raw_asn1_data = (*raw_asn1).clone();
let share_by_link = Callback::from(move |_| {
Expand Down
2 changes: 1 addition & 1 deletion src/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pub const BYTES_FORMATS: [BytesFormat; 5] = [
BytesFormat::Binary,
];

fn encode_bytes(bytes: impl AsRef<[u8]>, format: BytesFormat) -> String {
pub fn encode_bytes(bytes: impl AsRef<[u8]>, format: BytesFormat) -> String {
match format {
BytesFormat::Hex => hex::encode(bytes),
BytesFormat::Base64 => base64::encode(bytes),
Expand Down
61 changes: 46 additions & 15 deletions src/crypto_helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ mod info;
mod input;
mod macros;
mod output;
pub mod serde;

pub use algorithm::Algorithm;
use info::Info;
Expand All @@ -14,13 +13,15 @@ use picky_krb::crypto::{ChecksumSuite, CipherSuite};
use sha1::{Digest, Sha1};
use web_sys::KeyboardEvent;
use yew::{function_component, html, use_effect_with_deps, use_state, Callback, Html};
use yew_hooks::{use_clipboard, use_location};
use yew_hooks::{use_clipboard, use_local_storage, use_location};
use yew_notifications::{use_notification, Notification, NotificationType};

use self::computations::{process_krb_cipher, process_krb_hmac, process_rsa, process_zlib};
use crate::crypto_helper::computations::process_bcrypt;
use crate::url_query_params::generate_crypto_helper_link;

const CRYPTO_HELPER_LOCAL_STORAGE_KEY: &str = "CRYPTO_HELPER_DATA";

fn convert(algrithm: &Algorithm) -> Result<Vec<u8>, String> {
match algrithm {
Algorithm::Md5(input) => Ok(md5::compute(input).to_vec()),
Expand Down Expand Up @@ -71,29 +72,59 @@ pub fn crypto_helper() -> Html {
let algorithm_setter = algorithm.setter();
let location = use_location();
let notifications = notification_manager.clone();
let local_storage = use_local_storage::<String>(CRYPTO_HELPER_LOCAL_STORAGE_KEY.to_owned());
use_effect_with_deps(
move |_: &[(); 0]| {
let query = &location.search;

if query.len() < 2 {
return;
}

match serde_qs::from_str(&query[1..]) {
Ok(algorithm) => {
algorithm_setter.set(algorithm);
// First, we try to load data from the url.
// question mark + one any other char
if query.len() >= 2 {
match serde_qs::from_str(&query[1..]) {
Ok(algorithm) => {
algorithm_setter.set(algorithm);
}
Err(err) => notifications.spawn(Notification::new(
NotificationType::Error,
"Can not load data from url",
err.to_string(),
Notification::NOTIFICATION_LIFETIME,
)),
}
} else {
// Otherwise, we try to find a data in the local storage.
let raw_data = if let Some(raw_data) = (*local_storage).as_ref() {
raw_data.as_str()
} else {
return;
};
match serde_json::from_str(raw_data) {
Ok(algorithm) => {
algorithm_setter.set(algorithm);
}
Err(err) => notifications.spawn(Notification::new(
NotificationType::Error,
"Can not load data from the local storage",
err.to_string(),
Notification::NOTIFICATION_LIFETIME,
)),
}
Err(err) => notifications.spawn(Notification::new(
NotificationType::Error,
"Can not load data from url",
err.to_string(),
Notification::NOTIFICATION_LIFETIME,
)),
}
},
[],
);

let local_storage = use_local_storage::<String>(CRYPTO_HELPER_LOCAL_STORAGE_KEY.to_owned());
use_effect_with_deps(
move |algorithm| {
let algorithm: &Algorithm = algorithm;
local_storage.set(
serde_json::to_string(algorithm).expect("algorithm serialization into json string should never fail"),
);
},
algorithm.clone(),
);

let algorithm_data = (*algorithm).clone();
let clipboard = use_clipboard();
let share_by_link = Callback::from(move |_| {
Expand Down
2 changes: 1 addition & 1 deletion src/crypto_helper/algorithm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use rsa::pkcs1::{DecodeRsaPrivateKey, DecodeRsaPublicKey};
use rsa::{RsaPrivateKey, RsaPublicKey};
use serde::{Deserialize, Serialize};

use super::serde::*;
use crate::serde::*;

pub const MD5: &str = "MD5";
pub const SHA1: &str = "SHA1";
Expand Down
26 changes: 25 additions & 1 deletion src/jwt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::str::FromStr;

use web_sys::{HtmlInputElement, KeyboardEvent};
use yew::{function_component, html, use_effect_with_deps, use_state, Callback, Html, TargetCast};
use yew_hooks::use_location;
use yew_hooks::{use_local_storage, use_location};
use yew_notifications::{use_notification, Notification, NotificationType};

use crate::common::Checkbox;
Expand All @@ -20,6 +20,7 @@ use crate::jwt::jwt_utils::JwtUtils;
use crate::jwt::jwte::Jwte;
use crate::url_query_params;

const JWT_LOCAL_STORAGE_KEY: &str = "JWT_DATA";
const TEST_JWT: &str = "eyJhbGciOiJIUzI1NiJ9.eyJSb2xlIjoiQWRtaW4iLCJJc3N1ZXIiOiJJc3N1ZXIiLCJVc2VybmFtZSI6IkphdmFJblVzZSIsImV4cCI6MTY3MDAwNDI1NCwiaWF0IjoxNjcwMDA0MjU0fQ.ZGsN42vr-bM4uxXowtlNl7xRerkdKu6i29VS8DFQ4Tw";

#[function_component(Jwt)]
Expand Down Expand Up @@ -86,11 +87,23 @@ pub fn jwt() -> Html {
let jwt_setter = raw_jwt.setter();
let jwte_setter = jwte.setter();
let notifications = use_notification::<Notification>();
let local_storage = use_local_storage::<String>(JWT_LOCAL_STORAGE_KEY.to_owned());
use_effect_with_deps(
move |_: &[(); 0]| {
let query = &location.search;

if query.len() < 2 {
// URL query params is empty. We try to load JWT from local storage.
if let Some(raw_jwt) = (*local_storage).as_ref() {
match serde_json::from_str(raw_jwt.as_str()) {
Ok(jwt) => {
jwte_setter.set(Some(Jwte::Jwt(jwt)));
}
Err(err) => {
error!("Can not load JWT from local storage: {:?}", err);
}
}
}
return;
}

Expand Down Expand Up @@ -125,6 +138,17 @@ pub fn jwt() -> Html {
[],
);

let local_storage = use_local_storage::<String>(JWT_LOCAL_STORAGE_KEY.to_owned());
use_effect_with_deps(
move |jwte| {
let jwte: &Option<Jwte> = jwte;
if let Some(Jwte::Jwt(jwt)) = jwte {
local_storage.set(serde_json::to_string(jwt).expect("JWT serialization should not fail"));
}
},
jwte.clone(),
);

let jwte_setter = jwte.setter();
let set_jwt = Callback::from(move |jwt| {
jwte_setter.set(Some(Jwte::Jwt(jwt)));
Expand Down
5 changes: 4 additions & 1 deletion src/jwt/jwt.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use serde::{Deserialize, Serialize};
use serde_json::Value;

use super::signature::JwtSignatureAlgorithm;
use crate::serde::{deserialize_bytes, serialize_bytes};

pub mod editor;
pub mod viewer;

#[derive(Debug, PartialEq, Eq, Default, Clone)]
#[derive(Debug, PartialEq, Eq, Default, Clone, Serialize, Deserialize)]
pub struct Jwt {
pub raw_header: String,
pub parsed_header: String,
Expand All @@ -15,6 +17,7 @@ pub struct Jwt {

pub raw_signature: String,
pub parsed_signature: String,
#[serde(serialize_with = "serialize_bytes", deserialize_with = "deserialize_bytes")]
pub signature: Vec<u8>,
pub signature_algorithm: JwtSignatureAlgorithm,

Expand Down
2 changes: 1 addition & 1 deletion src/jwt/jwt_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ fn validate_signature(jwt: &Jwt, spawn_notification: Callback<Notification>) ->
Some(jwt.signature == calculated_signature)
}

fn generate_jwt(jwt: &Jwt, spawn_notification: Callback<Notification>) -> Option<Vec<u8>> {
pub fn generate_jwt(jwt: &Jwt, spawn_notification: Callback<Notification>) -> Option<Vec<u8>> {
let signature = calculate_signature(jwt, spawn_notification)?;

let header = base64::encode_config(jwt.parsed_header.as_bytes(), base64::URL_SAFE_NO_PAD);
Expand Down
8 changes: 7 additions & 1 deletion src/jwt/signature.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
use std::fmt::{self, Display};

use serde::{Deserialize, Serialize};
use serde_json::Value;

use crate::serde::{deserialize_bytes, serialize_bytes};

const JWT_SIGNATURE_ALGORITHMS: [&str; 10] = [
"HS256", "HS512", "none", "RS256", "HS384", "RS384", "RS512", "ES256", "ES384", "ES512",
];

#[derive(Debug, PartialEq, Eq, Clone)]
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub enum JwtSignatureAlgorithm {
None,

/// HMAC using SHA-256
#[serde(serialize_with = "serialize_bytes", deserialize_with = "deserialize_bytes")]
Hs256(Vec<u8>),

/// HMAC using SHA-384
#[serde(serialize_with = "serialize_bytes", deserialize_with = "deserialize_bytes")]
Hs384(Vec<u8>),

/// HMAC using SHA-512
#[serde(serialize_with = "serialize_bytes", deserialize_with = "deserialize_bytes")]
Hs512(Vec<u8>),

/// RSASSA-PKCS1-v1_5 using SHA-256
Expand Down
4 changes: 4 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#[macro_use]
extern crate log;

mod about;
mod asn1;
mod common;
Expand All @@ -6,6 +9,7 @@ mod footer;
mod header;
mod jwt;
mod not_found;
pub mod serde;
mod url_query_params;
mod utils;

Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion src/url_query_params.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize};

use crate::crypto_helper::serde::{deserialize_bytes, serialize_bytes};
use crate::crypto_helper::Algorithm;
use crate::serde::{deserialize_bytes, serialize_bytes};

const APP_HOST: &str = env!("APP_HOST");

Expand Down

0 comments on commit 0486f5e

Please sign in to comment.