Plume/plume-common/src/activity_pub/request.rs

87 lines
2.6 KiB
Rust
Raw Normal View History

2018-05-04 17:18:00 +02:00
use base64;
use openssl::hash::{Hasher, MessageDigest};
use reqwest::{
mime::Mime,
2018-07-18 16:58:28 +02:00
header::{Accept, Date, Headers, UserAgent, qitem}
};
2018-10-03 09:31:38 +02:00
use std::ops::Deref;
use std::time::SystemTime;
2018-05-04 17:18:00 +02:00
2018-07-18 16:58:28 +02:00
use activity_pub::ap_accept_header;
2018-05-04 17:18:00 +02:00
use activity_pub::sign::Signer;
const USER_AGENT: &'static str = concat!("Plume/", env!("CARGO_PKG_VERSION"));
2018-05-04 17:18:00 +02:00
header! {
(Signature, "Signature") => [String]
}
header! {
(Digest, "Digest") => [String]
}
2018-10-03 09:31:38 +02:00
impl Digest {
pub fn digest(body: String) -> Self {
let mut hasher = Hasher::new(MessageDigest::sha256()).unwrap();
hasher.update(&body.into_bytes()[..]).unwrap();
let res = base64::encode(&hasher.finish().unwrap());
Digest(format!("SHA-256={}", res))
}
pub fn verify(&self, body: String) -> bool {
if self.algorithm()=="SHA-256" {
let mut hasher = Hasher::new(MessageDigest::sha256()).unwrap();
hasher.update(&body.into_bytes()).unwrap();
self.value().deref()==hasher.finish().unwrap().deref()
} else {
false //algorithm not supported
}
}
pub fn algorithm(&self) -> &str {
let pos = self.0.find('=').unwrap();
&self.0[..pos]
}
pub fn value(&self) -> Vec<u8> {
let pos = self.0.find('=').unwrap()+1;
base64::decode(&self.0[pos..]).unwrap()
}
pub fn from_header(dig: &str) -> Result<Self, ()> {
if let Some(pos) = dig.find('=') {
let pos = pos+1;
if let Ok(_) = base64::decode(&dig[pos..]) {
Ok(Digest(dig.to_owned()))
} else {
Err(())
}
} else {
Err(())
}
}
}
2018-05-04 17:18:00 +02:00
pub fn headers() -> Headers {
let mut headers = Headers::new();
headers.set(UserAgent::new(USER_AGENT));
headers.set(Date(SystemTime::now().into()));
2018-07-18 16:58:28 +02:00
headers.set(Accept(ap_accept_header().into_iter().map(|h| qitem(h.parse::<Mime>().expect("Invalid Content-Type"))).collect()));
2018-05-04 17:18:00 +02:00
headers
}
pub fn signature<S: Signer>(signer: &S, headers: Headers) -> Signature {
2018-05-04 17:18:00 +02:00
let signed_string = headers.iter().map(|h| format!("{}: {}", h.name().to_lowercase(), h.value_string())).collect::<Vec<String>>().join("\n");
let signed_headers = headers.iter().map(|h| h.name().to_string()).collect::<Vec<String>>().join(" ").to_lowercase();
2018-05-04 17:18:00 +02:00
let data = signer.sign(signed_string);
let sign = base64::encode(&data[..]);
2018-05-04 17:18:00 +02:00
Signature(format!(
"keyId=\"{key_id}\",algorithm=\"rsa-sha256\",headers=\"{signed_headers}\",signature=\"{signature}\"",
key_id = signer.get_key_id(),
2018-05-04 17:18:00 +02:00
signed_headers = signed_headers,
signature = sign
))
}