]> Untitled Git - lemmy.git/commitdiff
Simplify signing code
authorFelix <me@nutomic.com>
Sun, 19 Apr 2020 11:44:44 +0000 (13:44 +0200)
committerFelix <me@nutomic.com>
Sun, 19 Apr 2020 11:44:44 +0000 (13:44 +0200)
server/src/api/community.rs
server/src/api/user.rs
server/src/apub/activities.rs
server/src/apub/signatures.rs
server/src/db/code_migrations.rs
server/src/db/community.rs
server/src/db/user.rs

index 30c8aa2052dc2d5048676112337c266054dfbbc0..0c0ddceec926b73aeea45949e8af279bb2518986 100644 (file)
@@ -201,7 +201,7 @@ impl Perform<CommunityResponse> for Oper<CreateCommunity> {
     }
 
     // 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(),
index 35bdd33abcc99de19c820e7b467407fb9c78f035..f42ea03a55afdf382e50a09be6297c3fdecef599 100644 (file)
@@ -252,7 +252,7 @@ impl Perform<LoginResponse> for Oper<Register> {
       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<LoginResponse> for Oper<Register> {
       }
     };
 
-    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) {
index a7f63ec857966d0f9ec5666b11d628518e8d2aad..9d2a0668034d8e844e79e1102833f8da1ec8c862 100644 (file)
@@ -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<A>(
   activity: &A,
-  keypair: &Keypair,
+  private_key: &str,
   sender_id: &str,
   to: Vec<String>,
 ) -> 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],
   )?;
index e0734e7be2535b53a6a760c2ab5e545b1a006d29..4181e11f73d714a2bb80af4a4007957cb0df2f55 100644 (file)
@@ -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<Keypair, Error> {
+  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<String, Error> {
+/// 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<String, Error> {
   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<Str
       headers,
     )
     .sign(signing_key_id, |signing_string| {
-      let private_key = PKey::private_key_from_pem(keypair.private_key.as_bytes())?;
+      let private_key = PKey::private_key_from_pem(private_key.as_bytes())?;
       let mut signer = Signer::new(MessageDigest::sha256(), &private_key).unwrap();
       signer.update(signing_string.as_bytes()).unwrap();
       Ok(base64::encode(signer.sign_to_vec()?)) as Result<_, Error>
index a72de685e385f690d4c6f3269688387077ecd485..605971996f56c06e331c48f1a6eee5fe0f940bf3 100644 (file)
@@ -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::<User_>(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::<Community>(conn)?;
 
   for ccommunity in &incorrect_communities {
-    let keypair = generate_actor_keypair();
+    let keypair = generate_actor_keypair()?;
 
     let form = CommunityForm {
       name: ccommunity.name.to_owned(),
index 7a706557bcc17f66e9cceac0defd0b72be4b64e9..ca2fc120a44bcf979f1b8639dd20c59232fc10cd 100644 (file)
@@ -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<Keypair> {
-    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)]
index dfce9f2cbdc65c2567611406fb65554fbc2349c5..3a079f0916e31452299cee9942b84c9347c1fda4 100644 (file)
@@ -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::<Self>(conn)
   }
-
-  pub fn get_keypair(&self) -> Option<Keypair> {
-    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)]