Created
February 28, 2023 06:39
-
-
Save seungjin/f706bca4137d236d6076938dc779ca7a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use base64::{engine::general_purpose, Engine as _}; | |
use chrono::Utc; | |
use http::HeaderMap; | |
use openssl::hash::MessageDigest; | |
use openssl::pkey::{PKey, Private}; | |
use openssl::sha::Sha256; | |
use openssl::sign::Signer; | |
use std::collections::HashMap; | |
use std::fs; | |
use toolbelt::http_request as hr; | |
pub async fn send() { | |
let document = read_file(); | |
let date = Utc::now().format("%a, %d %b %Y %H:%M:%S GMT").to_string(); | |
let mut hasher = Sha256::new(); | |
hasher.update(document.as_bytes()); | |
let digest = format! {"SHA-256={}", | |
general_purpose::STANDARD.encode(hasher.finish()) | |
}; | |
let signed_string = format!( | |
"(request-target): post /inbox\nhost: mstd.seungjin.net\ndate: {}\ndigest: {}", | |
date, digest | |
); | |
let signature = signature(signed_string); | |
/* | |
In ruby | |
header = 'keyId="https://my-example.com/actor",headers="(request-target) host date",signature="' + signature + '"' | |
*/ | |
let sig_header = format!( | |
"keyId=\"https://ap.dev.seungjin.net/actor#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest\",signature=\"{}\"", | |
signature | |
); | |
/* | |
HTTP.headers({ 'Host': 'mastodon.social', 'Date': date, 'Signature': header }) | |
.post('https://mastodon.social/inbox', body: document) | |
*/ | |
let mut headers = HashMap::new(); | |
headers.insert("Host".to_string(), "mstd.seungjin.net".to_string()); | |
headers.insert("Date".to_string(), date); | |
headers.insert( | |
"Accept".to_string(), | |
"application/activity+json".to_string(), | |
); | |
headers.insert("Digest".to_string(), digest); | |
headers.insert("Signature".to_string(), sig_header); | |
let a = hr::post( | |
"https://mstd.seungjin.net/inbox".to_string(), | |
headers, | |
document, | |
) | |
.await | |
.unwrap(); | |
println!("Status: {:#?}", a.status()); | |
} | |
pub fn read_file() -> String { | |
let file_path = "./create-hello-world.json"; | |
fs::read_to_string(file_path).expect("should have been able to read the file") | |
} | |
fn keypair() -> PKey<Private> { | |
// OpenSSL::PKey::RSA.new(File.read('private.pem')) in Ruby | |
let priv_pem = fs::read("./private.pem").unwrap(); | |
PKey::private_key_from_pem(&priv_pem).unwrap() | |
} | |
fn signature(signed_signature: String) -> String { | |
let keypair = keypair(); | |
// signature = Base64.strict_encode64( | |
// keypair.sign(OpenSSL::Digest::SHA256.new, signed_string) | |
// ) in Ruby | |
let mut signer = Signer::new(MessageDigest::sha256(), &keypair).unwrap(); | |
signer.update(signed_signature.as_bytes()).unwrap(); | |
let signature = signer.sign_to_vec().unwrap(); | |
// Encode the signature as a base64 string | |
let encoded_signature = general_purpose::STANDARD.encode(&signature); | |
encoded_signature | |
} | |
mod test { | |
use super::*; | |
#[tokio::test] | |
async fn test_send() { | |
send().await; | |
} | |
#[test] | |
fn test_signature() { | |
signature("rasars".to_owned()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment