diff options
Diffstat (limited to 'exes/webhook/src')
| -rw-r--r-- | exes/webhook/src/config.rs | 40 | ||||
| -rw-r--r-- | exes/webhook/src/handler/handler.rs | 52 | ||||
| -rw-r--r-- | exes/webhook/src/handler/make_service.rs | 27 | ||||
| -rw-r--r-- | exes/webhook/src/handler/mod.rs | 2 | ||||
| -rw-r--r-- | exes/webhook/src/handler/tests/signature.rs | 17 | ||||
| -rw-r--r-- | exes/webhook/src/main.rs | 76 |
6 files changed, 120 insertions, 94 deletions
diff --git a/exes/webhook/src/config.rs b/exes/webhook/src/config.rs index a054d33..68f6a5f 100644 --- a/exes/webhook/src/config.rs +++ b/exes/webhook/src/config.rs @@ -1,19 +1,43 @@ -use serde::Deserialize; +use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; -#[derive(Debug, Deserialize, Clone, Default)] +use ed25519_dalek::PublicKey; +use serde::{Deserialize, Deserializer}; + +fn default_listening_address() -> SocketAddr { + SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 8080)) +} + +#[derive(Debug, Deserialize, Clone, Copy)] pub struct ServerSettings { - pub port: u16, - pub address: String, + #[serde(default = "default_listening_address")] + pub listening_adress: SocketAddr, +} +impl Default for ServerSettings { + fn default() -> Self { + Self { + listening_adress: default_listening_address(), + } + } +} + +fn deserialize_pk<'de, D>(deserializer: D) -> Result<PublicKey, D::Error> +where + D: Deserializer<'de>, +{ + let str = String::deserialize(deserializer)?; + let public_key = PublicKey::from_bytes(&hex::decode(&str).unwrap()).unwrap(); + Ok(public_key) } -#[derive(Debug, Deserialize, Clone, Default)] +#[derive(Debug, Deserialize, Clone, Default, Copy)] pub struct Discord { - pub public_key: String, + #[serde(deserialize_with = "deserialize_pk")] + pub public_key: PublicKey, pub client_id: u32, } -#[derive(Debug, Deserialize, Clone, Default)] -pub struct Config { +#[derive(Debug, Deserialize, Clone, Default, Copy)] +pub struct WebhookConfig { pub server: ServerSettings, pub discord: Discord, } diff --git a/exes/webhook/src/handler/handler.rs b/exes/webhook/src/handler/handler.rs index b2ef44c..af79185 100644 --- a/exes/webhook/src/handler/handler.rs +++ b/exes/webhook/src/handler/handler.rs @@ -1,13 +1,12 @@ use super::error::WebhookError; use super::signature::validate_signature; -use crate::config::Config; +use crate::config::WebhookConfig; use ed25519_dalek::PublicKey; use hyper::{ body::{to_bytes, Bytes}, service::Service, Body, Method, Request, Response, StatusCode, }; -use serde::{Deserialize, Serialize}; use shared::nats_crate::Client; use shared::{ log::{debug, error}, @@ -17,10 +16,9 @@ use std::{ future::Future, pin::Pin, str::from_utf8, - sync::Arc, task::{Context, Poll}, }; -use twilight_model::gateway::event::{DispatchEvent}; +use twilight_model::gateway::event::DispatchEvent; use twilight_model::{ application::interaction::{Interaction, InteractionType}, gateway::payload::incoming::InteractionCreate, @@ -28,14 +26,13 @@ use twilight_model::{ /// Hyper service used to handle the discord webhooks #[derive(Clone)] -pub struct HandlerService { - pub config: Arc<Config>, - pub nats: Arc<Client>, - pub public_key: Arc<PublicKey>, +pub struct WebhookService { + pub config: WebhookConfig, + pub nats: Client, } -impl HandlerService { - async fn check_request(&self, req: Request<Body>) -> Result<Bytes, WebhookError> { +impl WebhookService { + async fn check_request(req: Request<Body>, pk: PublicKey) -> Result<Bytes, WebhookError> { if req.method() == Method::POST { let signature = if let Some(sig) = req.headers().get("X-Signature-Ed25519") { sig.to_owned() @@ -57,7 +54,7 @@ impl HandlerService { let data = to_bytes(req.into_body()).await?; if validate_signature( - &self.public_key, + &pk, &[timestamp.as_bytes().to_vec(), data.to_vec()].concat(), signature.to_str()?, ) { @@ -74,10 +71,11 @@ impl HandlerService { } async fn process_request( - &mut self, req: Request<Body>, + nats: Client, + pk: PublicKey, ) -> Result<Response<Body>, WebhookError> { - match self.check_request(req).await { + match Self::check_request(req, pk).await { Ok(data) => { let utf8 = from_utf8(&data); match utf8 { @@ -86,7 +84,7 @@ impl HandlerService { match value.kind { InteractionType::Ping => Ok(Response::builder() .header("Content-Type", "application/json") - .body(serde_json::to_string(&Ping { t: 1 }).unwrap().into()) + .body(r#"{"t":1}"#.into()) .unwrap()), _ => { debug!("calling nats"); @@ -106,10 +104,13 @@ impl HandlerService { let payload = serde_json::to_string(&data).unwrap(); - match self.nats.request( - "nova.cache.dispatch.INTERACTION_CREATE".to_string(), - Bytes::from(payload), - ).await { + match nats + .request( + "nova.cache.dispatch.INTERACTION_CREATE".to_string(), + Bytes::from(payload), + ) + .await + { Ok(response) => Ok(Response::builder() .header("Content-Type", "application/json") .body(Body::from(response.reply.unwrap())) @@ -144,15 +145,9 @@ impl HandlerService { } } -#[derive(Debug, Serialize, Deserialize)] -pub struct Ping { - #[serde(rename = "type")] - t: i32, -} - /// Implementation of the service -impl Service<Request<Body>> for HandlerService { - type Response = Response<Body>; +impl Service<hyper::Request<Body>> for WebhookService { + type Response = hyper::Response<Body>; type Error = hyper::Error; type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>; @@ -161,9 +156,10 @@ impl Service<Request<Body>> for HandlerService { } fn call(&mut self, req: Request<Body>) -> Self::Future { - let mut clone = self.clone(); + let future = + Self::process_request(req, self.nats.clone(), self.config.discord.public_key); Box::pin(async move { - let response = clone.process_request(req).await; + let response = future.await; match response { Ok(r) => Ok(r), diff --git a/exes/webhook/src/handler/make_service.rs b/exes/webhook/src/handler/make_service.rs index 48672a1..b51494a 100644 --- a/exes/webhook/src/handler/make_service.rs +++ b/exes/webhook/src/handler/make_service.rs @@ -1,22 +1,15 @@ -use super::handler::HandlerService; -use crate::config::Config; use hyper::service::Service; -use shared::nats_crate::Client; use std::{ future::{ready, Ready}, - sync::Arc, task::{Context, Poll}, }; -use ed25519_dalek::PublicKey; -pub struct MakeSvc { - pub settings: Arc<Config>, - pub nats: Arc<Client>, - pub public_key: Arc<PublicKey> +pub struct MakeSvc<T: Clone> { + pub service: T, } -impl<T> Service<T> for MakeSvc { - type Response = HandlerService; +impl<T, V: Clone> Service<T> for MakeSvc<V> { + type Response = V; type Error = std::io::Error; type Future = Ready<Result<Self::Response, Self::Error>>; @@ -25,10 +18,12 @@ impl<T> Service<T> for MakeSvc { } fn call(&mut self, _: T) -> Self::Future { - ready(Ok(HandlerService { - config: self.settings.clone(), - nats: self.nats.clone(), - public_key: self.public_key.clone() - })) + ready(Ok(self.service.clone())) + } +} + +impl<T: Clone> MakeSvc<T> { + pub fn new(service: T) -> Self { + Self { service } } } diff --git a/exes/webhook/src/handler/mod.rs b/exes/webhook/src/handler/mod.rs index 20a977a..e4cf35a 100644 --- a/exes/webhook/src/handler/mod.rs +++ b/exes/webhook/src/handler/mod.rs @@ -1,5 +1,5 @@ mod error; -mod handler; +pub mod handler; pub mod make_service; mod signature; diff --git a/exes/webhook/src/handler/tests/signature.rs b/exes/webhook/src/handler/tests/signature.rs index 490143b..0bed86a 100644 --- a/exes/webhook/src/handler/tests/signature.rs +++ b/exes/webhook/src/handler/tests/signature.rs @@ -5,7 +5,10 @@ use ed25519_dalek::PublicKey; fn validate_signature_test() { let signature = "543ec3547d57f9ddb1ec4c5c36503ebf288ffda3da3d510764c9a49c2abb57690ef974c63d174771bdd2481de1066966f57abbec12a3ec171b9f6e2373837002"; let content = "message de test incroyable".as_bytes().to_vec(); - let public_key = PublicKey::from_bytes(&hex::decode("eefe0c24473737cb2035232e3b4eb91c206f0a14684168f3503f7d8316058d6f").unwrap()).unwrap(); + let public_key = PublicKey::from_bytes( + &hex::decode("eefe0c24473737cb2035232e3b4eb91c206f0a14684168f3503f7d8316058d6f").unwrap(), + ) + .unwrap(); assert!(validate_signature(&public_key, &content, signature)) } @@ -13,7 +16,10 @@ fn validate_signature_test() { #[test] fn validate_signature_reverse_test() { let signature = "543ec3547d57f9ddb1ec4c5c36503ebf288ffda3da3d510764c9a49c2abb57690ef974c63d174771bdd2481de1066966f57abbec12a3ec171b9f6e2373837002"; - let public_key = PublicKey::from_bytes(&hex::decode("c029eea18437292c87c62aec34e7d1bd4e38fe6126f3f7c446de6375dc666044").unwrap()).unwrap(); + let public_key = PublicKey::from_bytes( + &hex::decode("c029eea18437292c87c62aec34e7d1bd4e38fe6126f3f7c446de6375dc666044").unwrap(), + ) + .unwrap(); let content = "ceci est un test qui ne fonctionnera pas!" .as_bytes() @@ -24,10 +30,13 @@ fn validate_signature_reverse_test() { #[test] fn invalid_hex() { let signature = "zzz"; - let public_key = PublicKey::from_bytes(&hex::decode("c029eea18437292c87c62aec34e7d1bd4e38fe6126f3f7c446de6375dc666044").unwrap()).unwrap(); + 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)) -}
\ No newline at end of file +} diff --git a/exes/webhook/src/main.rs b/exes/webhook/src/main.rs index 336dd82..efd4147 100644 --- a/exes/webhook/src/main.rs +++ b/exes/webhook/src/main.rs @@ -1,45 +1,47 @@ -use std::{net::ToSocketAddrs, sync::Arc}; mod config; mod handler; -use crate::handler::make_service::MakeSvc; +use std::{future::Future, pin::Pin}; -use crate::config::Config; -use ed25519_dalek::PublicKey; +use crate::{ + config::WebhookConfig, + handler::{handler::WebhookService, make_service::MakeSvc}, +}; use hyper::Server; -use shared::config::Settings; -use shared::log::{error, info}; +use leash::{ignite, AnyhowResultFuture, Component}; +use shared::{config::Settings, log::info, nats_crate::Client}; -#[tokio::main] -async fn main() { - let settings: Settings<Config> = Settings::new("webhook").unwrap(); - start(settings).await; -} +#[derive(Clone, Copy)] +struct WebhookServer {} + +impl Component for WebhookServer { + type Config = WebhookConfig; + const SERVICE_NAME: &'static str = "webhook"; + + fn start(&self, settings: Settings<Self::Config>) -> AnyhowResultFuture<()> { + Box::pin(async move { + info!("Starting server on {}", settings.server.listening_adress); + + let bind = settings.server.listening_adress; + let nats = + Into::<Pin<Box<dyn Future<Output = anyhow::Result<Client>>>>>::into(settings.nats) + .await?; + + let make_service = MakeSvc::new(WebhookService { + config: settings.config, + nats: nats.clone(), + }); -async fn start(settings: Settings<Config>) { - let addr = format!( - "{}:{}", - settings.config.server.address, settings.config.server.port - ) - .to_socket_addrs() - .unwrap() - .next() - .unwrap(); - - info!( - "Starting server on {}:{}", - settings.config.server.address, settings.config.server.port - ); - - 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.to_client().await.unwrap()), - public_key: public_key, - }); - - if let Err(e) = server.await { - error!("server error: {}", e); + let server = Server::bind(&bind).serve(make_service); + + server.await?; + + Ok(()) + }) + } + + fn new() -> Self { + Self {} } } + +ignite!(WebhookServer); |
