summaryrefslogtreecommitdiff
path: root/exes/webhook/src
diff options
context:
space:
mode:
Diffstat (limited to 'exes/webhook/src')
-rw-r--r--exes/webhook/src/config.rs40
-rw-r--r--exes/webhook/src/handler/handler.rs52
-rw-r--r--exes/webhook/src/handler/make_service.rs27
-rw-r--r--exes/webhook/src/handler/mod.rs2
-rw-r--r--exes/webhook/src/handler/tests/signature.rs17
-rw-r--r--exes/webhook/src/main.rs76
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);