]> git.puffer.fish Git - matthieu/nova.git/commitdiff
update webhook signatures
authorMatthieu <matthieu@developershouse.xyz>
Tue, 7 Sep 2021 18:09:55 +0000 (22:09 +0400)
committerMatthieu <matthieu@developershouse.xyz>
Tue, 7 Sep 2021 18:09:55 +0000 (22:09 +0400)
Cargo.lock
cargo/crates.bzl
webhook/Cargo.toml
webhook/cargo/BUILD.bazel
webhook/config/default.yaml
webhook/src/handle.rs

index 59e777d77f7d393ae6352f7115da39720630c35c..e229d201c25e6cd23f911a4ae660e97caff07da8 100644 (file)
@@ -338,6 +338,12 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
 [[package]]
 name = "http"
 version = "0.2.4"
@@ -1546,13 +1552,14 @@ dependencies = [
 name = "webhook"
 version = "0.1.0"
 dependencies = [
- "base64",
  "config",
+ "hex",
  "hyper",
  "libsodium-sys",
  "log",
  "pretty_env_logger",
  "serde 1.0.130",
+ "serde_json",
  "tokio",
 ]
 
index 1495d5f7131e373b132ba7d02b533386dcb05906..c090acbb4a2715ca4937f24102cfee00efaa5ee2 100644 (file)
@@ -19,6 +19,7 @@ _DEPENDENCIES = {
         "log": "@raze__log__0_4_14//:log",
         "pretty_env_logger": "@raze__pretty_env_logger__0_4_0//:pretty_env_logger",
         "serde": "@raze__serde__1_0_130//:serde",
+        "serde_json": "@raze__serde_json__1_0_67//:serde_json",
         "tokio": "@raze__tokio__1_11_0//:tokio",
     },
     "ratelimiter": {
index 0855804349c05407581c2a412c0d2d6d231180c8..2df8dff8a9ae2e0c4253780c4e02f9e82edd0ed2 100644 (file)
@@ -10,8 +10,9 @@ log = { version = "0.4", features = ["std"] }
 config = "0.11"
 serde = { version = "1.0.8", features = ["derive"] }
 libsodium-sys = "0.2.7"
-base64 = "0.13.0"
+hex = "0.4.3"
 pretty_env_logger = "0.4"
+serde_json = { version = "1.0" }
 
 [[bin]]
 name = "webhook"
index 414043304742e798e0d31bdb2c27f3016fffcd74..f65c3b784120d08df60a35a4c534508c098dde1c 100644 (file)
@@ -75,6 +75,15 @@ alias(
     ],
 )
 
+alias(
+    name = "serde_json",
+    actual = "@raze__serde_json__1_0_67//:serde_json",
+    tags = [
+        "cargo-raze",
+        "manual",
+    ],
+)
+
 alias(
     name = "tokio",
     actual = "@raze__tokio__1_11_0//:tokio",
index acaccab5afbbc35ec9c559cae48c74ef3a99b2b5..10128a046ae6d949308cbb74a823937ccb80735f 100644 (file)
@@ -1,3 +1,3 @@
 server:
   address: "0.0.0.0"
-  port: 80
\ No newline at end of file
+  port: 8000
\ No newline at end of file
index 122fec7bceac1422533446f324df7a71bee90f9a..ef3ebe11cc5da33a080574583ee9c236c35946c1 100644 (file)
@@ -1,27 +1,22 @@
 use hyper::service::Service;
-use hyper::{
-    body::{to_bytes, Bytes},
-    HeaderMap,
-};
+use hyper::{body::to_bytes, HeaderMap};
 use hyper::{Body, Method, Request, Response, StatusCode};
 use libsodium_sys::crypto_sign_ed25519_verify_detached;
 use log::info;
+use serde_json::Value;
 use std::future;
 use std::future::Future;
 use std::pin::Pin;
+use std::str::from_utf8;
 use std::task::{Context, Poll};
+use serde::{Deserialize, Serialize};
 
 use super::utils::Settings;
 
-static NOT_FOUND: &str = "
-<h1>Nova Webhook Gateway</h1>
-<p>Invalid request</p>
-";
-
-pub fn validate_signature(b64_public_key: &str, data: &Bytes, b64_signature: &str) -> bool {
+pub fn validate_signature(b64_public_key: &str, data: &Vec<u8>, b64_signature: &str) -> bool {
     // First, we need to check if the signature & private key is valid base64.
-    let signature_result = base64::decode(b64_signature);
-    let public_key_result = base64::decode(b64_public_key);
+    let signature_result = hex::decode(b64_signature);
+    let public_key_result = hex::decode(b64_public_key);
 
     if signature_result.is_ok() && public_key_result.is_ok() {
         // Since we now have the signatures in u8 vectors. We will initialize all the
@@ -47,7 +42,7 @@ pub fn validate_signature(b64_public_key: &str, data: &Bytes, b64_signature: &st
     false
 }
 
-fn get_signature<'b>(headers: &'b HeaderMap) -> Option<(&'b str, &'b str)> {
+fn get_signature(headers: &HeaderMap) -> Option<(&str, &str)> {
     let signature = headers.get("X-Signature-Ed25519");
     let timestamp = headers.get("X-Signature-Timestamp");
 
@@ -64,6 +59,12 @@ pub struct HandlerService {
     pub config: Settings,
 }
 
+#[derive(Debug, Serialize, Deserialize)]
+pub struct Ping {
+    #[serde(rename = "type")]
+    t: i32
+}
+
 impl Service<Request<Body>> for HandlerService {
     type Response = Response<Body>;
     type Error = hyper::Error;
@@ -78,24 +79,37 @@ impl Service<Request<Body>> for HandlerService {
             let public_key = self.config.discord.public_key.clone();
             return Box::pin(async move {
                 let headers = req.headers().clone();
-                let sig_headers = get_signature(&headers);
-                if sig_headers.is_some() {
-                    let (signature, _timestamp) = sig_headers.unwrap();
-                    let data = to_bytes(req.into_body()).await.unwrap();
-                    info!("data: {}", public_key);
-                    if validate_signature(public_key.as_str(), &data, signature) {
-                        return Ok(Response::new("signature verified!".into()));
+                if let Some((signature, timestamp)) = get_signature(&headers) {
+                    if let Ok(data) = to_bytes(req.into_body()).await {
+                        let contatenated_data = [timestamp.as_bytes().to_vec(), data.to_vec()].concat();
+
+                        if validate_signature(public_key.as_str(), &contatenated_data, signature) {
+                            let data: Value = serde_json::from_str(from_utf8(&data).unwrap()).unwrap();
+                            let t = data.get("type").unwrap().as_i64().unwrap();
+
+                            if t == 1 {
+                                info!("success!");
+                                
+                                return Ok(Response::builder().header("Content-Type", "application/json").body(serde_json::to_string(&Ping {
+                                    t: 1
+                                }).unwrap().into()).unwrap());
+                                
+                            } else {
+                                Ok(Response::builder().status(StatusCode::UNAUTHORIZED).body("invalid operation".into()).unwrap())
+                            }
+                        } else {
+                            Ok(Response::builder().status(StatusCode::UNAUTHORIZED).body("signature verification failed".into()).unwrap())
+                        }
+                    } else {
+                        Ok(Response::builder().status(StatusCode::UNAUTHORIZED).body("failed to read body".into()).unwrap())
                     }
-                    return Ok(Response::new("signature verification failed.".into()));
+                } else {
+                    Ok(Response::builder().status(StatusCode::UNAUTHORIZED).body("no signature specified".into()).unwrap())
                 }
-                return Ok(Response::new("no signature specified.".into()));
             });
         } else {
             return Box::pin(async {
-                let mut response = Response::new(NOT_FOUND.into());
-                let status = response.status_mut();
-                *status = StatusCode::BAD_REQUEST;
-                Ok(response)
+                Ok(Response::builder().status(StatusCode::UNAUTHORIZED).body("bad method".into()).unwrap())
             });
         }
     }
@@ -124,41 +138,32 @@ impl<T> Service<T> for MakeSvc {
 #[cfg(test)]
 mod test {
     use crate::handle::validate_signature;
-    use hyper::body::Bytes;
 
     #[test]
     fn validate_signature_test() {
         let signature = "VD7DVH1X+d2x7ExcNlA+vyiP/aPaPVEHZMmknCq7V2kO+XTGPRdHcb3SSB3hBmlm9Xq77BKj7Bcbn24jc4NwAg==";
         let public_key = "7v4MJEc3N8sgNSMuO065HCBvChRoQWjzUD99gxYFjW8=";
-        let content = "message de test incroyable";
-        assert!(validate_signature(
-            public_key,
-            &Bytes::from(content),
-            signature
-        ))
+        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 = "VD7DVH1X+d2x7ExcNlA+vyiP/aPaPVEHZMmknCq7V2kO+XTGPRdHcb3SSB3hBmlm9Xq77BKj7Bcbn24jc4NwAg==";
         let public_key = "wCnuoYQ3KSyHxirsNOfRvU44/mEm8/fERt5jddxmYEQ=";
-        let content = "ceci est un test qui ne fonctionnera pas!";
-        assert!(!validate_signature(
-            public_key,
-            &Bytes::from(content),
-            signature
-        ))
+        let content = "ceci est un test qui ne fonctionnera pas!"
+            .as_bytes()
+            .to_vec();
+        assert!(!validate_signature(public_key, &content, signature))
     }
 
     #[test]
     fn invalid_base64() {
         let signature = "zzz";
         let public_key = "zzz";
-        let content = "ceci est un test qui ne fonctionnera pas!";
-        assert!(!validate_signature(
-            public_key,
-            &Bytes::from(content),
-            signature
-        ))
+        let content = "ceci est un test qui ne fonctionnera pas!"
+            .as_bytes()
+            .to_vec();
+        assert!(!validate_signature(public_key, &content, signature))
     }
 }