From 177193b656f33a3c2dde2128f939500bcb841597 Mon Sep 17 00:00:00 2001 From: erdgeist Date: Sat, 1 Aug 2026 00:42:21 +0200 Subject: Add escape hatch rake task should all admins lose their 2nd factor --- lib/tasks/users.rake | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 lib/tasks/users.rake diff --git a/lib/tasks/users.rake b/lib/tasks/users.rake new file mode 100644 index 00000000..cdee7fc8 --- /dev/null +++ b/lib/tasks/users.rake @@ -0,0 +1,26 @@ +namespace :users do + desc "Clear a user's second factor from the shell. LOGIN=name. " \ + "The recovery path when an admin loses their device: elevation " \ + "requires a code, resetting someone else's factor requires " \ + "elevation, and self-service disable requires a current code -- so " \ + "with every admin locked out there is no in-app way back." + task :clear_otp => :environment do + login = ENV["LOGIN"].to_s.strip.downcase + abort "usage: LOGIN=name rake users:clear_otp" if login.empty? + + user = User.find_by(:login => login) + abort "no such user: #{login}" if user.nil? + + unless user.otp_enrolled? + puts "#{user.login} has no second factor enrolled; nothing to do." + next + end + + # Witnessed with the user as their own actor: there is no logged-in + # admin to attribute it to, and an unattributed hole in the log is worse + # than one that says "from the shell". + user.disable_otp!(:actor => user) + puts "Cleared the second factor for #{user.login}. " \ + "They can re-enrol under My account; recorded in the action log." + end +end -- cgit v1.3