Hi,
I'm trying to implement in rocket 0.4 a Webhook, and the header will contains a encrypted key.
I have to validate that key given datas, and I have to use the payload.
But I do not find how to convert Json into bytes.
#[post("/webhook/<property_id>", data = "<body>")]
fn t(property_id: &RawStr, body: Json<WebhookBody>, x_hook_signature: XHookSignature) {
x_hook_signature.validate(b"test", body.as_bytes());
}
pub struct XHookSignature(String);
impl XHookSignature {
pub fn validate(&self, key: &[u8], message: &[u8]) -> bool {
let hash = // encryption method with key and message that return '&[u8]';
self.0 == hash.iter().map(|b| format!("{:02x}", b)).collect::<Vec<_>>().join("")
}
}
So the body.as_byte()
does not work, and I found nothing in rocket_contrib documentation that can help me...
Have you any idea of the way to do that please ?
alice
May 26, 2022, 8:00am
2
You shouldn't use the Json<T>
utility if you need to see the raw bytes. Instead, use a body like rocket::data::Data
to get the raw bytes, validate them, then call serde
directly to have the byte array converted into a WebhookBody
object.
2 Likes
That's a good idea !
But I get a problem... The data is empty.
But with Postman I give a value :
Here's the logs :
DEBUG application::request - Decrypted mess : test
DEBUG application::request - Decrypted data :
DEBUG application::request - Hook signature : 7a7942582ceb81052b01fc52d05ac4d431f8e7db
DEBUG application::request - Encrypted data : fc85087452696e5bcbe3b7a71fde00e320af2cca
And the code :
#[post("/webhook/<agency_id>", data = "<body>")]
fn webhook(agency_id: &RawStr, body: Data, x_hook_signature: XHookSignature) -> Result<ApiResponse<()>, ApiResponse<ApiError>> {
let mut datas = vec![];
while !body.peek_complete() {
datas.extend_from_slice(body.peek());
}
if !x_hook_signature.validate(agency_id.as_bytes(), &datas[..]) {
return Err(ApiResponse::new(Status::InternalServerError, ApiError::new("Cannot validate hook signature with given datas !")));
}
let json_body: Json<WebhookBody>;
// Json::from_data(_, o: Transformed<'a, Self>);
// Json::transform(r: &Request, d: Data);
Ok(ApiResponse::new(Status::Ok, ()))
}
pub struct XHookSignature(String);
impl XHookSignature {
pub fn validate(&self, key: &[u8], message: &[u8]) -> bool {
log::debug!("Decrypted mess : {}", std::str::from_utf8(key).unwrap_or("failed to parse"));
log::debug!("Decrypted data : {}", std::str::from_utf8(message).unwrap_or("failed to parse"));
let hash = encryption method with key and message that return '&[u8]' and parsed into String;
log::debug!("Hook signature : {}", self.0);
log::debug!("Encrypted data : {}", hash);
self.0 == hash
}
}
Did I do something wrong ?
alice
May 26, 2022, 9:00am
4
I don't think you're supposed to use Data
in that way. Try this instead:
let mut datas = Vec::new();
body.stream_to(&mut datas);
Oh yeah in that way that's working ! Thank you
But about converting data into Json, I've found only two functions, and they need Request
.
Do I have to use it or are there another way, like let json_body: Json<WebhookBody> = Json(std::str::from_utf8(message).unwrap_or_default());
or something like that ?
alice
May 26, 2022, 10:12am
6
Just use the serde_json
crate directly instead of using the rocket Json
type. The serde_json::from_slice
function can do the conversion from a Vec<u8>
to your WebhookBody
type.
Thank you very much for your help !
Why don't I think the same way as you ?
Why do I always want to make it more complicated ?
For who need the implementation, here it is :
#[post("/webhook/<agency_id>", data = "<data_body>")]
fn webhook(
agency_id: &RawStr,
data_body: Data,
x_hook_signature: XHookSignature,
api_state: State<ApiState>,
) -> Result<ApiResponse<()>, ApiResponse<ApiError>> {
let mut datas = vec![];
if let Err(e) = data_body.stream_to(&mut datas) {
return Err(ApiResponse::new(
Status::InternalServerError,
ApiError::new(format!("Cannot parse given datas: {}", e)),
));
}
if !x_hook_signature.validate(agency_id.as_bytes(), &datas[..]) {
return Err(ApiResponse::new(
Status::InternalServerError,
ApiError::new("Cannot validate hook signature with given datas !"),
));
}
let body: WebhookBody = match serde_json::from_slice(&datas[..]) {
Ok(j) => j,
Err(e) => return Err(ApiResponse::new(
Status::InternalServerError,
ApiError::new(format!("Cannot parse datas as JSON object : {}", e)),
))
};
Ok(())
}
system
Closed
August 24, 2022, 11:42am
8
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.