From 40b619a91611dafe7b4f978c6c3341a1130e040f Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 13 Oct 2025 14:20:22 +0200 Subject: [PATCH] Merge commit from fork * Ensure tootctl revokes sessions, access tokens and web push subscriptions * Fix test coverage --------- Co-authored-by: Emelia Smith --- app/models/user.rb | 13 +++++++++---- lib/mastodon/cli/accounts.rb | 7 +++++-- spec/lib/mastodon/cli/accounts_spec.rb | 18 +++++++++++++----- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index 08e3bf7ea..d58dc9ed1 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -386,17 +386,22 @@ class User < ApplicationRecord end def reset_password! + # First, change password to something random, this revokes sessions and on-going access: + change_password!(SecureRandom.hex) + + # Finally, send a reset password prompt to the user + send_reset_password_instructions + end + + def change_password!(new_password) # First, change password to something random and deactivate all sessions transaction do - update(password: SecureRandom.hex) + update(password: new_password) session_activations.destroy_all end # Then, remove all authorized applications and connected push subscriptions revoke_access! - - # Finally, send a reset password prompt to the user - send_reset_password_instructions end protected diff --git a/lib/mastodon/cli/accounts.rb b/lib/mastodon/cli/accounts.rb index 33520df25..a4bbe5441 100644 --- a/lib/mastodon/cli/accounts.rb +++ b/lib/mastodon/cli/accounts.rb @@ -170,14 +170,17 @@ module Mastodon::CLI user.role_id = nil end - password = SecureRandom.hex if options[:reset_password] - user.password = password if options[:reset_password] user.email = options[:email] if options[:email] user.disabled = false if options[:enable] user.disabled = true if options[:disable] user.approved = true if options[:approve] user.otp_required_for_login = false if options[:disable_2fa] + # Password changes are a little different, as we also need to ensure + # sessions, subscriptions, and access tokens are revoked after changing: + password = SecureRandom.hex if options[:reset_password] + user.change_password!(password) if options[:reset_password] + if user.save user.confirm if options[:confirm] diff --git a/spec/lib/mastodon/cli/accounts_spec.rb b/spec/lib/mastodon/cli/accounts_spec.rb index a263d673d..eee2c7d25 100644 --- a/spec/lib/mastodon/cli/accounts_spec.rb +++ b/spec/lib/mastodon/cli/accounts_spec.rb @@ -314,12 +314,20 @@ describe Mastodon::CLI::Accounts do context 'with --reset-password option' do let(:options) { { reset_password: true } } - it 'returns a new password for the user' do - allow(SecureRandom).to receive(:hex).and_return('new_password') + let(:user) { Fabricate(:user, password: original_password) } + let(:original_password) { 'foobar12345' } + let(:new_password) { 'new_password12345' } - expect { cli.invoke(:modify, arguments, options) }.to output( - a_string_including('new_password') - ).to_stdout + it 'returns a new password for the user' do + allow(SecureRandom).to receive(:hex).and_return(new_password) + allow(Account).to receive(:find_local).and_return(user.account) + allow(user).to receive(:change_password!).and_call_original + + expect { cli.invoke(:modify, arguments, options) } + .to output(a_string_including(new_password)).to_stdout + + expect(user).to have_received(:change_password!).with(new_password) + expect(user.reload).to_not be_external_or_valid_password(original_password) end end