diff --git a/db/post_migrate/20260702144128_migrate_local_account_keypairs.rb b/db/post_migrate/20260702144128_migrate_local_account_keypairs.rb new file mode 100644 index 00000000000..664e8ca6457 --- /dev/null +++ b/db/post_migrate/20260702144128_migrate_local_account_keypairs.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +class MigrateLocalAccountKeypairs < ActiveRecord::Migration[8.1] + disable_ddl_transaction! + + class Account < ApplicationRecord + has_many :keypairs, inverse_of: :account + + scope :local, -> { where(domain: nil) } + end + + class Keypair < ApplicationRecord + self.inheritance_column = nil + + encrypts :private_key + + belongs_to :account + + enum :type, { + rsa: 0, + }, validate: true + end + + def up + Account.reset_column_information + Keypair.reset_column_information + + Account.local.where.not(private_key: nil).in_batches do |accounts| + Keypair.upsert_all( + accounts.map do |account| + { + type: :rsa, + account_id: account.id, + local_fragment: '#main-key', + public_key: account.public_key, + private_key: account.private_key, + } + end, + unique_by: [:account_id, :local_fragment] + ) + + accounts.update_all(public_key: '', private_key: nil) + end + + Account.reset_column_information + Keypair.reset_column_information + end + + def down + Account.reset_column_information + Keypair.reset_column_information + + Account.local.where(private_key: nil).find_each do |account| + keypair = account.keypairs.find_by(local_fragment: '#main-key') + next if keypair.nil? + + account.update(public_key: keypair.public_key, private_key: keypair.private_key) + keypair.delete + end + + Account.reset_column_information + Keypair.reset_column_information + end +end diff --git a/db/schema.rb b/db/schema.rb index 0d11ef712fb..6a753c72f9f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.1].define(version: 2026_07_01_161826) do +ActiveRecord::Schema[8.1].define(version: 2026_07_02_144128) do # These are extensions that must be enabled in order to support this database enable_extension "pg_catalog.plpgsql" diff --git a/lib/tasks/tests.rake b/lib/tasks/tests.rake index 6f41d07955a..48d2233c938 100644 --- a/lib/tasks/tests.rake +++ b/lib/tasks/tests.rake @@ -51,11 +51,16 @@ namespace :tests do exit(1) end - if Account.find(Account::INSTANCE_ACTOR_ID).private_key.blank? + if Account.find(Account::INSTANCE_ACTOR_ID).keypair.blank? puts 'Instance actor does not have a private key' exit(1) end + if Account.local.where.not(private_key: nil).exists? + puts 'Private keys not properly migrated' + exit(1) + end + unless Account.find_by(username: 'user', domain: nil).custom_filters.map { |filter| filter.keywords.pluck(:keyword) } == [['test'], ['take']] puts 'CustomFilterKeyword records not created as expected' exit(1)