* If an Update is signed with known key, skip re-following procedure
Because it means the remote actor did *not* lose their database
* Add CLI method for rotating keys
    bin/tootctl accounts rotate [USERNAME]
Generates a new RSA key per account and sends out an Update activity
signed with the old key.
* Key rotation: Space out Update fan-outs every 5 minutes per 1000 accounts
* Skip suspended accounts in key rotation
		
	
			
		
			
				
	
	
		
			55 lines
		
	
	
	
		
			1.5 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			55 lines
		
	
	
	
		
			1.5 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| # frozen_string_literal: true
 | |
| 
 | |
| require 'rubygems/package'
 | |
| require_relative '../../config/boot'
 | |
| require_relative '../../config/environment'
 | |
| require_relative 'cli_helper'
 | |
| 
 | |
| module Mastodon
 | |
|   class AccountsCLI < Thor
 | |
|     option :all, type: :boolean
 | |
|     desc 'rotate [USERNAME]', 'Generate and broadcast new keys'
 | |
|     long_desc <<-LONG_DESC
 | |
|       Generate and broadcast new RSA keys as part of security
 | |
|       maintenance.
 | |
| 
 | |
|       With the --all option, all local accounts will be subject
 | |
|       to the rotation. Otherwise, and by default, only a single
 | |
|       account specified by the USERNAME argument will be
 | |
|       processed.
 | |
|     LONG_DESC
 | |
|     def rotate(username = nil)
 | |
|       if options[:all]
 | |
|         processed = 0
 | |
|         delay     = 0
 | |
| 
 | |
|         Account.local.without_suspended.find_in_batches do |accounts|
 | |
|           accounts.each do |account|
 | |
|             rotate_keys_for_account(account, delay)
 | |
|             processed += 1
 | |
|             say('.', :green, false)
 | |
|           end
 | |
| 
 | |
|           delay += 5.minutes
 | |
|         end
 | |
| 
 | |
|         say
 | |
|         say("OK, rotated keys for #{processed} accounts", :green)
 | |
|       elsif username.present?
 | |
|         rotate_keys_for_account(Account.find_local(username))
 | |
|         say('OK', :green)
 | |
|       else
 | |
|         say('No account(s) given', :red)
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     private
 | |
| 
 | |
|     def rotate_keys_for_account(account, delay = 0)
 | |
|       old_key = account.private_key
 | |
|       new_key = OpenSSL::PKey::RSA.new(2048).to_pem
 | |
|       account.update(private_key: new_key)
 | |
|       ActivityPub::UpdateDistributionWorker.perform_in(delay, account.id, sign_with: old_key)
 | |
|     end
 | |
|   end
 | |
| end
 |