From: Felix Date: Sun, 19 Apr 2020 11:44:44 +0000 (+0200) Subject: Simplify signing code X-Git-Url: http://these/git/%7B%60%24%7BwebArchiveUrl%7D/%22%7B%7D/%22https:/nerdica.net/readmes/README.zh.hant.md?a=commitdiff_plain;h=5284dc0c5282f878f452c96ea08643e298708d26;p=lemmy.git Simplify signing code --- diff --git a/server/src/api/community.rs b/server/src/api/community.rs index 30c8aa20..0c0ddcee 100644 --- a/server/src/api/community.rs +++ b/server/src/api/community.rs @@ -201,7 +201,7 @@ impl Perform for Oper { } // When you create a community, make sure the user becomes a moderator and a follower - let keypair = generate_actor_keypair(); + let keypair = generate_actor_keypair()?; let community_form = CommunityForm { name: data.name.to_owned(), diff --git a/server/src/api/user.rs b/server/src/api/user.rs index 35bdd33a..f42ea03a 100644 --- a/server/src/api/user.rs +++ b/server/src/api/user.rs @@ -252,7 +252,7 @@ impl Perform for Oper { return Err(APIError::err("admin_already_created").into()); } - let keypair = generate_actor_keypair(); + let keypair = generate_actor_keypair()?; // Register the new user let user_form = UserForm { @@ -296,7 +296,7 @@ impl Perform for Oper { } }; - let keypair = generate_actor_keypair(); + let keypair = generate_actor_keypair()?; // Create the main community if it doesn't exist let main_community: Community = match Community::read(&conn, 2) { diff --git a/server/src/apub/activities.rs b/server/src/apub/activities.rs index a7f63ec8..9d2a0668 100644 --- a/server/src/apub/activities.rs +++ b/server/src/apub/activities.rs @@ -1,5 +1,5 @@ use crate::apub::is_apub_id_valid; -use crate::apub::signatures::{sign, Keypair}; +use crate::apub::signatures::sign; use crate::db::community::Community; use crate::db::community_view::CommunityFollowerView; use crate::db::post::Post; @@ -36,7 +36,7 @@ fn populate_object_props( /// Send an activity to a list of recipients, using the correct headers etc. fn send_activity( activity: &A, - keypair: &Keypair, + private_key: &str, sender_id: &str, to: Vec, ) -> Result<(), Error> @@ -52,7 +52,7 @@ where continue; } let request = Request::post(t).header("Host", to_url.domain().unwrap()); - let signature = sign(&request, keypair, sender_id)?; + let signature = sign(&request, private_key, sender_id)?; let res = request .header("Signature", signature) .header("Content-Type", "application/json") @@ -90,7 +90,7 @@ pub fn post_create(post: &Post, creator: &User_, conn: &PgConnection) -> Result< .set_object_base_box(page)?; send_activity( &create, - &creator.get_keypair().unwrap(), + &creator.private_key.as_ref().unwrap(), &creator.actor_id, get_follower_inboxes(conn, &community)?, )?; @@ -113,7 +113,7 @@ pub fn post_update(post: &Post, creator: &User_, conn: &PgConnection) -> Result< .set_object_base_box(page)?; send_activity( &update, - &creator.get_keypair().unwrap(), + &creator.private_key.as_ref().unwrap(), &creator.actor_id, get_follower_inboxes(conn, &community)?, )?; @@ -139,7 +139,7 @@ pub fn follow_community( let to = format!("{}/inbox", community.actor_id); send_activity( &follow, - &community.get_keypair().unwrap(), + &community.private_key.as_ref().unwrap(), &community.actor_id, vec![to], )?; @@ -172,7 +172,7 @@ pub fn accept_follow(follow: &Follow, conn: &PgConnection) -> Result<(), Error> let to = format!("{}/inbox", community_uri); send_activity( &accept, - &community.get_keypair().unwrap(), + &community.private_key.unwrap(), &community.actor_id, vec![to], )?; diff --git a/server/src/apub/signatures.rs b/server/src/apub/signatures.rs index e0734e7b..4181e11f 100644 --- a/server/src/apub/signatures.rs +++ b/server/src/apub/signatures.rs @@ -14,23 +14,20 @@ pub struct Keypair { } /// Generate the asymmetric keypair for ActivityPub HTTP signatures. -pub fn generate_actor_keypair() -> Keypair { - let rsa = Rsa::generate(2048).expect("sign::gen_keypair: key generation error"); - let pkey = PKey::from_rsa(rsa).expect("sign::gen_keypair: parsing error"); - let public_key = pkey - .public_key_to_pem() - .expect("sign::gen_keypair: public key encoding error"); - let private_key = pkey - .private_key_to_pem_pkcs8() - .expect("sign::gen_keypair: private key encoding error"); - Keypair { - private_key: String::from_utf8_lossy(&private_key).into_owned(), - public_key: String::from_utf8_lossy(&public_key).into_owned(), - } +pub fn generate_actor_keypair() -> Result { + let rsa = Rsa::generate(2048)?; + let pkey = PKey::from_rsa(rsa)?; + let public_key = pkey.public_key_to_pem()?; + let private_key = pkey.private_key_to_pem_pkcs8()?; + Ok(Keypair { + private_key: String::from_utf8(private_key)?, + public_key: String::from_utf8(public_key)?, + }) } /// Signs request headers with the given keypair. -pub fn sign(request: &Builder, keypair: &Keypair, sender_id: &str) -> Result { +/// TODO: would be nice to pass the sending actor in, instead of raw privatekey/id strings +pub fn sign(request: &Builder, private_key: &str, sender_id: &str) -> Result { let signing_key_id = format!("{}#main-key", sender_id); let config = Config::new(); @@ -55,7 +52,7 @@ pub fn sign(request: &Builder, keypair: &Keypair, sender_id: &str) -> Result diff --git a/server/src/db/code_migrations.rs b/server/src/db/code_migrations.rs index a72de685..60597199 100644 --- a/server/src/db/code_migrations.rs +++ b/server/src/db/code_migrations.rs @@ -7,6 +7,7 @@ use super::*; use crate::apub::signatures::generate_actor_keypair; use crate::apub::{make_apub_endpoint, EndpointType}; use crate::naive_now; +use failure::Error; use log::info; pub fn run_advanced_migrations(conn: &PgConnection) -> Result<(), Error> { @@ -30,7 +31,7 @@ fn user_updates_2020_04_02(conn: &PgConnection) -> Result<(), Error> { .load::(conn)?; for cuser in &incorrect_users { - let keypair = generate_actor_keypair(); + let keypair = generate_actor_keypair()?; let form = UserForm { name: cuser.name.to_owned(), @@ -77,7 +78,7 @@ fn community_updates_2020_04_02(conn: &PgConnection) -> Result<(), Error> { .load::(conn)?; for ccommunity in &incorrect_communities { - let keypair = generate_actor_keypair(); + let keypair = generate_actor_keypair()?; let form = CommunityForm { name: ccommunity.name.to_owned(), diff --git a/server/src/db/community.rs b/server/src/db/community.rs index 7a706557..ca2fc120 100644 --- a/server/src/db/community.rs +++ b/server/src/db/community.rs @@ -1,5 +1,4 @@ use super::*; -use crate::apub::signatures::Keypair; use crate::schema::{community, community_follower, community_moderator, community_user_ban}; #[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)] @@ -96,21 +95,6 @@ impl Community { pub fn get_url(&self) -> String { format!("https://{}/c/{}", Settings::get().hostname, self.name) } - - pub fn get_keypair(&self) -> Option { - if let Some(private) = self.private_key.to_owned() { - if let Some(public) = self.public_key.to_owned() { - Some(Keypair { - private_key: private, - public_key: public, - }) - } else { - None - } - } else { - None - } - } } #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)] diff --git a/server/src/db/user.rs b/server/src/db/user.rs index dfce9f2c..3a079f09 100644 --- a/server/src/db/user.rs +++ b/server/src/db/user.rs @@ -1,5 +1,4 @@ use super::*; -use crate::apub::signatures::Keypair; use crate::schema::user_; use crate::schema::user_::dsl::*; use crate::{is_email_regex, naive_now, Settings}; @@ -125,21 +124,6 @@ impl User_ { use crate::schema::user_::dsl::*; user_.filter(actor_id.eq(object_id)).first::(conn) } - - pub fn get_keypair(&self) -> Option { - if let Some(private) = self.private_key.to_owned() { - if let Some(public) = self.public_key.to_owned() { - Some(Keypair { - private_key: private, - public_key: public, - }) - } else { - None - } - } else { - None - } - } } #[derive(Debug, Serialize, Deserialize)]