diff options
| author | Matthieu <matthieu@developershouse.xyz> | 2021-10-18 13:52:21 +0400 |
|---|---|---|
| committer | Matthieu <matthieu@developershouse.xyz> | 2021-10-18 13:52:21 +0400 |
| commit | 2c39f7a6a1c3113337bc4e56b6e3cfa92f703fb3 (patch) | |
| tree | 01ceccb670f171c7bd12a5c0969c74572c5457e7 /webhook/src | |
| parent | 9023aa354902844b7d6100f55c3064afedd88966 (diff) | |
| parent | d55a128729ca94e727ce3a1ab4fb6af08d3cd109 (diff) | |
fix merge conflicts
Diffstat (limited to 'webhook/src')
| -rw-r--r-- | webhook/src/handler/handler.rs | 4 | ||||
| -rw-r--r-- | webhook/src/handler/make_service.rs | 3 | ||||
| -rw-r--r-- | webhook/src/handler/signature.rs | 39 | ||||
| -rw-r--r-- | webhook/src/handler/tests/handler_integration.rs | 15 | ||||
| -rw-r--r-- | webhook/src/handler/tests/signature.rs | 17 | ||||
| -rw-r--r-- | webhook/src/handler/tests/utils.rs | 49 | ||||
| -rw-r--r-- | webhook/src/main.rs | 4 |
7 files changed, 51 insertions, 80 deletions
diff --git a/webhook/src/handler/handler.rs b/webhook/src/handler/handler.rs index 74a1762..a07f995 100644 --- a/webhook/src/handler/handler.rs +++ b/webhook/src/handler/handler.rs @@ -19,12 +19,14 @@ use std::{ task::{Context, Poll}, time::Duration, }; +use ed25519_dalek::PublicKey; /// Hyper service used to handle the discord webhooks #[derive(Clone)] pub struct HandlerService { pub config: Arc<Config>, pub nats: Arc<Connection>, + pub public_key: Arc<PublicKey> } impl HandlerService { @@ -38,7 +40,7 @@ impl HandlerService { let contatenated_data = [timestamp.as_bytes().to_vec(), data.to_vec()].concat(); if let Ok(signature_str) = &signature.to_str() { if validate_signature( - &self.config.discord.public_key, + &self.public_key, &contatenated_data, signature_str, ) { diff --git a/webhook/src/handler/make_service.rs b/webhook/src/handler/make_service.rs index deeb2fe..9e90436 100644 --- a/webhook/src/handler/make_service.rs +++ b/webhook/src/handler/make_service.rs @@ -7,10 +7,12 @@ use std::{ sync::Arc, task::{Context, Poll}, }; +use ed25519_dalek::PublicKey; pub struct MakeSvc { pub settings: Arc<Config>, pub nats: Arc<Connection>, + pub public_key: Arc<PublicKey> } impl<T> Service<T> for MakeSvc { @@ -26,6 +28,7 @@ impl<T> Service<T> for MakeSvc { ready(Ok(HandlerService { config: self.settings.clone(), nats: self.nats.clone(), + public_key: self.public_key.clone() })) } } diff --git a/webhook/src/handler/signature.rs b/webhook/src/handler/signature.rs index e4c7d53..748fa6a 100644 --- a/webhook/src/handler/signature.rs +++ b/webhook/src/handler/signature.rs @@ -1,5 +1,8 @@ use common::prometheus::{Counter, HistogramVec, labels, opts, register_counter, register_histogram_vec}; -use libsodium_sys::crypto_sign_ed25519_verify_detached; +use ed25519_dalek::PublicKey; +use ed25519_dalek::Verifier; +use ed25519_dalek::Signature; +use std::convert::TryInto; lazy_static::lazy_static! { static ref SIGNATURE_TIME_HISTOGRAM: HistogramVec = register_histogram_vec!( @@ -15,36 +18,22 @@ lazy_static::lazy_static! { )).unwrap(); } -/// Checks the signature of a given data using the hex signature and the public key. -pub fn validate_signature(hex_public_key: &str, data: &Vec<u8>, hex_signature: &str) -> bool { +fn demo<T, const N: usize>(v: Vec<T>) -> [T; N] { + v.try_into() + .unwrap_or_else(|v: Vec<T>| panic!("Expected a Vec of length {} but it was {}", N, v.len())) +} + +pub fn validate_signature(public_key: &PublicKey, data: &Vec<u8>, hex_signature: &str) -> bool { SIGNATURE_COUNTER.inc(); let timer = SIGNATURE_TIME_HISTOGRAM.with_label_values(&["webhook_main"]).start_timer(); - // First, we need to check if the signature & private key is valid base64. let signature_result = hex::decode(hex_signature); - let public_key_result = hex::decode(hex_public_key); let mut result = false; - if signature_result.is_ok() && public_key_result.is_ok() { - // Since we now have the signatures in u8 vectors. We will initialize all the - // parameters for the ffi call to sodium. - let signature_pointer = signature_result.unwrap(); - let private_key_pointer = public_key_result.unwrap(); - - let data_pointer = data.as_ptr(); - let data_len = data.len() as u64; - - // A ffi call is considered unsafe by the Rust compiler - // we assume all the parameters are correct for the call - unsafe { - // If the signature is valid, sodium will return 0 - result = crypto_sign_ed25519_verify_detached( - signature_pointer.as_ptr(), - data_pointer, - data_len, - private_key_pointer.as_ptr(), - ) == 0; - } + if let Ok(signature) = signature_result { + let sig = Signature::from(demo(signature)); + + result = public_key.verify(data, &sig).is_ok(); } timer.observe_duration(); diff --git a/webhook/src/handler/tests/handler_integration.rs b/webhook/src/handler/tests/handler_integration.rs index 6031428..906b347 100644 --- a/webhook/src/handler/tests/handler_integration.rs +++ b/webhook/src/handler/tests/handler_integration.rs @@ -4,6 +4,7 @@ use ctor; use hyper::{Body, Method, Request, StatusCode}; use lazy_static::lazy_static; use serde_json::json; +use ed25519_dalek::Keypair; use common::{ config::test_init, @@ -35,7 +36,7 @@ static mut NATS: Option<Container<Cli, GenericImage>> = None; static mut SETTINGS: Option<Settings<Config>> = None; lazy_static! { - static ref KEYPAIR: (String, [u8; 64]) = generate_keypair(); + static ref TEST_KEYPAIR: Keypair = generate_keypair(); static ref DOCKER: Cli = Cli::default(); } @@ -59,7 +60,7 @@ unsafe fn init() { address: "0.0.0.0".to_string(), }, discord: crate::config::Discord { - public_key: KEYPAIR.0.clone(), + public_key: hex::encode(TEST_KEYPAIR.public.clone()), client_id: 0, }, }, @@ -103,7 +104,7 @@ async fn respond_to_pings() { let ping = json!({ "type": 1, "id": "0", "application_id": "0", "token": "random token", "version": 1 }).to_string(); let timestamp = "my datetime :)"; let signature_data = [timestamp.as_bytes().to_vec(), ping.as_bytes().to_vec()].concat(); - let signature = sign_message(signature_data, KEYPAIR.1); + let signature = sign_message(signature_data, &TEST_KEYPAIR); let req = Request::builder() .method(Method::POST) @@ -140,7 +141,7 @@ async fn response_500_when_no_nats_response() { let ping = json!({ "type": 2, "id": "0", "application_id": "0", "token": "random token", "version": 1 }).to_string(); let timestamp = "my datetime :)"; let signature_data = [timestamp.as_bytes().to_vec(), ping.as_bytes().to_vec()].concat(); - let signature = sign_message(signature_data, KEYPAIR.1); + let signature = sign_message(signature_data, &TEST_KEYPAIR); // we must timeout let req = Request::builder() @@ -166,7 +167,7 @@ async fn respond_from_nats_response() { let ping = json!({ "type": 2, "id": "0", "application_id": "0", "token": "random token", "version": 1 }).to_string(); let timestamp = "my datetime :)"; let signature_data = [timestamp.as_bytes().to_vec(), ping.as_bytes().to_vec()].concat(); - let signature = sign_message(signature_data, KEYPAIR.1); + let signature = sign_message(signature_data, &TEST_KEYPAIR); sub.with_handler(move |msg| { info!("Received {}", &msg); @@ -191,7 +192,7 @@ async fn response_400_when_invalid_json_body() { let ping = "{".to_string(); let timestamp = "my datetime :)"; let signature_data = [timestamp.as_bytes().to_vec(), ping.as_bytes().to_vec()].concat(); - let signature = sign_message(signature_data, KEYPAIR.1); + let signature = sign_message(signature_data, &TEST_KEYPAIR); let req = Request::builder() .method(Method::POST) @@ -212,7 +213,7 @@ async fn response_400_when_invalid_utf8_body() { let timestamp = "my datetime :)"; let signature_data = [timestamp.as_bytes().to_vec(), ping.to_vec()].concat(); - let signature = sign_message(signature_data, KEYPAIR.1); + let signature = sign_message(signature_data, &TEST_KEYPAIR); let req = Request::builder() .method(Method::POST) diff --git a/webhook/src/handler/tests/signature.rs b/webhook/src/handler/tests/signature.rs index 475e446..490143b 100644 --- a/webhook/src/handler/tests/signature.rs +++ b/webhook/src/handler/tests/signature.rs @@ -1,30 +1,33 @@ use crate::handler::signature::validate_signature; - +use ed25519_dalek::PublicKey; #[test] fn validate_signature_test() { let signature = "543ec3547d57f9ddb1ec4c5c36503ebf288ffda3da3d510764c9a49c2abb57690ef974c63d174771bdd2481de1066966f57abbec12a3ec171b9f6e2373837002"; - let public_key = "eefe0c24473737cb2035232e3b4eb91c206f0a14684168f3503f7d8316058d6f"; let content = "message de test incroyable".as_bytes().to_vec(); - assert!(validate_signature(public_key, &content, signature)) + let public_key = PublicKey::from_bytes(&hex::decode("eefe0c24473737cb2035232e3b4eb91c206f0a14684168f3503f7d8316058d6f").unwrap()).unwrap(); + + assert!(validate_signature(&public_key, &content, signature)) } #[test] fn validate_signature_reverse_test() { let signature = "543ec3547d57f9ddb1ec4c5c36503ebf288ffda3da3d510764c9a49c2abb57690ef974c63d174771bdd2481de1066966f57abbec12a3ec171b9f6e2373837002"; - let public_key = "c029eea18437292c87c62aec34e7d1bd4e38fe6126f3f7c446de6375dc666044"; + let public_key = PublicKey::from_bytes(&hex::decode("c029eea18437292c87c62aec34e7d1bd4e38fe6126f3f7c446de6375dc666044").unwrap()).unwrap(); + let content = "ceci est un test qui ne fonctionnera pas!" .as_bytes() .to_vec(); - assert!(!validate_signature(public_key, &content, signature)) + assert!(!validate_signature(&public_key, &content, signature)) } #[test] fn invalid_hex() { let signature = "zzz"; - let public_key = "zzz"; + let public_key = PublicKey::from_bytes(&hex::decode("c029eea18437292c87c62aec34e7d1bd4e38fe6126f3f7c446de6375dc666044").unwrap()).unwrap(); + let content = "ceci est un test qui ne fonctionnera pas!" .as_bytes() .to_vec(); - assert!(!validate_signature(public_key, &content, signature)) + assert!(!validate_signature(&public_key, &content, signature)) }
\ No newline at end of file diff --git a/webhook/src/handler/tests/utils.rs b/webhook/src/handler/tests/utils.rs index f8cdac2..5e59f09 100644 --- a/webhook/src/handler/tests/utils.rs +++ b/webhook/src/handler/tests/utils.rs @@ -1,46 +1,15 @@ -pub fn generate_keypair() -> ( - String, - [u8; libsodium_sys::crypto_sign_ed25519_SECRETKEYBYTES as usize], -) { - use libsodium_sys::crypto_sign_ed25519_keypair; - let pk_s: String; +use rand::rngs::OsRng; +use ed25519_dalek::{Signer, Keypair, Signature}; - let mut pk = [0; libsodium_sys::crypto_sign_ed25519_PUBLICKEYBYTES as usize]; - let mut sk = [0; libsodium_sys::crypto_sign_ed25519_SECRETKEYBYTES as usize]; - - let pk_p = pk.as_mut_ptr(); - let sk_p = sk.as_mut_ptr(); - - // generate keypair - unsafe { - if crypto_sign_ed25519_keypair(pk_p, sk_p) < 0 { - panic!("keypair generation failed!"); - } - }; - - pk_s = hex::encode(pk); - return (pk_s, sk); +pub fn generate_keypair() -> Keypair { + let mut csprng = OsRng{}; + Keypair::generate(&mut csprng) } pub fn sign_message( - msg: Vec<u8>, - sk: [u8; libsodium_sys::crypto_sign_ed25519_SECRETKEYBYTES as usize], + message: Vec<u8>, + keypair: &Keypair, ) -> String { - use libc::c_ulonglong; - use libsodium_sys::crypto_sign_ed25519_detached; - - let len = msg.len(); - let mut signature_len: c_ulonglong = 0; - let mut str = [0; 64]; - unsafe { - crypto_sign_ed25519_detached( - str.as_mut_ptr(), - &mut signature_len, - msg.as_ptr(), - len as u64, - sk.as_ptr(), - ); - }; - - return hex::encode(str); + let signature: Signature = keypair.sign(&message); + return hex::encode(signature.to_bytes()); }
\ No newline at end of file diff --git a/webhook/src/main.rs b/webhook/src/main.rs index 98e5f13..00d42ee 100644 --- a/webhook/src/main.rs +++ b/webhook/src/main.rs @@ -6,6 +6,7 @@ use crate::handler::make_service::MakeSvc; use crate::config::Config;
use common::config::Settings;
use common::log::{error, info};
+use ed25519_dalek::PublicKey;
use hyper::Server;
#[tokio::main]
@@ -30,9 +31,12 @@ async fn start(settings: Settings<Config>) { );
let config = Arc::new(settings.config);
+ let public_key =
+ Arc::new(PublicKey::from_bytes(&hex::decode(&config.discord.public_key).unwrap()).unwrap());
let server = Server::bind(&addr).serve(MakeSvc {
settings: config,
nats: Arc::new(settings.nats.into()),
+ public_key: public_key,
});
if let Err(e) = server.await {
|
