From eb977dc25a45cf44db8e8ff51a84507ec2f76c54 Mon Sep 17 00:00:00 2001
From: Benjamin Neff <benjamin@coding4coffee.ch>
Date: Wed, 27 Oct 2021 04:21:25 +0200
Subject: [PATCH] Use old person private key if relayable author migrated away

We only store signatures for relayables if the author is external, but
if the author becomes external through a migration, the signature is
missing. Lets just use the old persons private key to still be able to
generate a signature for the export.

closes #8310
---
 Changelog.md                                      |  1 +
 app/serializers/federation_entity_serializer.rb   | 15 +++++++++++++++
 .../export/others_data_serializer_spec.rb         | 11 ++++++++---
 3 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/Changelog.md b/Changelog.md
index 7a7d5eecb5..62ddd3f856 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -11,6 +11,7 @@
 * Ensure the log folder exists [#8287](https://github.com/diaspora/diaspora/pull/8287)
 * Limit name length in header [#8313] (https://github.com/diaspora/diaspora/pull/8313)
 * Fix fallback avatar in hovercards [#8316](https://github.com/diaspora/diaspora/pull/8316)
+* Use old person private key for export if relayable author migrated away [#8310](https://github.com/diaspora/diaspora/pull/8310)
 
 ## Features
 * Add tags to tumblr posts [#8244](https://github.com/diaspora/diaspora/pull/8244)
diff --git a/app/serializers/federation_entity_serializer.rb b/app/serializers/federation_entity_serializer.rb
index 22fa74afcd..c19b4b30f2 100644
--- a/app/serializers/federation_entity_serializer.rb
+++ b/app/serializers/federation_entity_serializer.rb
@@ -5,11 +5,26 @@
 # are used as for federation messages generation.
 class FederationEntitySerializer < ActiveModel::Serializer
   include SerializerPostProcessing
+  include Diaspora::Logging
 
   private
 
   def modify_serializable_object(hash)
     hash.merge(entity.to_json)
+  rescue DiasporaFederation::Entities::Relayable::AuthorPrivateKeyNotFound => e
+    # The author of this relayable probably migrated from this pod to a different pod,
+    # and we neither have the signature nor the new private key to generate a valid signature.
+    # But we can use the private key of the old user to generate the signature it had when this entity was created
+    old_person = AccountMigration.joins(:old_person)
+                                 .where("new_person_id = ? AND people.owner_id IS NOT NULL", object.author_id)
+                                 .first.old_person
+    if old_person
+      logger.info "Using private key of #{old_person.diaspora_handle} to export: #{e.message}"
+      object.author = old_person
+      hash.merge(entity.to_json)
+    else
+      logger.warn "Skip entity for export because #{e.class}: #{e.message}"
+    end
   end
 
   def entity
diff --git a/spec/serializers/export/others_data_serializer_spec.rb b/spec/serializers/export/others_data_serializer_spec.rb
index 2c40adfb80..66674f949d 100644
--- a/spec/serializers/export/others_data_serializer_spec.rb
+++ b/spec/serializers/export/others_data_serializer_spec.rb
@@ -13,9 +13,14 @@ describe Export::OthersDataSerializer do
     serializer.associations
   end
 
-  context "with user's activity" do
-    before do
-      DataGenerator.new(user).activity
+  it "uses old local user private key if the author was migrated away from the pod" do
+    post = DataGenerator.new(user).status_message_with_activity
+
+    old_comment_author = post.comments.first.author
+    AccountMigration.create!(old_person: old_comment_author, new_person: FactoryGirl.create(:person)).perform!
+
+    serializer.associations[:relayables].select {|r| r[:entity_type] == "comment" }.each do |comment|
+      expect(comment[:entity_data][:author]).to eq(old_comment_author.diaspora_handle)
     end
   end
 end
-- 
GitLab