From 60b26344d6171d56dbbe4a610da5b3c2457169c6 Mon Sep 17 00:00:00 2001 From: ghe0 Date: Thu, 15 Aug 2024 02:11:58 +0300 Subject: [PATCH] signing random messages from user --- src/database.rs | 55 ++++++++++++++++++++++++++++++++++++++++++++-- src/grpc.rs | 6 +++-- src/http_server.rs | 24 ++++++++++++++++++-- 3 files changed, 79 insertions(+), 6 deletions(-) diff --git a/src/database.rs b/src/database.rs index c270f5a..907033e 100644 --- a/src/database.rs +++ b/src/database.rs @@ -1,11 +1,44 @@ #![allow(dead_code)] -use ed25519_dalek::{SigningKey, VerifyingKey}; +use ed25519_dalek::{Signer, SigningKey, VerifyingKey}; use once_cell::sync::Lazy; use std::collections::HashMap; use std::sync::Mutex; use std::time::SystemTime; use tabled::{Table, Tabled}; +pub enum SigningError { + CorruptedKey, + KeyNotFound, +} + +impl std::fmt::Display for SigningError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let error_message = match self { + SigningError::CorruptedKey => "The public key is corrupted", + SigningError::KeyNotFound => "Did not find the public key", + }; + write!(f, "{}", error_message) + } +} + +impl From for SigningError { + fn from(_: hex::FromHexError) -> Self { + Self::CorruptedKey + } +} + +impl From for SigningError { + fn from(_: ed25519_dalek::ed25519::Error) -> Self { + Self::CorruptedKey + } +} + +impl From for SigningError { + fn from(_: std::array::TryFromSliceError) -> Self { + Self::CorruptedKey + } +} + #[derive(Clone)] pub struct NodeInfo { pub pubkey: VerifyingKey, @@ -27,11 +60,29 @@ pub fn remove_key(pubkey: &VerifyingKey) { keys.remove(pubkey); } -pub fn get_privkey(pubkey: &VerifyingKey) -> Option { +fn get_privkey(pubkey: &VerifyingKey) -> Option { let keys = KEYS.lock().unwrap(); keys.get(pubkey).cloned() } +pub fn sign_message_with_key(pubkey: &str, message: &str) -> Result { + // Parse the hex string into a VerifyingKey + let key_bytes = hex::decode(pubkey)?; + let pubkey = VerifyingKey::from_bytes(&key_bytes.as_slice().try_into()?)?; + + // Lock the hashmap and try to get the SigningKey + let key_store = KEYS.lock().unwrap(); + let signing_key = match key_store.get(&pubkey) { + Some(k) => k, + None => return Err(SigningError::KeyNotFound), + }; + + // TODO: check if to_bytes returns the signature in a format that people can verify from bash + let signature = hex::encode(signing_key.sign(message.as_bytes()).to_bytes()); + + Ok(signature) +} + pub fn add_node(ip: String, info: NodeInfo) { let mut nodes = NODES.lock().unwrap(); nodes.insert(ip, info); diff --git a/src/grpc.rs b/src/grpc.rs index a7c3ea4..483ec72 100644 --- a/src/grpc.rs +++ b/src/grpc.rs @@ -4,11 +4,13 @@ use rand::rngs::OsRng; pub fn add_node(ip: String) { let mut csprng = OsRng; + let privkey = ed25519_dalek::SigningKey::generate(&mut csprng); database::add_node( ip, NodeInfo { - pubkey: ed25519_dalek::SigningKey::generate(&mut csprng).verifying_key(), + pubkey: privkey.verifying_key(), updated_at: std::time::SystemTime::now(), }, - ) + ); + database::add_key(privkey.verifying_key(), privkey); } diff --git a/src/http_server.rs b/src/http_server.rs index d9040d9..317751a 100644 --- a/src/http_server.rs +++ b/src/http_server.rs @@ -1,14 +1,34 @@ -use salvo::prelude::*; use crate::database::get_nodes_as_html_tabe; +use salvo::prelude::*; #[handler] async fn homepage() -> String { get_nodes_as_html_tabe() } +#[handler] +async fn sign(req: &mut Request) -> String { + let pubkey = match req.query::("pubkey") { + Some(k) => k, + None => return "pubkey must be specified as GET param".to_string(), + }; + + let something = match req.query::("something") { + Some(k) => k, + None => return "something must be specified as GET param".to_string(), + }; + + match crate::database::sign_message_with_key(&pubkey, &something) { + Ok(s) => s, + Err(e) => e.to_string(), + } +} + pub async fn start() { let acceptor = TcpListener::new("0.0.0.0:5800").bind().await; - let router = Router::new().get(homepage); + let router = Router::new() + .get(homepage) + .push(Router::with_path("sign").get(sign)); println!("{:?}", router); Server::new(acceptor).serve(router).await; }