|
- use rocket::data::{self, FromDataSimple};
- use rocket::http::{Status};
- use rocket::{Request, Data, Outcome};
- use std::io::Read;
- use ed25519_dalek::{Verifier, Signature};
- use crate::discord::Interaction;
-
- pub struct AuthenticatedInteraction {
- signature: String,
- timestamp: String,
- pub interaction: Interaction,
- }
-
- impl AuthenticatedInteraction {
- pub fn get_signature(&self) -> &str {
- &self.signature
- }
-
- pub fn get_timestamp(&self) -> &str {
- &self.timestamp
- }
- }
-
- impl FromDataSimple for AuthenticatedInteraction {
- type Error = ();
-
- fn from_data(request: &Request, data: Data) -> data::Outcome<Self, Self::Error> {
- let signature_opt = request.headers().get_one("x-signature-ed25519");
- let timestamp_opt = request.headers().get_one("x-signature-timestamp");
- if signature_opt.is_some() && timestamp_opt.is_some() {
- let signature = signature_opt.unwrap().to_owned();
- let timestamp = timestamp_opt.unwrap().to_owned();
- println!("signature: `{}` time: `{}`", &signature, ×tamp); // debug
- if let Ok(hex_data) = hex::decode(signature.clone()) {
- let mut buffer = [0; 64];
- for i in 0..64 { // copy hex decode into static-size buffer
- if i >= hex_data.len() { break; }
- buffer[i] = hex_data[i];
- }
- let sign = Signature::new(buffer); // requires [u8; 64]
- // validate authentication
- let mut string_buf = String::new();
- if let Ok(string_len) = data.open().take(1_000_000).read_to_string(&mut string_buf) {
- let msg = format!("{}{}", ×tamp, &string_buf[..string_len]);
- let verif_result = crate::VERIFICATION_KEY.read()
- .unwrap()
- .unwrap()
- .verify(msg.as_bytes(), &sign);
- if verif_result.is_err() {
- println!("Signature validation error");
- return Outcome::Failure((Status::Unauthorized, ()))
- }
- if let Ok(payload) = serde_json::from_str(&string_buf[..string_len]) {
- let auth = AuthenticatedInteraction {
- signature: signature.clone(),
- timestamp: timestamp.clone(),
- interaction: payload,
- };
- return Outcome::Success(auth);
- }
- println!("Invalid json payload");
- return Outcome::Failure((Status::Unauthorized, ()))
- }
- println!("Invalid body");
- return Outcome::Failure((Status::Unauthorized, ()))
- }
- println!("Invalid signature headers");
- return Outcome::Failure((Status::Unauthorized, ()))
- }
- println!("Missing signature headers");
- Outcome::Failure((Status::Unauthorized, ()))
- }
- }
|