From 05d43150bcc81a3403fe08e6c9a2d74de4eca9b4 Mon Sep 17 00:00:00 2001
From: Dessalines <tyhou13@gmx.com>
Date: Mon, 22 Nov 2021 10:10:18 -0500
Subject: [PATCH] Making public key required. Fixes #1934

---
 crates/api/src/local_user.rs                              | 3 ++-
 crates/api_crud/src/community/create.rs                   | 4 ++--
 crates/api_crud/src/community/update.rs                   | 1 +
 crates/api_crud/src/user/create.rs                        | 6 +++---
 crates/apub/src/fetcher/user_or_community.rs              | 2 +-
 crates/apub/src/http/mod.rs                               | 2 +-
 crates/apub/src/objects/community.rs                      | 3 +--
 crates/apub/src/objects/person.rs                         | 6 ++----
 crates/apub/src/protocol/objects/group.rs                 | 2 +-
 crates/apub_lib/src/traits.rs                             | 8 +++-----
 crates/db_schema/src/impls/community.rs                   | 3 ++-
 crates/db_schema/src/impls/person.rs                      | 3 ++-
 crates/db_schema/src/schema.rs                            | 8 ++++----
 crates/db_schema/src/source/community.rs                  | 6 +++---
 crates/db_schema/src/source/person.rs                     | 8 ++++----
 .../2021-11-22-143904_add_required_public_key/down.sql    | 2 ++
 .../2021-11-22-143904_add_required_public_key/up.sql      | 7 +++++++
 src/code_migrations.rs                                    | 6 +++---
 18 files changed, 44 insertions(+), 36 deletions(-)
 create mode 100644 migrations/2021-11-22-143904_add_required_public_key/down.sql
 create mode 100644 migrations/2021-11-22-143904_add_required_public_key/up.sql

diff --git a/crates/api/src/local_user.rs b/crates/api/src/local_user.rs
index 727dd1a5..6f63d14b 100644
--- a/crates/api/src/local_user.rs
+++ b/crates/api/src/local_user.rs
@@ -191,6 +191,7 @@ impl Perform for SaveUserSettings {
     let default_listing_type = data.default_listing_type;
     let default_sort_type = data.default_sort_type;
     let password_encrypted = local_user_view.local_user.password_encrypted;
+    let public_key = local_user_view.person.public_key;
 
     let person_form = PersonForm {
       name: local_user_view.person.name,
@@ -207,7 +208,7 @@ impl Perform for SaveUserSettings {
       local: None,
       admin: None,
       private_key: None,
-      public_key: None,
+      public_key,
       last_refreshed_at: None,
       shared_inbox_url: None,
       matrix_user_id,
diff --git a/crates/api_crud/src/community/create.rs b/crates/api_crud/src/community/create.rs
index b91cab43..19c6fc6b 100644
--- a/crates/api_crud/src/community/create.rs
+++ b/crates/api_crud/src/community/create.rs
@@ -93,8 +93,8 @@ impl PerformCrud for CreateCommunity {
       banner,
       nsfw: data.nsfw,
       actor_id: Some(community_actor_id.to_owned()),
-      private_key: Some(keypair.private_key),
-      public_key: Some(keypair.public_key),
+      private_key: Some(Some(keypair.private_key)),
+      public_key: keypair.public_key,
       followers_url: Some(generate_followers_url(&community_actor_id)?),
       inbox_url: Some(generate_inbox_url(&community_actor_id)?),
       shared_inbox_url: Some(Some(generate_shared_inbox_url(&community_actor_id)?)),
diff --git a/crates/api_crud/src/community/update.rs b/crates/api_crud/src/community/update.rs
index d1fd8981..a4f877d6 100644
--- a/crates/api_crud/src/community/update.rs
+++ b/crates/api_crud/src/community/update.rs
@@ -57,6 +57,7 @@ impl PerformCrud for EditCommunity {
       name: read_community.name,
       title: data.title.to_owned().unwrap_or(read_community.title),
       description: data.description.to_owned(),
+      public_key: read_community.public_key,
       icon,
       banner,
       nsfw: data.nsfw,
diff --git a/crates/api_crud/src/user/create.rs b/crates/api_crud/src/user/create.rs
index 78b204ff..2ce2fa36 100644
--- a/crates/api_crud/src/user/create.rs
+++ b/crates/api_crud/src/user/create.rs
@@ -109,7 +109,7 @@ impl PerformCrud for Register {
       name: data.username.to_owned(),
       actor_id: Some(actor_id.clone()),
       private_key: Some(Some(actor_keypair.private_key)),
-      public_key: Some(Some(actor_keypair.public_key)),
+      public_key: actor_keypair.public_key,
       inbox_url: Some(generate_inbox_url(&actor_id)?),
       shared_inbox_url: Some(Some(generate_shared_inbox_url(&actor_id)?)),
       admin: Some(no_admins),
@@ -189,8 +189,8 @@ impl PerformCrud for Register {
           title: "The Default Community".to_string(),
           description: Some("The Default Community".to_string()),
           actor_id: Some(actor_id.to_owned()),
-          private_key: Some(main_community_keypair.private_key),
-          public_key: Some(main_community_keypair.public_key),
+          private_key: Some(Some(main_community_keypair.private_key)),
+          public_key: main_community_keypair.public_key,
           followers_url: Some(generate_followers_url(&actor_id)?),
           inbox_url: Some(generate_inbox_url(&actor_id)?),
           shared_inbox_url: Some(Some(generate_shared_inbox_url(&actor_id)?)),
diff --git a/crates/apub/src/fetcher/user_or_community.rs b/crates/apub/src/fetcher/user_or_community.rs
index 08138964..00612cbb 100644
--- a/crates/apub/src/fetcher/user_or_community.rs
+++ b/crates/apub/src/fetcher/user_or_community.rs
@@ -103,7 +103,7 @@ impl ActorType for UserOrCommunity {
     }
   }
 
-  fn public_key(&self) -> Option<String> {
+  fn public_key(&self) -> String {
     match self {
       UserOrCommunity::User(p) => p.public_key(),
       UserOrCommunity::Community(p) => p.public_key(),
diff --git a/crates/apub/src/http/mod.rs b/crates/apub/src/http/mod.rs
index ebb155a8..18e654d4 100644
--- a/crates/apub/src/http/mod.rs
+++ b/crates/apub/src/http/mod.rs
@@ -95,7 +95,7 @@ where
   let actor = ObjectId::<UserOrCommunity>::new(activity_data.actor)
     .dereference(context, request_counter)
     .await?;
-  verify_signature(&request, &actor.public_key().context(location_info!())?)?;
+  verify_signature(&request, &actor.public_key())?;
 
   // Do nothing if we received the same activity before
   if is_activity_already_known(context.pool(), &activity_data.id).await? {
diff --git a/crates/apub/src/objects/community.rs b/crates/apub/src/objects/community.rs
index d8bc837f..300ad2f2 100644
--- a/crates/apub/src/objects/community.rs
+++ b/crates/apub/src/objects/community.rs
@@ -163,7 +163,7 @@ impl ActorType for ApubCommunity {
   fn actor_id(&self) -> Url {
     self.actor_id.to_owned().into()
   }
-  fn public_key(&self) -> Option<String> {
+  fn public_key(&self) -> String {
     self.public_key.to_owned()
   }
   fn private_key(&self) -> Option<String> {
@@ -244,7 +244,6 @@ pub(crate) mod tests {
     let community = parse_lemmy_community(&context).await;
 
     assert_eq!(community.title, "Ten Forward");
-    assert!(community.public_key.is_some());
     assert!(!community.local);
     assert_eq!(community.description.as_ref().unwrap().len(), 132);
 
diff --git a/crates/apub/src/objects/person.rs b/crates/apub/src/objects/person.rs
index 422862cb..8c0587dd 100644
--- a/crates/apub/src/objects/person.rs
+++ b/crates/apub/src/objects/person.rs
@@ -158,7 +158,7 @@ impl ApubObject for ApubPerson {
       admin: Some(false),
       bot_account: Some(person.kind == UserTypes::Service),
       private_key: None,
-      public_key: Some(Some(person.public_key.public_key_pem)),
+      public_key: person.public_key.public_key_pem,
       last_refreshed_at: Some(naive_now()),
       inbox_url: Some(person.inbox.into()),
       shared_inbox_url: Some(person.endpoints.shared_inbox.map(|s| s.into())),
@@ -177,7 +177,7 @@ impl ActorType for ApubPerson {
     self.actor_id.to_owned().into()
   }
 
-  fn public_key(&self) -> Option<String> {
+  fn public_key(&self) -> String {
     self.public_key.to_owned()
   }
 
@@ -222,7 +222,6 @@ pub(crate) mod tests {
     let person = parse_lemmy_person(&context).await;
 
     assert_eq!(person.display_name, Some("Jean-Luc Picard".to_string()));
-    assert!(person.public_key.is_some());
     assert!(!person.local);
     assert_eq!(person.bio.as_ref().unwrap().len(), 39);
 
@@ -245,7 +244,6 @@ pub(crate) mod tests {
 
     assert_eq!(person.actor_id, url.into());
     assert_eq!(person.name, "lanodan");
-    assert!(person.public_key.is_some());
     assert!(!person.local);
     assert_eq!(request_counter, 0);
     assert_eq!(person.bio.as_ref().unwrap().len(), 873);
diff --git a/crates/apub/src/protocol/objects/group.rs b/crates/apub/src/protocol/objects/group.rs
index def87859..fa225398 100644
--- a/crates/apub/src/protocol/objects/group.rs
+++ b/crates/apub/src/protocol/objects/group.rs
@@ -81,7 +81,7 @@ impl Group {
       actor_id: Some(self.id.into()),
       local: Some(false),
       private_key: None,
-      public_key: Some(self.public_key.public_key_pem),
+      public_key: self.public_key.public_key_pem,
       last_refreshed_at: Some(naive_now()),
       icon: Some(self.icon.map(|i| i.url.into())),
       banner: Some(self.image.map(|i| i.url.into())),
diff --git a/crates/apub_lib/src/traits.rs b/crates/apub_lib/src/traits.rs
index c0cdb1af..e96b568c 100644
--- a/crates/apub_lib/src/traits.rs
+++ b/crates/apub_lib/src/traits.rs
@@ -1,8 +1,7 @@
 use crate::{data::Data, signatures::PublicKey};
 use activitystreams::chrono::NaiveDateTime;
-use anyhow::Context;
 pub use lemmy_apub_lib_derive::*;
-use lemmy_utils::{location_info, LemmyError};
+use lemmy_utils::LemmyError;
 use url::Url;
 
 #[async_trait::async_trait(?Send)]
@@ -71,8 +70,7 @@ pub trait ApubObject {
 pub trait ActorType {
   fn actor_id(&self) -> Url;
 
-  // TODO: this should not be an option (needs db migration in lemmy)
-  fn public_key(&self) -> Option<String>;
+  fn public_key(&self) -> String;
   fn private_key(&self) -> Option<String>;
 
   fn inbox_url(&self) -> Url;
@@ -87,7 +85,7 @@ pub trait ActorType {
     Ok(PublicKey {
       id: format!("{}#main-key", self.actor_id()),
       owner: Box::new(self.actor_id()),
-      public_key_pem: self.public_key().context(location_info!())?,
+      public_key_pem: self.public_key(),
     })
   }
 }
diff --git a/crates/db_schema/src/impls/community.rs b/crates/db_schema/src/impls/community.rs
index 1fac4a27..8adf2ba5 100644
--- a/crates/db_schema/src/impls/community.rs
+++ b/crates/db_schema/src/impls/community.rs
@@ -319,6 +319,7 @@ mod tests {
     let new_community = CommunityForm {
       name: "TIL".into(),
       title: "nada".to_owned(),
+      public_key: "nada".to_owned(),
       ..CommunityForm::default()
     };
 
@@ -337,7 +338,7 @@ mod tests {
       actor_id: inserted_community.actor_id.to_owned(),
       local: true,
       private_key: None,
-      public_key: None,
+      public_key: "nada".to_owned(),
       last_refreshed_at: inserted_community.published,
       icon: None,
       banner: None,
diff --git a/crates/db_schema/src/impls/person.rs b/crates/db_schema/src/impls/person.rs
index b0476480..5e0048ec 100644
--- a/crates/db_schema/src/impls/person.rs
+++ b/crates/db_schema/src/impls/person.rs
@@ -270,6 +270,7 @@ mod tests {
 
     let new_person = PersonForm {
       name: "holly".into(),
+      public_key: "nada".to_owned(),
       ..PersonForm::default()
     };
 
@@ -291,7 +292,7 @@ mod tests {
       bot_account: false,
       admin: false,
       private_key: None,
-      public_key: None,
+      public_key: "nada".to_owned(),
       last_refreshed_at: inserted_person.published,
       inbox_url: inserted_person.inbox_url.to_owned(),
       shared_inbox_url: None,
diff --git a/crates/db_schema/src/schema.rs b/crates/db_schema/src/schema.rs
index b0802890..6cd2e2af 100644
--- a/crates/db_schema/src/schema.rs
+++ b/crates/db_schema/src/schema.rs
@@ -86,7 +86,7 @@ table! {
         actor_id -> Varchar,
         local -> Bool,
         private_key -> Nullable<Text>,
-        public_key -> Nullable<Text>,
+        public_key -> Text,
         last_refreshed_at -> Timestamp,
         icon -> Nullable<Varchar>,
         banner -> Nullable<Varchar>,
@@ -293,7 +293,7 @@ table! {
         bio -> Nullable<Text>,
         local -> Bool,
         private_key -> Nullable<Text>,
-        public_key -> Nullable<Text>,
+        public_key -> Text,
         last_refreshed_at -> Timestamp,
         banner -> Nullable<Varchar>,
         deleted -> Bool,
@@ -514,7 +514,7 @@ table! {
         bio -> Nullable<Text>,
         local -> Bool,
         private_key -> Nullable<Text>,
-        public_key -> Nullable<Text>,
+        public_key -> Text,
         last_refreshed_at -> Timestamp,
         banner -> Nullable<Varchar>,
         deleted -> Bool,
@@ -539,7 +539,7 @@ table! {
         bio -> Nullable<Text>,
         local -> Bool,
         private_key -> Nullable<Text>,
-        public_key -> Nullable<Text>,
+        public_key -> Text,
         last_refreshed_at -> Timestamp,
         banner -> Nullable<Varchar>,
         deleted -> Bool,
diff --git a/crates/db_schema/src/source/community.rs b/crates/db_schema/src/source/community.rs
index 4c351b88..269e7dbf 100644
--- a/crates/db_schema/src/source/community.rs
+++ b/crates/db_schema/src/source/community.rs
@@ -19,7 +19,7 @@ pub struct Community {
   pub actor_id: DbUrl,
   pub local: bool,
   pub private_key: Option<String>,
-  pub public_key: Option<String>,
+  pub public_key: String,
   pub last_refreshed_at: chrono::NaiveDateTime,
   pub icon: Option<DbUrl>,
   pub banner: Option<DbUrl>,
@@ -60,8 +60,8 @@ pub struct CommunityForm {
   pub nsfw: Option<bool>,
   pub actor_id: Option<DbUrl>,
   pub local: Option<bool>,
-  pub private_key: Option<String>,
-  pub public_key: Option<String>,
+  pub private_key: Option<Option<String>>,
+  pub public_key: String,
   pub last_refreshed_at: Option<chrono::NaiveDateTime>,
   pub icon: Option<Option<DbUrl>>,
   pub banner: Option<Option<DbUrl>>,
diff --git a/crates/db_schema/src/source/person.rs b/crates/db_schema/src/source/person.rs
index c9ffad7b..8ff56eba 100644
--- a/crates/db_schema/src/source/person.rs
+++ b/crates/db_schema/src/source/person.rs
@@ -18,7 +18,7 @@ pub struct Person {
   pub bio: Option<String>,
   pub local: bool,
   pub private_key: Option<String>,
-  pub public_key: Option<String>,
+  pub public_key: String,
   pub last_refreshed_at: chrono::NaiveDateTime,
   pub banner: Option<DbUrl>,
   pub deleted: bool,
@@ -66,7 +66,7 @@ pub struct PersonAlias1 {
   pub bio: Option<String>,
   pub local: bool,
   pub private_key: Option<String>,
-  pub public_key: Option<String>,
+  pub public_key: String,
   pub last_refreshed_at: chrono::NaiveDateTime,
   pub banner: Option<DbUrl>,
   pub deleted: bool,
@@ -113,7 +113,7 @@ pub struct PersonAlias2 {
   pub bio: Option<String>,
   pub local: bool,
   pub private_key: Option<String>,
-  pub public_key: Option<String>,
+  pub public_key: String,
   pub last_refreshed_at: chrono::NaiveDateTime,
   pub banner: Option<DbUrl>,
   pub deleted: bool,
@@ -159,7 +159,7 @@ pub struct PersonForm {
   pub bio: Option<Option<String>>,
   pub local: Option<bool>,
   pub private_key: Option<Option<String>>,
-  pub public_key: Option<Option<String>>,
+  pub public_key: String,
   pub last_refreshed_at: Option<chrono::NaiveDateTime>,
   pub banner: Option<Option<DbUrl>>,
   pub deleted: Option<bool>,
diff --git a/migrations/2021-11-22-143904_add_required_public_key/down.sql b/migrations/2021-11-22-143904_add_required_public_key/down.sql
new file mode 100644
index 00000000..775d07d3
--- /dev/null
+++ b/migrations/2021-11-22-143904_add_required_public_key/down.sql
@@ -0,0 +1,2 @@
+alter table community alter column public_key drop not null;
+alter table person alter column public_key drop not null;
diff --git a/migrations/2021-11-22-143904_add_required_public_key/up.sql b/migrations/2021-11-22-143904_add_required_public_key/up.sql
new file mode 100644
index 00000000..b2882561
--- /dev/null
+++ b/migrations/2021-11-22-143904_add_required_public_key/up.sql
@@ -0,0 +1,7 @@
+-- Delete the empty public keys
+delete from community where public_key is null;
+delete from person where public_key is null;
+
+-- Make it required
+alter table community alter column public_key set not null;
+alter table person alter column public_key set not null;
diff --git a/src/code_migrations.rs b/src/code_migrations.rs
index 2feefbdf..b7c43508 100644
--- a/src/code_migrations.rs
+++ b/src/code_migrations.rs
@@ -64,7 +64,7 @@ fn user_updates_2020_04_02(
         protocol_and_hostname,
       )?),
       private_key: Some(Some(keypair.private_key)),
-      public_key: Some(Some(keypair.public_key)),
+      public_key: keypair.public_key,
       last_refreshed_at: Some(naive_now()),
       ..PersonForm::default()
     };
@@ -109,8 +109,8 @@ fn community_updates_2020_04_02(
       updated: None,
       actor_id: Some(community_actor_id.to_owned()),
       local: Some(ccommunity.local),
-      private_key: Some(keypair.private_key),
-      public_key: Some(keypair.public_key),
+      private_key: Some(Some(keypair.private_key)),
+      public_key: keypair.public_key,
       last_refreshed_at: Some(naive_now()),
       published: None,
       icon: Some(ccommunity.icon.to_owned()),
-- 
2.44.1