mirror of
https://github.com/System-End/slack-morphism-rust.git
synced 2026-04-19 19:45:13 +00:00
Drop dependency on ring (#306)
This commit is contained in:
parent
8c8b07e19c
commit
9d67410192
2 changed files with 39 additions and 40 deletions
|
|
@ -22,7 +22,7 @@ path = "src/lib.rs"
|
|||
|
||||
[features]
|
||||
default = []
|
||||
signature-verifier = ["dep:ring"]
|
||||
signature-verifier = ["dep:sha2", "dep:subtle", "dep:hmac"]
|
||||
hyper = ["dep:tokio", "dep:http-body-util", "dep:hyper", "dep:hyper-rustls", "dep:hyper-util", "dep:tokio-stream", "dep:tokio-tungstenite", "dep:signal-hook", "dep:signal-hook-tokio", "signature-verifier"]
|
||||
axum = ["hyper", "dep:axum", "dep:tower"]
|
||||
|
||||
|
|
@ -38,7 +38,6 @@ futures-locks = "0.7"
|
|||
base64 = "0.22"
|
||||
hex = "0.4"
|
||||
tracing = "0.1"
|
||||
ring = { version = "0.17", optional = true }
|
||||
lazy_static = "1.4"
|
||||
http = "1.1"
|
||||
async-trait = "0.1"
|
||||
|
|
@ -58,6 +57,9 @@ hyper-rustls = { version = "0.27", features = ["rustls-native-certs", "http2"],
|
|||
tokio-tungstenite = { version = "0.26.0", features = ["rustls-tls-native-roots"], optional = true }
|
||||
axum = { version = "0.8", optional = true }
|
||||
tower = { version = "0.5", optional = true }
|
||||
sha2 = { version = "0.10", optional = true }
|
||||
subtle = { version = "2.6", optional = true }
|
||||
hmac = { version = "0.12", optional = true }
|
||||
|
||||
[target.'cfg(not(windows))'.dependencies]
|
||||
signal-hook = { version = "0.3", default-features = false, features = ["extended-siginfo"], optional = true }
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
use crate::models::SlackSigningSecret;
|
||||
use ring::hmac;
|
||||
use hmac::{Hmac, Mac};
|
||||
use rsb_derive::Builder;
|
||||
use rvstruct::*;
|
||||
use sha2::Sha256;
|
||||
use std::error::Error;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use subtle::ConstantTimeEq;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SlackEventSignatureVerifier {
|
||||
secret_len: usize,
|
||||
key: hmac::Key,
|
||||
secret_bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
impl SlackEventSignatureVerifier {
|
||||
|
|
@ -16,19 +17,19 @@ impl SlackEventSignatureVerifier {
|
|||
pub const SLACK_SIGNED_TIMESTAMP: &'static str = "x-slack-request-timestamp";
|
||||
|
||||
pub fn new(secret: &SlackSigningSecret) -> Self {
|
||||
let secret_bytes = secret.value().as_bytes();
|
||||
SlackEventSignatureVerifier {
|
||||
secret_len: secret_bytes.len(),
|
||||
key: hmac::Key::new(hmac::HMAC_SHA256, secret_bytes),
|
||||
}
|
||||
let secret_bytes = secret.value().as_bytes().to_vec();
|
||||
SlackEventSignatureVerifier { secret_bytes }
|
||||
}
|
||||
|
||||
fn sign<'a, 'b>(&'a self, body: &'b str, ts: &'b str) -> String {
|
||||
let data_to_sign = format!("v0:{ts}:{body}");
|
||||
format!(
|
||||
"v0={}",
|
||||
hex::encode(hmac::sign(&self.key, data_to_sign.as_bytes()))
|
||||
)
|
||||
let mut mac = Hmac::<Sha256>::new_from_slice(&self.secret_bytes)
|
||||
.expect("HMAC can take key of any size");
|
||||
mac.update(b"v0:");
|
||||
mac.update(ts.as_bytes());
|
||||
mac.update(b":");
|
||||
mac.update(body.as_bytes());
|
||||
let result = mac.finalize().into_bytes();
|
||||
format!("v0={}", hex::encode(result))
|
||||
}
|
||||
|
||||
pub fn verify<'b>(
|
||||
|
|
@ -37,25 +38,25 @@ impl SlackEventSignatureVerifier {
|
|||
body: &'b str,
|
||||
ts: &'b str,
|
||||
) -> Result<(), SlackEventSignatureVerifierError> {
|
||||
if self.secret_len == 0 {
|
||||
if self.secret_bytes.is_empty() {
|
||||
Err(SlackEventSignatureVerifierError::CryptoInitError(
|
||||
SlackEventSignatureCryptoInitError::new("secret key is empty".into()),
|
||||
))
|
||||
} else {
|
||||
let hash_to_check = self.sign(body, ts);
|
||||
ring::constant_time::verify_slices_are_equal(hash_to_check.as_bytes(), hash.as_bytes())
|
||||
.map_err(|_| {
|
||||
SlackEventSignatureVerifierError::WrongSignatureError(
|
||||
SlackEventWrongSignatureErrorInit {
|
||||
body_len: body.len(),
|
||||
ts: ts.into(),
|
||||
received_hash: hash.into(),
|
||||
generated_hash: hash_to_check,
|
||||
}
|
||||
.into(),
|
||||
)
|
||||
})?;
|
||||
Ok(())
|
||||
if hash_to_check.as_bytes().ct_eq(hash.as_bytes()).unwrap_u8() == 1 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(SlackEventSignatureVerifierError::WrongSignatureError(
|
||||
SlackEventWrongSignatureErrorInit {
|
||||
body_len: body.len(),
|
||||
ts: ts.into(),
|
||||
received_hash: hash.into(),
|
||||
generated_hash: hash_to_check,
|
||||
}
|
||||
.into(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -140,10 +141,9 @@ impl Error for SlackEventWrongSignatureError {}
|
|||
|
||||
#[test]
|
||||
fn check_signature_success() {
|
||||
let rng = ring::rand::SystemRandom::new();
|
||||
let key_value: [u8; ring::digest::SHA256_OUTPUT_LEN] =
|
||||
ring::rand::generate(&rng).unwrap().expose();
|
||||
let key_str: String = hex::encode(key_value);
|
||||
use sha2::Digest;
|
||||
|
||||
let key_str: String = hex::encode(Sha256::digest("test-key"));
|
||||
|
||||
let verifier = SlackEventSignatureVerifier::new(&key_str.into());
|
||||
|
||||
|
|
@ -186,13 +186,10 @@ fn check_empty_secret_error_test() {
|
|||
|
||||
#[test]
|
||||
fn check_signature_error() {
|
||||
let rng = ring::rand::SystemRandom::new();
|
||||
let key_value_correct: [u8; ring::digest::SHA256_OUTPUT_LEN] =
|
||||
ring::rand::generate(&rng).unwrap().expose();
|
||||
let key_value_malicious: [u8; ring::digest::SHA256_OUTPUT_LEN] =
|
||||
ring::rand::generate(&rng).unwrap().expose();
|
||||
let key_str_correct: String = hex::encode(key_value_correct);
|
||||
let key_str_malicious: String = hex::encode(key_value_malicious);
|
||||
use sha2::Digest;
|
||||
|
||||
let key_str_correct: String = hex::encode(Sha256::digest("correct-key"));
|
||||
let key_str_malicious: String = hex::encode(Sha256::digest("malicious-key"));
|
||||
|
||||
let verifier_correct = SlackEventSignatureVerifier::new(&key_str_correct.into());
|
||||
let verifier_malicious = SlackEventSignatureVerifier::new(&key_str_malicious.into());
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue