Skip to content

Commit 4154ad1

Browse files
committed
use ed25519-dalek fork with digest verifier
1 parent f040265 commit 4154ad1

File tree

2 files changed

+24
-25
lines changed

2 files changed

+24
-25
lines changed

actix-web-lab/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ actix-web = { version = "4", features = ["rustls-0_23"] }
7575
async_zip = { version = "0.0.17", features = ["deflate", "tokio"] }
7676
base64 = "0.22"
7777
digest = "0.10"
78-
ed25519-dalek = "2"
78+
ed25519-dalek = { git = "https://github.com/robjtede/ed25519-dalek.git", branch = "verify-digest" }
7979
env_logger = "0.11"
8080
futures-util = { version = "0.3.17", default-features = false, features = ["std", "io"] }
8181
generic-array = "0.14"

actix-web-lab/examples/discord_webhook.rs

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ use actix_web::{
88
App, Error, HttpRequest, HttpServer,
99
};
1010
use actix_web_lab::extract::{Json, RequestSignature, RequestSignatureScheme};
11+
use async_trait::async_trait;
1112
use bytes::{BufMut as _, BytesMut};
12-
use ed25519_dalek::{Signature, Verifier as _, VerifyingKey};
13+
use ed25519_dalek::{PublicKey, Signature, StreamVerifier, Verifier as _, VerifyingKey};
1314
use hex_literal::hex;
1415
use once_cell::sync::Lazy;
1516
use rustls::{pki_types::PrivateKeyDer, ServerConfig};
@@ -24,13 +25,16 @@ static TS_HDR_NAME: HeaderName = HeaderName::from_static("x-signature-timestamp"
2425
static APP_PUBLIC_KEY: Lazy<VerifyingKey> =
2526
Lazy::new(|| VerifyingKey::from_bytes(APP_PUBLIC_KEY_BYTES).unwrap());
2627

28+
/// Signature scheme for Discord interactions/webhooks.
29+
///
30+
/// Verification is done in `finalize` so this does not support optional verification.
2731
#[derive(Debug)]
2832
struct DiscordWebhook {
2933
/// Signature taken from webhook request header.
3034
candidate_signature: Signature,
3135

32-
/// Cloned payload state.
33-
chunks: Vec<Bytes>,
36+
/// Signature verifier.
37+
verifier: StreamVerifier,
3438
}
3539

3640
impl DiscordWebhook {
@@ -58,50 +62,44 @@ impl DiscordWebhook {
5862
}
5963

6064
impl RequestSignatureScheme for DiscordWebhook {
61-
type Signature = (BytesMut, Signature);
65+
type Signature = Signature;
6266

6367
type Error = Error;
6468

6569
async fn init(req: &HttpRequest) -> Result<Self, Self::Error> {
6670
let ts = Self::get_timestamp(req)?.to_owned();
6771
let candidate_signature = Self::get_signature(req)?;
6872

73+
let mut verifier = APP_PUBLIC_KEY
74+
.verify_stream(&candidate_signature)
75+
.map_err(error::ErrorBadRequest)?;
76+
77+
verifier.update(ts);
78+
6979
Ok(Self {
7080
candidate_signature,
71-
chunks: vec![Bytes::from(ts)],
81+
verifier,
7282
})
7383
}
7484

7585
async fn consume_chunk(&mut self, _req: &HttpRequest, chunk: Bytes) -> Result<(), Self::Error> {
76-
self.chunks.push(chunk);
86+
self.verifier.update(chunk);
7787
Ok(())
7888
}
7989

8090
async fn finalize(self, _req: &HttpRequest) -> Result<Self::Signature, Self::Error> {
81-
let buf_len = self.chunks.iter().map(|chunk| chunk.len()).sum();
82-
let mut buf = BytesMut::with_capacity(buf_len);
83-
84-
for chunk in self.chunks {
85-
buf.put(chunk);
86-
}
91+
self.verifier.finalize_and_verify().map_err(|_| {
92+
error::ErrorUnauthorized("given signature does not match calculated signature")
93+
})?;
8794

88-
Ok((buf, self.candidate_signature))
95+
Ok(self.candidate_signature)
8996
}
9097

9198
fn verify(
92-
(payload, candidate_signature): Self::Signature,
99+
signature: Self::Signature,
93100
_req: &HttpRequest,
94101
) -> Result<Self::Signature, Self::Error> {
95-
if APP_PUBLIC_KEY
96-
.verify(&payload, &candidate_signature)
97-
.is_ok()
98-
{
99-
Ok((payload, candidate_signature))
100-
} else {
101-
Err(error::ErrorUnauthorized(
102-
"given signature does not match calculated signature",
103-
))
104-
}
102+
Ok(signature)
105103
}
106104
}
107105

@@ -119,6 +117,7 @@ async fn main() -> io::Result<()> {
119117
let (Json(form), _) = body.into_parts();
120118
println!("{}", serde_json::to_string_pretty(&form).unwrap());
121119

120+
// reply with PONG code
122121
web::Json(serde_json::json!({
123122
"type": 1
124123
}))

0 commit comments

Comments
 (0)