From: Matthieu Date: Wed, 13 Oct 2021 09:09:35 +0000 (+0400) Subject: add more tests for the webhook X-Git-Tag: v0.1~56^2~28 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=1a10e1778ce34d704545433f6f462f72e4b905dd;p=matthieu%2Fnova.git add more tests for the webhook --- diff --git a/webhook/Cargo.toml b/webhook/Cargo.toml index ba0b2f8..7e73c43 100644 --- a/webhook/Cargo.toml +++ b/webhook/Cargo.toml @@ -12,6 +12,7 @@ libsodium-sys = "0.2.7" hex = "0.4.3" serde_json = { version = "1.0" } libc = "0.2.101" +lazy_static = "1.4.0" [[bin]] name = "webhook" diff --git a/webhook/src/handler/error.rs b/webhook/src/handler/error.rs new file mode 100644 index 0000000..ccec59f --- /dev/null +++ b/webhook/src/handler/error.rs @@ -0,0 +1,24 @@ +use hyper::{Body, Error, Response, StatusCode}; + +pub struct WebhookError { + pub code: StatusCode, + pub message: String, +} + +impl WebhookError { + pub fn new(code: StatusCode, message: &str) -> WebhookError { + WebhookError { + code, + message: message.to_string(), + } + } +} + +impl Into> for WebhookError { + fn into(self) -> Response { + Response::builder() + .status(self.code) + .body(self.message.into()) + .unwrap() + } +} diff --git a/webhook/src/handler/handler.rs b/webhook/src/handler/handler.rs index b3dc8a6..bcce81d 100644 --- a/webhook/src/handler/handler.rs +++ b/webhook/src/handler/handler.rs @@ -1,14 +1,22 @@ +use super::error::WebhookError; use super::{signature::validate_signature, types::Interaction}; use crate::config::Config; +use common::log::{debug, error, info}; +use common::nats_crate::Connection; use hyper::{ body::{to_bytes, Bytes}, service::Service, Body, Method, Request, Response, StatusCode, }; -use common::log::{error, info, trace}; -use common::nats_crate::Connection; use serde::{Deserialize, Serialize}; -use std::{future::Future, io::{Error, ErrorKind}, pin::Pin, str::from_utf8, sync::Arc, task::{Context, Poll}, time::Duration}; +use std::{ + future::Future, + pin::Pin, + str::from_utf8, + sync::Arc, + task::{Context, Poll}, + time::Duration, +}; /// Hyper service used to handle the discord webhooks #[derive(Clone)] @@ -18,7 +26,7 @@ pub struct HandlerService { } impl HandlerService { - async fn check_request(&self, req: Request) -> Result { + async fn check_request(&self, req: Request) -> Result { if req.method() == Method::POST { let headers = req.headers().clone(); let signature = headers.get("X-Signature-Ed25519"); @@ -34,25 +42,79 @@ impl HandlerService { ) { Ok(data) } else { - Err(Error::new( - ErrorKind::InvalidData, - "invalid signature specified", - )) + Err(WebhookError::new(StatusCode::UNAUTHORIZED, "invalid signature")) } } else { - Err(Error::new( - ErrorKind::BrokenPipe, - "failed to read signature", - )) + Err(WebhookError::new(StatusCode::BAD_REQUEST, "failed to read signature")) } } else { - Err(Error::new(ErrorKind::BrokenPipe, "unable to read body")) + Err(WebhookError::new(StatusCode::BAD_REQUEST, "unable to read body")) } } else { - Err(Error::new(ErrorKind::InvalidData, "missing headers")) + Err(WebhookError::new(StatusCode::UNAUTHORIZED, "missing signature headers")) } } else { - Err(Error::new(ErrorKind::InvalidData, "invalid method")) + Err(WebhookError::new(StatusCode::NOT_FOUND, "not found")) + } + } + + + async fn process_request(&mut self, req: Request) -> Result, WebhookError> { + match self.check_request(req).await { + Ok(data) => { + let utf8 = from_utf8(&data); + match utf8 { + Ok(data) => match serde_json::from_str::(data) { + Ok(value) => match value.t { + 1 => { + info!("sending pong"); + // a ping must be responded with another ping + return Ok(Response::builder() + .header("Content-Type", "application/json") + .body(serde_json::to_string(&Ping { t: 1 }).unwrap().into()) + .unwrap()); + } + _ => { + debug!("calling nats"); + // this should hopefully not fail ? + let payload = + serde_json::to_string(&common::payloads::CachePayload { + tracing: common::payloads::Tracing { + node_id: "".to_string(), + span: None, + }, + operation: "".to_string(), + data: value, + }) + .unwrap(); + + match self.nats.request_timeout( + "nova.cache.dispatch.interaction", + payload, + Duration::from_secs(2), + ) { + Ok(response) => Ok(Response::builder() + .header("Content-Type", "application/json") + .body( + Body::from(response.data) + ) + .unwrap()), + + Err(error) => { + error!("failed to request nats: {}", error); + Err(WebhookError::new(StatusCode::INTERNAL_SERVER_ERROR, "failed to request nats")) + } + } + } + }, + + Err(_) => Err(WebhookError::new(StatusCode::BAD_REQUEST, "invalid json body")), + }, + + Err(_) => Err(WebhookError::new(StatusCode::BAD_REQUEST, "not utf-8 body")), + } + } + Err(error) => Err(error), } } } @@ -74,58 +136,13 @@ impl Service> for HandlerService { } fn call(&mut self, req: Request) -> Self::Future { - let self_clone = self.clone(); - + let mut clone = self.clone(); Box::pin(async move { - match self_clone.check_request(req).await { - Ok(data) => { - let value: Interaction = - serde_json::from_str(from_utf8(&data).unwrap()).unwrap(); - trace!("received value: {:?}", value); - - match value.t { - 1 => { - info!("sending pong"); - // a ping must be responded with another ping - return Ok(Response::builder() - .header("Content-Type", "application/json") - .body(serde_json::to_string(&Ping { t: 1 }).unwrap().into()) - .unwrap()); - } - _ => { - let payload = serde_json::to_string(&common::payloads::CachePayload { - tracing: common::payloads::Tracing { - node_id: "".to_string(), - span: None, - }, - operation: "".to_string(), - data: value, - }) - .unwrap(); + let response = clone.process_request(req).await; - match self_clone - .nats - .request_timeout("nova.cache.dispatch.interaction", payload, Duration::from_secs(2)) - { - Ok(response) => Ok(Response::builder() - .header("Content-Type", "application/json") - .body(from_utf8(&response.data).unwrap().to_string().into()) - .unwrap()), - Err(error) => { - error!("failed to request nats: {}", error); - Ok(Response::builder() - .status(500) - .body("an internal server error occured".to_string().into()) - .unwrap()) - } - } - } - } - } - Err(error) => Ok(Response::builder() - .status(StatusCode::UNAUTHORIZED) - .body(error.to_string().into()) - .unwrap()), + match response { + Ok(r) => Ok(r), + Err(e) => Ok(e.into()) } }) } diff --git a/webhook/src/handler/mod.rs b/webhook/src/handler/mod.rs index 598906b..a437dd5 100644 --- a/webhook/src/handler/mod.rs +++ b/webhook/src/handler/mod.rs @@ -2,4 +2,7 @@ pub mod make_service; mod signature; mod handler; mod types; +mod error; + +#[cfg(test)] pub mod tests; \ No newline at end of file diff --git a/webhook/src/handler/signature.rs b/webhook/src/handler/signature.rs index 5af6b63..b98af51 100644 --- a/webhook/src/handler/signature.rs +++ b/webhook/src/handler/signature.rs @@ -29,37 +29,3 @@ pub fn validate_signature(hex_public_key: &str, data: &Vec, hex_signature: & } false } - -#[cfg(test)] -mod test { - use crate::handler::signature::validate_signature; - - - #[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)) - } - - #[test] - fn validate_signature_reverse_test() { - let signature = "543ec3547d57f9ddb1ec4c5c36503ebf288ffda3da3d510764c9a49c2abb57690ef974c63d174771bdd2481de1066966f57abbec12a3ec171b9f6e2373837002"; - let public_key = "c029eea18437292c87c62aec34e7d1bd4e38fe6126f3f7c446de6375dc666044"; - let content = "ceci est un test qui ne fonctionnera pas!" - .as_bytes() - .to_vec(); - assert!(!validate_signature(public_key, &content, signature)) - } - - #[test] - fn invalid_hex() { - let signature = "zzz"; - let public_key = "zzz"; - let content = "ceci est un test qui ne fonctionnera pas!" - .as_bytes() - .to_vec(); - assert!(!validate_signature(public_key, &content, signature)) - } -} diff --git a/webhook/src/handler/tests/handler.rs b/webhook/src/handler/tests/handler.rs index 3e5ccd0..e69de29 100644 --- a/webhook/src/handler/tests/handler.rs +++ b/webhook/src/handler/tests/handler.rs @@ -1,174 +0,0 @@ -fn generate_keypair() -> ( - String, - [u8; libsodium_sys::crypto_sign_ed25519_SECRETKEYBYTES as usize], -) { - use libsodium_sys::crypto_sign_ed25519_keypair; - let pk_s: String; - - 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); -} - -fn sign_message( - msg: Vec, - sk: [u8; libsodium_sys::crypto_sign_ed25519_SECRETKEYBYTES as usize], -) -> 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); -} - -#[tokio::test] -async fn respond_to_pings_and_deny_invalid() { - use crate::start; - use common::config::test_init; - use common::config::Settings; - use common::log::info; - use common::testcontainers::images::generic::GenericImage; - use common::testcontainers::Docker; - use hyper::{Body, Method, Request}; - use libsodium_sys::sodium_init; - use serde_json::json; - use std::time::Duration; - - test_init(); - - unsafe { - if sodium_init() < 0 { - panic!("libsodium init error!"); - } - } - - let (private_key, secret_key) = generate_keypair(); - let ping = json!({ "type": 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, secret_key); - - // start nats - let docker = common::testcontainers::clients::Cli::default(); - let image = GenericImage::new("nats"); - let node = docker.run(image); - node.start(); - let port = node.get_host_port(4222).unwrap(); - - let settings: Settings = common::config::Settings { - config: crate::config::Config { - server: crate::config::ServerSettings { - port: 5003, - address: "0.0.0.0".to_string(), - }, - discord: crate::config::Discord { - public_key: private_key, - client_id: 0, - }, - }, - monitoring: common::monitoring::MonitoringConfiguration { - enabled: false, - address: None, - port: None, - }, - nats: common::nats::NatsConfiguration { - client_cert: None, - root_cert: None, - jetstream_api_prefix: None, - max_reconnects: None, - reconnect_buffer_size: None, - tls: None, - client_name: None, - tls_required: None, - host: format!("localhost:{}", port), - }, - }; - - let nats: common::nats_crate::Connection = settings.nats.clone().into(); - // start the server - tokio::task::spawn(start(settings)); - tokio::time::sleep(Duration::from_secs(1)).await; - - let req = Request::builder() - .method(Method::POST) - .uri("http://localhost:5003/") - .header("X-Signature-Ed25519", signature) - .header("X-Signature-Timestamp", timestamp) - .body(Body::from(ping.clone())) - .expect("request builder"); - let client = hyper::client::Client::new(); - let result = client.request(req).await.unwrap(); - assert!(result.status() == 200); - - let req = Request::builder() - .method(Method::POST) - .uri("http://localhost:5003/") - .header("X-Signature-Ed25519", "inva&lid signature :)") - .header("X-Signature-Timestamp", timestamp) - .body(Body::from(ping.clone())) - .expect("request builder"); - let client = hyper::client::Client::new(); - let result = client.request(req).await.unwrap(); - assert!(result.status() == 401); - - // setup nats mock listener - let sub = nats.subscribe("nova.cache.dispatch.interaction").unwrap(); - - let ping = json!({ "type": 0 }).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, secret_key); - - // we must timeout - let req = Request::builder() - .method(Method::POST) - .uri("http://localhost:5003/") - .header("X-Signature-Ed25519", signature.clone()) - .header("X-Signature-Timestamp", timestamp) - .body(Body::from(ping.clone())) - .expect("request builder"); - let client = hyper::client::Client::new(); - let result = client.request(req).await.unwrap(); - assert!(result.status() == 500); - - sub.with_handler(move |msg| { - info!("Received {}", &msg); - msg.respond("ok :)").unwrap(); - Ok(()) - }); - - let req = Request::builder() - .method(Method::POST) - .uri("http://localhost:5003/") - .header("X-Signature-Ed25519", signature.clone()) - .header("X-Signature-Timestamp", timestamp) - .body(Body::from(ping.clone())) - .expect("request builder"); - let client = hyper::client::Client::new(); - let result = client.request(req).await.unwrap(); - assert!(result.status() == 200); -} diff --git a/webhook/src/handler/tests/handler_integration.rs b/webhook/src/handler/tests/handler_integration.rs new file mode 100644 index 0000000..6aee0bd --- /dev/null +++ b/webhook/src/handler/tests/handler_integration.rs @@ -0,0 +1,213 @@ +use std::time::Duration; + +use crate::{ + config::Config, + handler::tests::utils::{generate_keypair, sign_message}, + start, +}; +use common::{config::test_init, nats_crate::Connection}; +use common::{ + config::Settings, + log::info, + testcontainers::{clients::Cli, images::generic::GenericImage, Container, Docker}, +}; +use hyper::{Body, Method, Request}; +use lazy_static::{__Deref, lazy_static}; +use serde_json::json; + +lazy_static! { + static ref DOCKER: Cli = Cli::default(); + + static ref NATS_CONTAINER: Container<'static, Cli, GenericImage> = { + test_init(); + let image: GenericImage = GenericImage::new("nats"); + let container = DOCKER.run(image); + container.start(); + container.get_host_port(4222).unwrap(); + container + }; + + static ref KEYPAIR: (String, [u8; 64]) = { + generate_keypair() + }; + + static ref SETTINGS: Settings = { + let port = NATS_CONTAINER.get_host_port(4222).unwrap(); + common::config::Settings { + config: crate::config::Config { + server: crate::config::ServerSettings { + port: 5003, + address: "0.0.0.0".to_string(), + }, + discord: crate::config::Discord { + public_key: KEYPAIR.0.clone(), + client_id: 0, + }, + }, + redis: common::redis::RedisConfiguration { + url: "".to_string(), + }, + monitoring: common::monitoring::MonitoringConfiguration { + enabled: false, + address: None, + port: None, + }, + nats: common::nats::NatsConfiguration { + client_cert: None, + root_cert: None, + jetstream_api_prefix: None, + max_reconnects: None, + reconnect_buffer_size: None, + tls: None, + client_name: None, + tls_required: None, + host: format!("localhost:{}", port), + }, + } + }; + + static ref TASK: () = { + std::thread::spawn(|| { + let r = tokio::runtime::Runtime::new().unwrap(); + r.spawn(async { start(SETTINGS.clone()).await }); + loop {} + }); + std::thread::sleep(Duration::from_secs(1)); + }; +} + +#[tokio::test] +async fn respond_to_pings() { + let _ = NATS_CONTAINER.deref(); + let _ = TASK.deref(); + let ping = json!({ "type": 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 req = Request::builder() + .method(Method::POST) + .uri("http://localhost:5003/") + .header("X-Signature-Ed25519", signature) + .header("X-Signature-Timestamp", timestamp) + .body(Body::from(ping.clone())) + .expect("request builder"); + let client = hyper::client::Client::new(); + let result = client.request(req).await.unwrap(); + + assert!(result.status() == 200); +} + +#[tokio::test] +async fn deny_invalid_signatures() { + let _ = NATS_CONTAINER.deref(); + let _ = TASK.deref(); + let ping = json!({ "type": 1 }).to_string(); + let timestamp = "my datetime :)"; + + let req = Request::builder() + .method(Method::POST) + .uri("http://localhost:5003/") + .header("X-Signature-Ed25519", "inva&lid signature :)") + .header("X-Signature-Timestamp", timestamp) + .body(Body::from(ping.clone())) + .expect("request builder"); + let client = hyper::client::Client::new(); + let result = client.request(req).await.unwrap(); + assert!(result.status() == 401); +} + +#[tokio::test] +async fn response_500_when_no_nats_response() { + let _ = NATS_CONTAINER.deref(); + let _ = TASK.deref(); + let ping = json!({ "type": 0 }).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); + + // we must timeout + let req = Request::builder() + .method(Method::POST) + .uri("http://localhost:5003/") + .header("X-Signature-Ed25519", signature) + .header("X-Signature-Timestamp", timestamp) + .body(Body::from(ping.clone())) + .expect("request builder"); + + let client = hyper::client::Client::new(); + let result = client.request(req).await.unwrap(); + assert!(result.status() == 500); +} + +#[tokio::test] +async fn respond_from_nats_response() { + let _ = NATS_CONTAINER.deref(); + let _ = TASK.deref(); + let nats: Connection = SETTINGS.clone().nats.into(); + let sub = nats.subscribe("nova.cache.dispatch.interaction").unwrap(); + let ping = json!({ "type": 0 }).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); + + sub.with_handler(move |msg| { + info!("Received {}", &msg); + msg.respond("ok :)").unwrap(); + Ok(()) + }); + + let req = Request::builder() + .method(Method::POST) + .uri("http://localhost:5003/") + .header("X-Signature-Ed25519", signature) + .header("X-Signature-Timestamp", timestamp) + .body(Body::from(ping.clone())) + .expect("request builder"); + let client = hyper::client::Client::new(); + let result = client.request(req).await.unwrap(); + assert!(result.status() == 200); +} + +#[tokio::test] +async fn response_400_when_invalid_json_body() { + let _ = TASK.deref(); + 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 req = Request::builder() + .method(Method::POST) + .uri("http://localhost:5003/") + .header("X-Signature-Ed25519", signature) + .header("X-Signature-Timestamp", timestamp) + .body(Body::from(ping.clone())) + .expect("request builder"); + let client = hyper::client::Client::new(); + let result = client.request(req).await.unwrap(); + assert!(result.status() == 400); +} + + +#[tokio::test] +async fn response_400_when_invalid_utf8_body() { + let _ = TASK.deref(); + // invalid 2 octet sequence + let ping = vec![0xc3, 0x28]; + + 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 req = Request::builder() + .method(Method::POST) + .uri("http://localhost:5003/") + .header("X-Signature-Ed25519", signature) + .header("X-Signature-Timestamp", timestamp) + .body(Body::from(ping.clone())) + .expect("request builder"); + let client = hyper::client::Client::new(); + let result = client.request(req).await.unwrap(); + assert!(result.status() == 400); +} diff --git a/webhook/src/handler/tests/mod.rs b/webhook/src/handler/tests/mod.rs index ef7d850..589ad52 100644 --- a/webhook/src/handler/tests/mod.rs +++ b/webhook/src/handler/tests/mod.rs @@ -1 +1,4 @@ -pub mod handler; \ No newline at end of file +pub mod handler_integration; +pub mod signature; +pub mod utils; +pub mod handler; diff --git a/webhook/src/handler/tests/signature.rs b/webhook/src/handler/tests/signature.rs new file mode 100644 index 0000000..475e446 --- /dev/null +++ b/webhook/src/handler/tests/signature.rs @@ -0,0 +1,30 @@ +use crate::handler::signature::validate_signature; + + +#[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)) +} + +#[test] +fn validate_signature_reverse_test() { + let signature = "543ec3547d57f9ddb1ec4c5c36503ebf288ffda3da3d510764c9a49c2abb57690ef974c63d174771bdd2481de1066966f57abbec12a3ec171b9f6e2373837002"; + let public_key = "c029eea18437292c87c62aec34e7d1bd4e38fe6126f3f7c446de6375dc666044"; + let content = "ceci est un test qui ne fonctionnera pas!" + .as_bytes() + .to_vec(); + assert!(!validate_signature(public_key, &content, signature)) +} + +#[test] +fn invalid_hex() { + let signature = "zzz"; + let public_key = "zzz"; + let content = "ceci est un test qui ne fonctionnera pas!" + .as_bytes() + .to_vec(); + 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 new file mode 100644 index 0000000..f8cdac2 --- /dev/null +++ b/webhook/src/handler/tests/utils.rs @@ -0,0 +1,46 @@ +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; + + 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 sign_message( + msg: Vec, + sk: [u8; libsodium_sys::crypto_sign_ed25519_SECRETKEYBYTES as usize], +) -> 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); +} \ No newline at end of file diff --git a/webhook/src/main.rs b/webhook/src/main.rs index b213e9d..eef4751 100644 --- a/webhook/src/main.rs +++ b/webhook/src/main.rs @@ -15,6 +15,7 @@ async fn main() { } async fn start(settings: Settings) { + let addr = format!( "{}:{}", settings.config.server.address, settings.config.server.port @@ -36,6 +37,6 @@ async fn start(settings: Settings) { }); if let Err(e) = server.await { - panic!("server error: {}", e); + error!("server error: {}", e); } }