about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--app/models/user.rb12
-rw-r--r--db/post_migrate/20220118183010_remove_index_users_on_remember_token.rb13
-rw-r--r--db/post_migrate/20220118183123_remove_rememberable_from_users.rb8
-rw-r--r--db/schema.rb5
-rw-r--r--lib/mastodon/maintenance_cli.rb34
5 files changed, 51 insertions, 21 deletions
diff --git a/app/models/user.rb b/app/models/user.rb
index 49dcb8156..c2bc5b590 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -10,7 +10,6 @@
 #  encrypted_password        :string           default(""), not null
 #  reset_password_token      :string
 #  reset_password_sent_at    :datetime
-#  remember_created_at       :datetime
 #  sign_in_count             :integer          default(0), not null
 #  current_sign_in_at        :datetime
 #  last_sign_in_at           :datetime
@@ -32,7 +31,6 @@
 #  disabled                  :boolean          default(FALSE), not null
 #  moderator                 :boolean          default(FALSE), not null
 #  invite_id                 :bigint(8)
-#  remember_token            :string
 #  chosen_languages          :string           is an Array
 #  created_by_application_id :bigint(8)
 #  approved                  :boolean          default(TRUE), not null
@@ -44,6 +42,11 @@
 #
 
 class User < ApplicationRecord
+  self.ignored_columns = %w(
+    remember_created_at
+    remember_token
+  )
+
   include Settings::Extend
   include UserRoles
 
@@ -329,10 +332,9 @@ class User < ApplicationRecord
   end
 
   def reset_password!
-    # First, change password to something random, invalidate the remember-me token,
-    # and deactivate all sessions
+    # First, change password to something random and deactivate all sessions
     transaction do
-      update(remember_token: nil, remember_created_at: nil, password: SecureRandom.hex)
+      update(password: SecureRandom.hex)
       session_activations.destroy_all
     end
 
diff --git a/db/post_migrate/20220118183010_remove_index_users_on_remember_token.rb b/db/post_migrate/20220118183010_remove_index_users_on_remember_token.rb
new file mode 100644
index 000000000..367d489de
--- /dev/null
+++ b/db/post_migrate/20220118183010_remove_index_users_on_remember_token.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class RemoveIndexUsersOnRememberToken < ActiveRecord::Migration[6.1]
+  disable_ddl_transaction!
+
+  def up
+    remove_index :users, name: :index_users_on_remember_token
+  end
+
+  def down
+    add_index :users, :remember_token, algorithm: :concurrently, unique: true, name: :index_users_on_remember_token
+  end
+end
diff --git a/db/post_migrate/20220118183123_remove_rememberable_from_users.rb b/db/post_migrate/20220118183123_remove_rememberable_from_users.rb
new file mode 100644
index 000000000..1e274c6e0
--- /dev/null
+++ b/db/post_migrate/20220118183123_remove_rememberable_from_users.rb
@@ -0,0 +1,8 @@
+class RemoveRememberableFromUsers < ActiveRecord::Migration[6.1]
+  def change
+    safety_assured do
+      remove_column :users, :remember_token, :string, null: true, default: nil
+      remove_column :users, :remember_created_at, :datetime, null: true, default: nil
+    end
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 4e0f76dcd..fd4633d69 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.define(version: 2022_01_16_202951) do
+ActiveRecord::Schema.define(version: 2022_01_18_183123) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "plpgsql"
@@ -937,7 +937,6 @@ ActiveRecord::Schema.define(version: 2022_01_16_202951) do
     t.string "encrypted_password", default: "", null: false
     t.string "reset_password_token"
     t.datetime "reset_password_sent_at"
-    t.datetime "remember_created_at"
     t.integer "sign_in_count", default: 0, null: false
     t.datetime "current_sign_in_at"
     t.datetime "last_sign_in_at"
@@ -959,7 +958,6 @@ ActiveRecord::Schema.define(version: 2022_01_16_202951) do
     t.boolean "disabled", default: false, null: false
     t.boolean "moderator", default: false, null: false
     t.bigint "invite_id"
-    t.string "remember_token"
     t.string "chosen_languages", array: true
     t.bigint "created_by_application_id"
     t.boolean "approved", default: true, null: false
@@ -972,7 +970,6 @@ ActiveRecord::Schema.define(version: 2022_01_16_202951) do
     t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
     t.index ["created_by_application_id"], name: "index_users_on_created_by_application_id"
     t.index ["email"], name: "index_users_on_email", unique: true
-    t.index ["remember_token"], name: "index_users_on_remember_token", unique: true
     t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
   end
 
diff --git a/lib/mastodon/maintenance_cli.rb b/lib/mastodon/maintenance_cli.rb
index 47e2d78bb..00861df77 100644
--- a/lib/mastodon/maintenance_cli.rb
+++ b/lib/mastodon/maintenance_cli.rb
@@ -14,7 +14,7 @@ module Mastodon
     end
 
     MIN_SUPPORTED_VERSION = 2019_10_01_213028
-    MAX_SUPPORTED_VERSION = 2021_05_26_193025
+    MAX_SUPPORTED_VERSION = 2022_01_18_183123
 
     # Stubs to enjoy ActiveRecord queries while not depending on a particular
     # version of the code/database
@@ -84,13 +84,14 @@ module Mastodon
 
         owned_classes = [
           Status, StatusPin, MediaAttachment, Poll, Report, Tombstone, Favourite,
-          Follow, FollowRequest, Block, Mute, AccountIdentityProof,
+          Follow, FollowRequest, Block, Mute,
           AccountModerationNote, AccountPin, AccountStat, ListAccount,
           PollVote, Mention
         ]
         owned_classes << AccountDeletionRequest if ActiveRecord::Base.connection.table_exists?(:account_deletion_requests)
         owned_classes << AccountNote if ActiveRecord::Base.connection.table_exists?(:account_notes)
         owned_classes << FollowRecommendationSuppression if ActiveRecord::Base.connection.table_exists?(:follow_recommendation_suppressions)
+        owned_classes << AccountIdentityProof if ActiveRecord::Base.connection.table_exists?(:account_identity_proofs)
 
         owned_classes.each do |klass|
           klass.where(account_id: other_account.id).find_each do |record|
@@ -139,17 +140,22 @@ module Mastodon
       @prompt = TTY::Prompt.new
 
       if ActiveRecord::Migrator.current_version < MIN_SUPPORTED_VERSION
-        @prompt.warn 'Your version of the database schema is too old and is not supported by this script.'
-        @prompt.warn 'Please update to at least Mastodon 3.0.0 before running this script.'
+        @prompt.error 'Your version of the database schema is too old and is not supported by this script.'
+        @prompt.error 'Please update to at least Mastodon 3.0.0 before running this script.'
         exit(1)
       elsif ActiveRecord::Migrator.current_version > MAX_SUPPORTED_VERSION
         @prompt.warn 'Your version of the database schema is more recent than this script, this may cause unexpected errors.'
-        exit(1) unless @prompt.yes?('Continue anyway?')
+        exit(1) unless @prompt.yes?('Continue anyway? (Yes/No)')
+      end
+
+      if Sidekiq::ProcessSet.new.any?
+        @prompt.error 'It seems Sidekiq is running. All Mastodon processes need to be stopped when using this script.'
+        exit(1)
       end
 
       @prompt.warn 'This task will take a long time to run and is potentially destructive.'
       @prompt.warn 'Please make sure to stop Mastodon and have a backup.'
-      exit(1) unless @prompt.yes?('Continue?')
+      exit(1) unless @prompt.yes?('Continue? (Yes/No)')
 
       deduplicate_users!
       deduplicate_account_domain_blocks!
@@ -236,12 +242,14 @@ module Mastodon
         end
       end
 
-      ActiveRecord::Base.connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM users WHERE remember_token IS NOT NULL GROUP BY remember_token HAVING count(*) > 1").each do |row|
-        users = User.where(id: row['ids'].split(',')).sort_by(&:updated_at).reverse.drop(1)
-        @prompt.warn "Unsetting remember token for those accounts: #{users.map(&:account).map(&:acct).join(', ')}"
+      if ActiveRecord::Migrator.current_version < 20220118183010
+        ActiveRecord::Base.connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM users WHERE remember_token IS NOT NULL GROUP BY remember_token HAVING count(*) > 1").each do |row|
+          users = User.where(id: row['ids'].split(',')).sort_by(&:updated_at).reverse.drop(1)
+          @prompt.warn "Unsetting remember token for those accounts: #{users.map(&:account).map(&:acct).join(', ')}"
 
-        users.each do |user|
-          user.update!(remember_token: nil)
+          users.each do |user|
+            user.update!(remember_token: nil)
+          end
         end
       end
 
@@ -257,7 +265,7 @@ module Mastodon
       @prompt.say 'Restoring users indexes…'
       ActiveRecord::Base.connection.add_index :users, ['confirmation_token'], name: 'index_users_on_confirmation_token', unique: true
       ActiveRecord::Base.connection.add_index :users, ['email'], name: 'index_users_on_email', unique: true
-      ActiveRecord::Base.connection.add_index :users, ['remember_token'], name: 'index_users_on_remember_token', unique: true
+      ActiveRecord::Base.connection.add_index :users, ['remember_token'], name: 'index_users_on_remember_token', unique: true if ActiveRecord::Migrator.current_version < 20220118183010
       ActiveRecord::Base.connection.add_index :users, ['reset_password_token'], name: 'index_users_on_reset_password_token', unique: true
     end
 
@@ -274,6 +282,8 @@ module Mastodon
     end
 
     def deduplicate_account_identity_proofs!
+      return unless ActiveRecord::Base.connection.table_exists?(:account_identity_proofs)
+
       remove_index_if_exists!(:account_identity_proofs, 'index_account_proofs_on_account_and_provider_and_username')
 
       @prompt.say 'Removing duplicate account identity proofs…'