Skip to content

Commit 77254a8

Browse files
committed
use ed25519-dalek fork with digest verifier
1 parent 3233ad1 commit 77254a8

File tree

2 files changed

+24
-26
lines changed

2 files changed

+24
-26
lines changed

actix-web-lab/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ tracing = { version = "0.1.30", features = ["log"] }
5757
actix-web = { version = "4", features = ["rustls"] }
5858

5959
base64 = "0.13"
60-
ed25519-dalek = "1.0.1"
6160
env_logger = "0.9"
6261
futures-util = { version = "0.3.7", default-features = false, features = ["std"] }
6362
hex = "0.4"
@@ -68,3 +67,5 @@ rustls-pemfile = "1.0.0"
6867
serde = { version = "1", features = ["derive"] }
6968
sha2 = "0.10"
7069
static_assertions = "1.1"
70+
71+
ed25519-dalek = { git = "https://github.com/robjtede/ed25519-dalek.git", branch = "verify-digest" }

actix-web-lab/examples/discord_webhook.rs

+22-25
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ use actix_web::{
1212
};
1313
use actix_web_lab::extract::{Json, RequestSignature, RequestSignatureScheme};
1414
use async_trait::async_trait;
15-
use bytes::{BufMut as _, BytesMut};
16-
use ed25519_dalek::{PublicKey, Signature, Verifier as _};
15+
use ed25519_dalek::{DigestVerifier, PublicKey, Signature};
1716
use hex_literal::hex;
1817
use once_cell::sync::Lazy;
1918
use rustls::{Certificate, PrivateKey, ServerConfig};
@@ -30,13 +29,16 @@ static SIG_HDR_NAME: Lazy<HeaderName> =
3029
static TS_HDR_NAME: Lazy<HeaderName> =
3130
Lazy::new(|| HeaderName::from_static("x-signature-timestamp"));
3231

32+
/// Signature scheme for Discord interactions/webhooks.
33+
///
34+
/// Verification is done in `finalize` so this does not support optional verification.
3335
#[derive(Debug)]
3436
struct DiscordWebhook {
3537
/// Signature taken from webhook request header.
3638
candidate_signature: Signature,
3739

38-
/// Cloned payload state.
39-
chunks: Vec<Bytes>,
40+
/// Signature verifier.
41+
verifier: DigestVerifier,
4042
}
4143

4244
impl DiscordWebhook {
@@ -65,50 +67,44 @@ impl DiscordWebhook {
6567

6668
#[async_trait(?Send)]
6769
impl RequestSignatureScheme for DiscordWebhook {
68-
type Signature = (BytesMut, Signature);
70+
type Signature = Signature;
6971

7072
type Error = Error;
7173

7274
async fn init(req: &HttpRequest) -> Result<Self, Self::Error> {
7375
let ts = Self::get_timestamp(req)?.to_owned();
7476
let candidate_signature = Self::get_signature(req)?;
7577

78+
let mut verifier = APP_PUBLIC_KEY
79+
.verify_digest(&candidate_signature)
80+
.map_err(error::ErrorBadRequest)?;
81+
82+
verifier.update(ts);
83+
7684
Ok(Self {
7785
candidate_signature,
78-
chunks: vec![Bytes::from(ts)],
86+
verifier,
7987
})
8088
}
8189

8290
async fn consume_chunk(&mut self, _req: &HttpRequest, chunk: Bytes) -> Result<(), Self::Error> {
83-
self.chunks.push(chunk);
91+
self.verifier.update(chunk);
8492
Ok(())
8593
}
8694

8795
async fn finalize(self, _req: &HttpRequest) -> Result<Self::Signature, Self::Error> {
88-
let buf_len = self.chunks.iter().map(|chunk| chunk.len()).sum();
89-
let mut buf = BytesMut::with_capacity(buf_len);
90-
91-
for chunk in self.chunks {
92-
buf.put(chunk);
93-
}
96+
self.verifier.finalize_and_verify().map_err(|_| {
97+
error::ErrorUnauthorized("given signature does not match calculated signature")
98+
})?;
9499

95-
Ok((buf, self.candidate_signature))
100+
Ok(self.candidate_signature)
96101
}
97102

98103
fn verify(
99-
(payload, candidate_signature): Self::Signature,
104+
signature: Self::Signature,
100105
_req: &HttpRequest,
101106
) -> Result<Self::Signature, Self::Error> {
102-
if APP_PUBLIC_KEY
103-
.verify(&payload, &candidate_signature)
104-
.is_ok()
105-
{
106-
Ok((payload, candidate_signature))
107-
} else {
108-
Err(error::ErrorUnauthorized(
109-
"given signature does not match calculated signature",
110-
))
111-
}
107+
Ok(signature)
112108
}
113109
}
114110

@@ -126,6 +122,7 @@ async fn main() -> io::Result<()> {
126122
let (Json(form), _) = body.into_parts();
127123
println!("{}", serde_json::to_string_pretty(&form).unwrap());
128124

125+
// reply with PONG code
129126
web::Json(serde_json::json!({
130127
"type": 1
131128
}))

0 commit comments

Comments
 (0)