about summary refs log tree commit diff
diff options
context:
space:
mode:
authorClaire <claire.github-309c@sitedethib.com>2021-03-24 10:44:31 +0100
committerGitHub <noreply@github.com>2021-03-24 10:44:31 +0100
commitcbd0ee1d07c0d48e4ed14bd446cd23d334e76da8 (patch)
treeb3bbd59f6589fefc7f88f55117951f62b5771f3d
parent82556834cf816030eac0d3f962028cb8dafac2aa (diff)
Update Mastodon to Rails 6.1 (#15910)
* Update devise-two-factor to unreleased fork for Rails 6 support

Update tests to match new `rotp` version.

* Update nsa gem to unreleased fork for Rails 6 support

* Update rails to 6.1.3 and rails-i18n to 6.0

* Update to unreleased fork of pluck_each for Ruby 6 support

* Run "rails app:update"

* Add missing ActiveStorage config file

* Use config.ssl_options instead of removed ApplicationController#force_ssl

Disabled force_ssl-related tests as they do not seem to be easily testable
anymore.

* Fix nonce directives by removing Rails 5 specific monkey-patching

* Fix fixture_file_upload deprecation warning

* Fix yield-based test failing with Rails 6

* Use Rails 6's index_with when possible

* Use ActiveRecord::Cache::Store#delete_multi from Rails 6

This will yield better performances when deleting an account

* Disable Rails 6.1's automatic preload link headers

Since Rails 6.1, ActionView adds preload links for javascript files
in the Links header per default.

In our case, that will bloat headers too much and potentially cause
issues with reverse proxies. Furhermore, we don't need those links,
as we already output them as HTML link tags.

* Switch to Rails 6.0 default config

* Switch to Rails 6.1 default config

* Do not include autoload paths in the load path
-rw-r--r--Gemfile10
-rw-r--r--Gemfile.lock181
-rw-r--r--app/controllers/application_controller.rb6
-rw-r--r--app/lib/delivery_failure_tracker.rb2
-rw-r--r--app/lib/feed_manager.rb12
-rw-r--r--app/lib/settings/scoped_settings.rb2
-rw-r--r--app/models/concerns/account_interactions.rb2
-rw-r--r--app/models/report.rb2
-rw-r--r--app/services/delete_account_service.rb3
-rw-r--r--app/services/import_service.rb4
-rwxr-xr-xbin/setup16
-rwxr-xr-xbin/yarn12
-rw-r--r--config/application.rb3
-rw-r--r--config/environments/production.rb7
-rw-r--r--config/initializers/application_controller_renderer.rb10
-rw-r--r--config/initializers/backtrace_silencers.rb7
-rw-r--r--config/initializers/content_security_policy.rb12
-rw-r--r--config/initializers/permissions_policy.rb11
-rw-r--r--config/initializers/preload_link_headers.rb8
-rw-r--r--config/storage.yml0
-rw-r--r--lib/tasks/emojis.rake2
-rw-r--r--spec/controllers/api/v1/accounts/credentials_controller_spec.rb4
-rw-r--r--spec/controllers/api/v1/media_controller_spec.rb10
-rw-r--r--spec/controllers/application_controller_spec.rb14
-rw-r--r--spec/controllers/settings/imports_controller_spec.rb4
-rw-r--r--spec/controllers/settings/profiles_controller_spec.rb4
-rw-r--r--spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb2
-rw-r--r--spec/models/setting_spec.rb11
-rw-r--r--spec/models/user_spec.rb2
29 files changed, 204 insertions, 159 deletions
diff --git a/Gemfile b/Gemfile
index 98af92def..0b2fdf156 100644
--- a/Gemfile
+++ b/Gemfile
@@ -6,7 +6,7 @@ ruby '>= 2.5.0', '< 3.0.0'
 gem 'pkg-config', '~> 1.4'
 
 gem 'puma', '~> 5.2'
-gem 'rails', '~> 5.2.4.5'
+gem 'rails', '~> 6.1.3'
 gem 'sprockets', '~> 3.7.2'
 gem 'thor', '~> 1.1'
 gem 'rack', '~> 2.2.3'
@@ -34,7 +34,7 @@ gem 'iso-639'
 gem 'chewy', '~> 5.2'
 gem 'cld3', '~> 3.4.1'
 gem 'devise', '~> 4.7'
-gem 'devise-two-factor', '~> 3.1'
+gem 'devise-two-factor', git: 'https://github.com/ClearlyClaire/devise-two-factor', ref: '594bb8a32e6f94df7e5ba7c9399eaf9ff25bac0d'
 
 group :pam_authentication, optional: true do
   gem 'devise_pam_authenticatable2', '~> 9.2'
@@ -65,7 +65,7 @@ gem 'link_header', '~> 0.0'
 gem 'mime-types', '~> 3.3.1', require: 'mime/types/columnar'
 gem 'nilsimsa', git: 'https://github.com/witgo/nilsimsa', ref: 'fd184883048b922b176939f851338d0a4971a532'
 gem 'nokogiri', '~> 1.11'
-gem 'nsa', '~> 0.2'
+gem 'nsa', git: 'https://github.com/Gargron/nsa', ref: 'd1079e0cdafdfed7f9f35478d13b9bdaa65965c0'
 gem 'oj', '~> 3.11'
 gem 'ox', '~> 2.14'
 gem 'parslet'
@@ -75,7 +75,7 @@ gem 'pundit', '~> 2.1'
 gem 'premailer-rails'
 gem 'rack-attack', '~> 6.5'
 gem 'rack-cors', '~> 1.1', require: 'rack/cors'
-gem 'rails-i18n', '~> 5.1'
+gem 'rails-i18n', '~> 6.0'
 gem 'rails-settings-cached', '~> 0.6'
 gem 'redis', '~> 4.2', require: ['redis', 'redis/connection/hiredis']
 gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
@@ -159,4 +159,4 @@ gem 'concurrent-ruby', require: false
 gem 'connection_pool', require: false
 
 gem 'xorcist', '~> 1.1'
-gem 'pluck_each', '~> 0.1.3'
+gem 'pluck_each', git: 'https://github.com/nsommer/pluck_each', ref: '73be0947c52fc54bf6d7085378db008358aac5eb'
diff --git a/Gemfile.lock b/Gemfile.lock
index 1a67f893d..1f7183b9d 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,4 +1,27 @@
 GIT
+  remote: https://github.com/ClearlyClaire/devise-two-factor
+  revision: 594bb8a32e6f94df7e5ba7c9399eaf9ff25bac0d
+  ref: 594bb8a32e6f94df7e5ba7c9399eaf9ff25bac0d
+  specs:
+    devise-two-factor (3.1.0)
+      activesupport (< 7.0)
+      attr_encrypted (>= 1.3, < 4, != 2)
+      devise
+      railties (< 7.0)
+      rotp (~> 6)
+
+GIT
+  remote: https://github.com/Gargron/nsa
+  revision: d1079e0cdafdfed7f9f35478d13b9bdaa65965c0
+  ref: d1079e0cdafdfed7f9f35478d13b9bdaa65965c0
+  specs:
+    nsa (0.2.8)
+      activesupport (>= 4.2, < 7)
+      concurrent-ruby (~> 1.0, >= 1.0.2)
+      sidekiq (>= 3.5)
+      statsd-ruby (~> 1.4, >= 1.4.0)
+
+GIT
   remote: https://github.com/ianheggie/health_check
   revision: 0b799ead604f900ed50685e9b2d469cd2befba5b
   ref: 0b799ead604f900ed50685e9b2d469cd2befba5b
@@ -7,6 +30,15 @@ GIT
       rails (>= 4.0)
 
 GIT
+  remote: https://github.com/nsommer/pluck_each
+  revision: 73be0947c52fc54bf6d7085378db008358aac5eb
+  ref: 73be0947c52fc54bf6d7085378db008358aac5eb
+  specs:
+    pluck_each (0.1.3)
+      activerecord (>= 6.1.0)
+      activesupport (>= 6.1.0)
+
+GIT
   remote: https://github.com/witgo/nilsimsa
   revision: fd184883048b922b176939f851338d0a4971a532
   ref: fd184883048b922b176939f851338d0a4971a532
@@ -16,53 +48,71 @@ GIT
 GEM
   remote: https://rubygems.org/
   specs:
-    actioncable (5.2.4.5)
-      actionpack (= 5.2.4.5)
+    actioncable (6.1.3)
+      actionpack (= 6.1.3)
+      activesupport (= 6.1.3)
       nio4r (~> 2.0)
       websocket-driver (>= 0.6.1)
-    actionmailer (5.2.4.5)
-      actionpack (= 5.2.4.5)
-      actionview (= 5.2.4.5)
-      activejob (= 5.2.4.5)
+    actionmailbox (6.1.3)
+      actionpack (= 6.1.3)
+      activejob (= 6.1.3)
+      activerecord (= 6.1.3)
+      activestorage (= 6.1.3)
+      activesupport (= 6.1.3)
+      mail (>= 2.7.1)
+    actionmailer (6.1.3)
+      actionpack (= 6.1.3)
+      actionview (= 6.1.3)
+      activejob (= 6.1.3)
+      activesupport (= 6.1.3)
       mail (~> 2.5, >= 2.5.4)
       rails-dom-testing (~> 2.0)
-    actionpack (5.2.4.5)
-      actionview (= 5.2.4.5)
-      activesupport (= 5.2.4.5)
-      rack (~> 2.0, >= 2.0.8)
+    actionpack (6.1.3)
+      actionview (= 6.1.3)
+      activesupport (= 6.1.3)
+      rack (~> 2.0, >= 2.0.9)
       rack-test (>= 0.6.3)
       rails-dom-testing (~> 2.0)
-      rails-html-sanitizer (~> 1.0, >= 1.0.2)
-    actionview (5.2.4.5)
-      activesupport (= 5.2.4.5)
+      rails-html-sanitizer (~> 1.0, >= 1.2.0)
+    actiontext (6.1.3)
+      actionpack (= 6.1.3)
+      activerecord (= 6.1.3)
+      activestorage (= 6.1.3)
+      activesupport (= 6.1.3)
+      nokogiri (>= 1.8.5)
+    actionview (6.1.3)
+      activesupport (= 6.1.3)
       builder (~> 3.1)
       erubi (~> 1.4)
       rails-dom-testing (~> 2.0)
-      rails-html-sanitizer (~> 1.0, >= 1.0.3)
+      rails-html-sanitizer (~> 1.1, >= 1.2.0)
     active_model_serializers (0.10.12)
       actionpack (>= 4.1, < 6.2)
       activemodel (>= 4.1, < 6.2)
       case_transform (>= 0.2)
       jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
     active_record_query_trace (1.8)
-    activejob (5.2.4.5)
-      activesupport (= 5.2.4.5)
+    activejob (6.1.3)
+      activesupport (= 6.1.3)
       globalid (>= 0.3.6)
-    activemodel (5.2.4.5)
-      activesupport (= 5.2.4.5)
-    activerecord (5.2.4.5)
-      activemodel (= 5.2.4.5)
-      activesupport (= 5.2.4.5)
-      arel (>= 9.0)
-    activestorage (5.2.4.5)
-      actionpack (= 5.2.4.5)
-      activerecord (= 5.2.4.5)
+    activemodel (6.1.3)
+      activesupport (= 6.1.3)
+    activerecord (6.1.3)
+      activemodel (= 6.1.3)
+      activesupport (= 6.1.3)
+    activestorage (6.1.3)
+      actionpack (= 6.1.3)
+      activejob (= 6.1.3)
+      activerecord (= 6.1.3)
+      activesupport (= 6.1.3)
       marcel (~> 0.3.1)
-    activesupport (5.2.4.5)
+      mimemagic (~> 0.3.2)
+    activesupport (6.1.3)
       concurrent-ruby (~> 1.0, >= 1.0.2)
-      i18n (>= 0.7, < 2)
-      minitest (~> 5.1)
-      tzinfo (~> 1.1)
+      i18n (>= 1.6, < 2)
+      minitest (>= 5.1)
+      tzinfo (~> 2.0)
+      zeitwerk (~> 2.3)
     addressable (2.7.0)
       public_suffix (>= 2.0.2, < 5.0)
     airbrussh (1.4.0)
@@ -71,7 +121,6 @@ GEM
     annotate (3.1.1)
       activerecord (>= 3.2, < 7.0)
       rake (>= 10.4, < 14.0)
-    arel (9.0.0)
     ast (2.4.2)
     attr_encrypted (3.1.0)
       encryptor (~> 3.0.0)
@@ -175,12 +224,6 @@ GEM
       railties (>= 4.1.0)
       responders
       warden (~> 1.2.3)
-    devise-two-factor (3.1.0)
-      activesupport (< 6.1)
-      attr_encrypted (>= 1.3, < 4, != 2)
-      devise (~> 4.0)
-      railties (< 6.1)
-      rotp (~> 2.0)
     devise_pam_authenticatable2 (9.2.0)
       devise (>= 4.0.0)
       rpam2 (~> 4.0)
@@ -370,11 +413,6 @@ GEM
       racc (~> 1.4)
     nokogumbo (2.0.4)
       nokogiri (~> 1.8, >= 1.8.4)
-    nsa (0.2.7)
-      activesupport (>= 4.2, < 6)
-      concurrent-ruby (~> 1.0, >= 1.0.2)
-      sidekiq (>= 3.5)
-      statsd-ruby (~> 1.4, >= 1.4.0)
     oj (3.11.3)
     omniauth (1.9.1)
       hashie (>= 3.4.6)
@@ -414,9 +452,6 @@ GEM
     pghero (2.8.0)
       activerecord (>= 5)
     pkg-config (1.4.5)
-    pluck_each (0.1.3)
-      activerecord (> 3.2.0)
-      activesupport (> 3.0.0)
     posix-spawn (0.3.15)
     premailer (1.14.2)
       addressable
@@ -450,18 +485,20 @@ GEM
       rack
     rack-test (1.1.0)
       rack (>= 1.0, < 3)
-    rails (5.2.4.5)
-      actioncable (= 5.2.4.5)
-      actionmailer (= 5.2.4.5)
-      actionpack (= 5.2.4.5)
-      actionview (= 5.2.4.5)
-      activejob (= 5.2.4.5)
-      activemodel (= 5.2.4.5)
-      activerecord (= 5.2.4.5)
-      activestorage (= 5.2.4.5)
-      activesupport (= 5.2.4.5)
-      bundler (>= 1.3.0)
-      railties (= 5.2.4.5)
+    rails (6.1.3)
+      actioncable (= 6.1.3)
+      actionmailbox (= 6.1.3)
+      actionmailer (= 6.1.3)
+      actionpack (= 6.1.3)
+      actiontext (= 6.1.3)
+      actionview (= 6.1.3)
+      activejob (= 6.1.3)
+      activemodel (= 6.1.3)
+      activerecord (= 6.1.3)
+      activestorage (= 6.1.3)
+      activesupport (= 6.1.3)
+      bundler (>= 1.15.0)
+      railties (= 6.1.3)
       sprockets-rails (>= 2.0.0)
     rails-controller-testing (1.0.5)
       actionpack (>= 5.0.1.rc1)
@@ -472,17 +509,17 @@ GEM
       nokogiri (>= 1.6)
     rails-html-sanitizer (1.3.0)
       loofah (~> 2.3)
-    rails-i18n (5.1.3)
+    rails-i18n (6.0.0)
       i18n (>= 0.7, < 2)
-      railties (>= 5.0, < 6)
+      railties (>= 6.0.0, < 7)
     rails-settings-cached (0.6.6)
       rails (>= 4.2.0)
-    railties (5.2.4.5)
-      actionpack (= 5.2.4.5)
-      activesupport (= 5.2.4.5)
+    railties (6.1.3)
+      actionpack (= 6.1.3)
+      activesupport (= 6.1.3)
       method_source
       rake (>= 0.8.7)
-      thor (>= 0.19.0, < 2.0)
+      thor (~> 1.0)
     rainbow (3.0.0)
     rake (13.0.3)
     rdf (3.1.13)
@@ -500,7 +537,7 @@ GEM
       actionpack (>= 5.0)
       railties (>= 5.0)
     rexml (3.2.4)
-    rotp (2.1.2)
+    rotp (6.2.0)
     rpam2 (4.0.2)
     rqrcode (1.2.0)
       chunky_png (~> 1.0)
@@ -600,7 +637,7 @@ GEM
       net-scp (>= 1.1.2)
       net-ssh (>= 2.8.0)
     stackprof (0.2.16)
-    statsd-ruby (1.4.0)
+    statsd-ruby (1.5.0)
     stoplight (2.2.1)
     streamio-ffmpeg (3.0.2)
       multi_json (~> 1.8)
@@ -612,7 +649,6 @@ GEM
     terrapin (0.6.0)
       climate_control (>= 0.0.3, < 1.0)
     thor (1.1.0)
-    thread_safe (0.3.6)
     thwait (0.2.0)
       e2mmap
     tilt (2.0.10)
@@ -632,8 +668,8 @@ GEM
     twitter-text (3.1.0)
       idn-ruby
       unf (~> 0.1.0)
-    tzinfo (1.2.9)
-      thread_safe (~> 0.1)
+    tzinfo (2.0.4)
+      concurrent-ruby (~> 1.0)
     tzinfo-data (1.2021.1)
       tzinfo (>= 1.0.0)
     unf (0.1.4)
@@ -672,6 +708,7 @@ GEM
     xorcist (1.1.2)
     xpath (3.2.0)
       nokogiri (~> 1.8)
+    zeitwerk (2.4.2)
 
 PLATFORMS
   ruby
@@ -703,7 +740,7 @@ DEPENDENCIES
   concurrent-ruby
   connection_pool
   devise (~> 4.7)
-  devise-two-factor (~> 3.1)
+  devise-two-factor!
   devise_pam_authenticatable2 (~> 9.2)
   discard (~> 1.2)
   doorkeeper (~> 5.5)
@@ -741,7 +778,7 @@ DEPENDENCIES
   net-ldap (~> 0.17)
   nilsimsa!
   nokogiri (~> 1.11)
-  nsa (~> 0.2)
+  nsa!
   oj (~> 3.11)
   omniauth (~> 1.9)
   omniauth-cas (~> 2.0)
@@ -756,7 +793,7 @@ DEPENDENCIES
   pg (~> 1.2)
   pghero (~> 2.8)
   pkg-config (~> 1.4)
-  pluck_each (~> 0.1.3)
+  pluck_each!
   posix-spawn
   premailer-rails
   private_address_check (~> 0.5)
@@ -767,9 +804,9 @@ DEPENDENCIES
   rack (~> 2.2.3)
   rack-attack (~> 6.5)
   rack-cors (~> 1.1)
-  rails (~> 5.2.4.5)
+  rails (~> 6.1.3)
   rails-controller-testing (~> 1.0)
-  rails-i18n (~> 5.1)
+  rails-i18n (~> 6.0)
   rails-settings-cached (~> 0.6)
   rdf-normalize (~> 0.4)
   redis (~> 4.2)
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 5b7eec94f..6361d4b27 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -5,8 +5,6 @@ class ApplicationController < ActionController::Base
   # For APIs, you may want to use :null_session instead.
   protect_from_forgery with: :exception
 
-  force_ssl if: :https_enabled?
-
   include Localized
   include UserTrackingConcern
   include SessionTrackingConcern
@@ -42,10 +40,6 @@ class ApplicationController < ActionController::Base
 
   private
 
-  def https_enabled?
-    Rails.env.production? && !request.path.start_with?('/health') && !request.headers["Host"].end_with?(".onion")
-  end
-
   def authorized_fetch_mode?
     ENV['AUTHORIZED_FETCH'] == 'true' || Rails.configuration.x.whitelist_mode
   end
diff --git a/app/lib/delivery_failure_tracker.rb b/app/lib/delivery_failure_tracker.rb
index 25fa694d2..2cd6ef7ad 100644
--- a/app/lib/delivery_failure_tracker.rb
+++ b/app/lib/delivery_failure_tracker.rb
@@ -29,7 +29,7 @@ class DeliveryFailureTracker
 
   class << self
     def without_unavailable(urls)
-      unavailable_domains_map = Rails.cache.fetch('unavailable_domains') { UnavailableDomain.pluck(:domain).each_with_object({}) { |domain, hash| hash[domain] = true } }
+      unavailable_domains_map = Rails.cache.fetch('unavailable_domains') { UnavailableDomain.pluck(:domain).index_with(true) }
 
       urls.reject do |url|
         host = Addressable::URI.parse(url).normalized_host
diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb
index 165338437..43aeecb35 100644
--- a/app/lib/feed_manager.rb
+++ b/app/lib/feed_manager.rb
@@ -533,12 +533,12 @@ class FeedManager
       arr
     end
 
-    crutches[:following]       = Follow.where(account_id: receiver_id, target_account_id: statuses.map(&:in_reply_to_account_id).compact).pluck(:target_account_id).each_with_object({}) { |id, mapping| mapping[id] = true }
-    crutches[:hiding_reblogs]  = Follow.where(account_id: receiver_id, target_account_id: statuses.map { |s| s.account_id if s.reblog? }.compact, show_reblogs: false).pluck(:target_account_id).each_with_object({}) { |id, mapping| mapping[id] = true }
-    crutches[:blocking]        = Block.where(account_id: receiver_id, target_account_id: check_for_blocks).pluck(:target_account_id).each_with_object({}) { |id, mapping| mapping[id] = true }
-    crutches[:muting]          = Mute.where(account_id: receiver_id, target_account_id: check_for_blocks).pluck(:target_account_id).each_with_object({}) { |id, mapping| mapping[id] = true }
-    crutches[:domain_blocking] = AccountDomainBlock.where(account_id: receiver_id, domain: statuses.map { |s| s.reblog&.account&.domain }.compact).pluck(:domain).each_with_object({}) { |domain, mapping| mapping[domain] = true }
-    crutches[:blocked_by]      = Block.where(target_account_id: receiver_id, account_id: statuses.map { |s| s.reblog&.account_id }.compact).pluck(:account_id).each_with_object({}) { |id, mapping| mapping[id] = true }
+    crutches[:following]       = Follow.where(account_id: receiver_id, target_account_id: statuses.map(&:in_reply_to_account_id).compact).pluck(:target_account_id).index_with(true)
+    crutches[:hiding_reblogs]  = Follow.where(account_id: receiver_id, target_account_id: statuses.map { |s| s.account_id if s.reblog? }.compact, show_reblogs: false).pluck(:target_account_id).index_with(true)
+    crutches[:blocking]        = Block.where(account_id: receiver_id, target_account_id: check_for_blocks).pluck(:target_account_id).index_with(true)
+    crutches[:muting]          = Mute.where(account_id: receiver_id, target_account_id: check_for_blocks).pluck(:target_account_id).index_with(true)
+    crutches[:domain_blocking] = AccountDomainBlock.where(account_id: receiver_id, domain: statuses.map { |s| s.reblog&.account&.domain }.compact).pluck(:domain).index_with(true)
+    crutches[:blocked_by]      = Block.where(target_account_id: receiver_id, account_id: statuses.map { |s| s.reblog&.account_id }.compact).pluck(:account_id).index_with(true)
 
     crutches
   end
diff --git a/app/lib/settings/scoped_settings.rb b/app/lib/settings/scoped_settings.rb
index acabf0c8e..1e18d6d46 100644
--- a/app/lib/settings/scoped_settings.rb
+++ b/app/lib/settings/scoped_settings.rb
@@ -63,7 +63,7 @@ module Settings
 
     class << self
       def default_settings
-        defaulting = DEFAULTING_TO_UNSCOPED.each_with_object({}) { |k, h| h[k] = Setting[k] }
+        defaulting = DEFAULTING_TO_UNSCOPED.index_with { |k| Setting[k] }
         Setting.default_settings.merge!(defaulting)
       end
     end
diff --git a/app/models/concerns/account_interactions.rb b/app/models/concerns/account_interactions.rb
index 974f57820..51e8e04a8 100644
--- a/app/models/concerns/account_interactions.rb
+++ b/app/models/concerns/account_interactions.rb
@@ -67,7 +67,7 @@ module AccountInteractions
     private
 
     def follow_mapping(query, field)
-      query.pluck(field).each_with_object({}) { |id, mapping| mapping[id] = true }
+      query.pluck(field).index_with(true)
     end
   end
 
diff --git a/app/models/report.rb b/app/models/report.rb
index cd08120e4..ef41547d9 100644
--- a/app/models/report.rb
+++ b/app/models/report.rb
@@ -32,7 +32,7 @@ class Report < ApplicationRecord
 
   scope :unresolved, -> { where(action_taken: false) }
   scope :resolved,   -> { where(action_taken: true) }
-  scope :with_accounts, -> { includes([:account, :target_account, :action_taken_by_account, :assigned_account].each_with_object({}) { |k, h| h[k] = { user: [:invite_request, :invite] } }) }
+  scope :with_accounts, -> { includes([:account, :target_account, :action_taken_by_account, :assigned_account].index_with({ user: [:invite_request, :invite] })) }
 
   validates :comment, length: { maximum: 1000 }
 
diff --git a/app/services/delete_account_service.rb b/app/services/delete_account_service.rb
index 802799ccd..182f0e127 100644
--- a/app/services/delete_account_service.rb
+++ b/app/services/delete_account_service.rb
@@ -188,8 +188,7 @@ class DeleteAccountService < BaseService
       ids = favourites.pluck(:status_id)
       StatusStat.where(status_id: ids).update_all('favourites_count = GREATEST(0, favourites_count - 1)')
       Chewy.strategy.current.update(StatusesIndex::Status, ids) if Chewy.enabled?
-      # Rails.cache.delete_multi would be better, but we don't have it yet
-      ids.each { |id| Rails.cache.delete("statuses/#{id}") }
+      Rails.cache.delete_multi(ids.map { |id| "statuses/#{id}" })
       favourites.delete_all
     end
   end
diff --git a/app/services/import_service.rb b/app/services/import_service.rb
index b11532283..74ad5b79f 100644
--- a/app/services/import_service.rb
+++ b/app/services/import_service.rb
@@ -45,7 +45,7 @@ class ImportService < BaseService
     items = @data.take(ROWS_PROCESSING_LIMIT).map { |row| row['#domain'].strip }
 
     if @import.overwrite?
-      presence_hash = items.each_with_object({}) { |id, mapping| mapping[id] = true }
+      presence_hash = items.index_with(true)
 
       @account.domain_blocks.find_each do |domain_block|
         if presence_hash[domain_block.domain]
@@ -96,7 +96,7 @@ class ImportService < BaseService
     items = @data.take(ROWS_PROCESSING_LIMIT).map { |row| row['#uri'].strip }
 
     if @import.overwrite?
-      presence_hash = items.each_with_object({}) { |id, mapping| mapping[id] = true }
+      presence_hash = items.index_with(true)
 
       @account.bookmarks.find_each do |bookmark|
         if presence_hash[bookmark.status.uri]
diff --git a/bin/setup b/bin/setup
index fc77b0809..90700ac4f 100755
--- a/bin/setup
+++ b/bin/setup
@@ -1,6 +1,5 @@
 #!/usr/bin/env ruby
-require 'fileutils'
-include FileUtils
+require "fileutils"
 
 # path to your application root.
 APP_ROOT = File.expand_path('..', __dir__)
@@ -9,22 +8,25 @@ def system!(*args)
   system(*args) || abort("\n== Command #{args} failed ==")
 end
 
-chdir APP_ROOT do
-  # This script is a starting point to setup your application.
+FileUtils.chdir APP_ROOT do
+  # This script is a way to set up or update your development environment automatically.
+  # This script is idempotent, so that you can run it at any time and get an expectable outcome.
   # Add necessary setup steps to this file.
 
   puts '== Installing dependencies =='
   system! 'gem install bundler --conservative'
   system('bundle check') || system!('bundle install')
-  system!('yarn install')
+
+  # Install JavaScript dependencies
+  system! 'bin/yarn'
 
   # puts "\n== Copying sample files =="
   # unless File.exist?('config/database.yml')
-  #   cp 'config/database.yml.sample', 'config/database.yml'
+  #   FileUtils.cp 'config/database.yml.sample', 'config/database.yml'
   # end
 
   puts "\n== Preparing database =="
-  system! 'bin/rails db:setup'
+  system! 'bin/rails db:prepare'
 
   puts "\n== Removing old logs and tempfiles =="
   system! 'bin/rails log:clear tmp:clear'
diff --git a/bin/yarn b/bin/yarn
index 460dd565b..9fab2c350 100755
--- a/bin/yarn
+++ b/bin/yarn
@@ -1,9 +1,15 @@
 #!/usr/bin/env ruby
 APP_ROOT = File.expand_path('..', __dir__)
 Dir.chdir(APP_ROOT) do
-  begin
-    exec "yarnpkg", *ARGV
-  rescue Errno::ENOENT
+  yarn = ENV["PATH"].split(File::PATH_SEPARATOR).
+    select { |dir| File.expand_path(dir) != __dir__ }.
+    product(["yarn", "yarn.cmd", "yarn.ps1"]).
+    map { |dir, file| File.expand_path(file, dir) }.
+    find { |file| File.executable?(file) }
+
+  if yarn
+    exec yarn, *ARGV
+  else
     $stderr.puts "Yarn executable was not detected in the system."
     $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install"
     exit 1
diff --git a/config/application.rb b/config/application.rb
index 3267fa71b..c911e76dc 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -39,7 +39,8 @@ require_relative '../lib/mastodon/redis_config'
 module Mastodon
   class Application < Rails::Application
     # Initialize configuration defaults for originally generated Rails version.
-    config.load_defaults 5.2
+    config.load_defaults 6.1
+    config.add_autoload_paths_to_load_path = false
 
     # Settings in config/environments/* take precedence over those specified here.
     # Application configuration should go into files in config/initializers
diff --git a/config/environments/production.rb b/config/environments/production.rb
index 81a67902e..6df0a3365 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -44,6 +44,13 @@ Rails.application.configure do
   # Allow to specify public IP of reverse proxy if it's needed
   config.action_dispatch.trusted_proxies = ENV['TRUSTED_PROXY_IP'].split.map { |item| IPAddr.new(item) } if ENV['TRUSTED_PROXY_IP'].present?
 
+  config.force_ssl = true
+  config.ssl_options = {
+    redirect: {
+      exclude: -> request { request.path.start_with?('/health') || request.headers["Host"].end_with?('.onion') }
+    }
+  }
+
   # Use the lowest log level to ensure availability of diagnostic information
   # when problems arise.
   config.log_level = ENV.fetch('RAILS_LOG_LEVEL', 'info').to_sym
diff --git a/config/initializers/application_controller_renderer.rb b/config/initializers/application_controller_renderer.rb
index 51639b67a..89d2efab2 100644
--- a/config/initializers/application_controller_renderer.rb
+++ b/config/initializers/application_controller_renderer.rb
@@ -1,6 +1,8 @@
 # Be sure to restart your server when you modify this file.
 
-# ApplicationController.renderer.defaults.merge!(
-#   http_host: 'example.org',
-#   https: false
-# )
+# ActiveSupport::Reloader.to_prepare do
+#   ApplicationController.renderer.defaults.merge!(
+#     http_host: 'example.org',
+#     https: false
+#   )
+# end
diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb
index 59385cdf3..33699c309 100644
--- a/config/initializers/backtrace_silencers.rb
+++ b/config/initializers/backtrace_silencers.rb
@@ -1,7 +1,8 @@
 # Be sure to restart your server when you modify this file.
 
 # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
-# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
+# Rails.backtrace_cleaner.add_silencer { |line| /my_noisy_library/.match?(line) }
 
-# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
-# Rails.backtrace_cleaner.remove_silencers!
+# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code
+# by setting BACKTRACE=1 before calling your invocation, like "BACKTRACE=1 ./bin/rails runner 'MyClass.perform'".
+Rails.backtrace_cleaner.remove_silencers! if ENV["BACKTRACE"]
diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb
index 98dc711e1..92645ff28 100644
--- a/config/initializers/content_security_policy.rb
+++ b/config/initializers/content_security_policy.rb
@@ -49,17 +49,7 @@ end
 
 Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
 
-# Monkey-patching Rails 5
-module ActionDispatch
-  class ContentSecurityPolicy
-    def nonce_directive?(directive)
-      directive == 'style-src'
-    end
-  end
-end
-
-# Rails 6 would require the following instead:
-# Rails.application.config.content_security_policy_nonce_directives = %w(style-src)
+Rails.application.config.content_security_policy_nonce_directives = %w(style-src)
 
 PgHero::HomeController.content_security_policy do |p|
   p.script_src :self, :unsafe_inline, assets_host
diff --git a/config/initializers/permissions_policy.rb b/config/initializers/permissions_policy.rb
new file mode 100644
index 000000000..00f64d71b
--- /dev/null
+++ b/config/initializers/permissions_policy.rb
@@ -0,0 +1,11 @@
+# Define an application-wide HTTP permissions policy. For further
+# information see https://developers.google.com/web/updates/2018/06/feature-policy
+#
+# Rails.application.config.permissions_policy do |f|
+#   f.camera      :none
+#   f.gyroscope   :none
+#   f.microphone  :none
+#   f.usb         :none
+#   f.fullscreen  :self
+#   f.payment     :self, "https://secure.example.com"
+# end
diff --git a/config/initializers/preload_link_headers.rb b/config/initializers/preload_link_headers.rb
new file mode 100644
index 000000000..9f21c45ec
--- /dev/null
+++ b/config/initializers/preload_link_headers.rb
@@ -0,0 +1,8 @@
+# Since Rails 6.1, ActionView adds preload links for javascript files
+# in the Links header per default.
+
+# In our case, that will bloat headers too much and potentially cause
+# issues with reverse proxies. Furhermore, we don't need those links,
+# as we already output them as HTML link tags.
+
+Rails.application.config.action_view.preload_links_header = false
diff --git a/config/storage.yml b/config/storage.yml
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/config/storage.yml
diff --git a/lib/tasks/emojis.rake b/lib/tasks/emojis.rake
index 01ae95564..c8655cc47 100644
--- a/lib/tasks/emojis.rake
+++ b/lib/tasks/emojis.rake
@@ -69,7 +69,7 @@ namespace :emojis do
       end
     end
 
-    existence_maps = grouped_codes.map { |c| c.map { |cc| [cc, File.exist?(Rails.root.join('public', 'emoji', codepoints_to_filename(cc) + '.svg'))] }.to_h }
+    existence_maps = grouped_codes.map { |c| c.index_with { |cc| File.exist?(Rails.root.join('public', 'emoji', codepoints_to_filename(cc) + '.svg')) } }
     map = {}
 
     existence_maps.each do |group|
diff --git a/spec/controllers/api/v1/accounts/credentials_controller_spec.rb b/spec/controllers/api/v1/accounts/credentials_controller_spec.rb
index ebd462a03..9fb0d8770 100644
--- a/spec/controllers/api/v1/accounts/credentials_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/credentials_controller_spec.rb
@@ -30,8 +30,8 @@ describe Api::V1::Accounts::CredentialsController do
           patch :update, params: {
             display_name: "Alice Isn't Dead",
             note: "Hi!\n\nToot toot!",
-            avatar: fixture_file_upload('files/avatar.gif', 'image/gif'),
-            header: fixture_file_upload('files/attachment.jpg', 'image/jpeg'),
+            avatar: fixture_file_upload('avatar.gif', 'image/gif'),
+            header: fixture_file_upload('attachment.jpg', 'image/jpeg'),
             source: {
               privacy: 'unlisted',
               sensitive: true,
diff --git a/spec/controllers/api/v1/media_controller_spec.rb b/spec/controllers/api/v1/media_controller_spec.rb
index 4e3037208..3eb015a1c 100644
--- a/spec/controllers/api/v1/media_controller_spec.rb
+++ b/spec/controllers/api/v1/media_controller_spec.rb
@@ -15,7 +15,7 @@ RSpec.describe Api::V1::MediaController, type: :controller do
       context 'when imagemagick cant identify the file type' do
         before do
           expect_any_instance_of(Account).to receive_message_chain(:media_attachments, :create!).and_raise(Paperclip::Errors::NotIdentifiedByImageMagickError)
-          post :create, params: { file: fixture_file_upload('files/attachment.jpg', 'image/jpeg') }
+          post :create, params: { file: fixture_file_upload('attachment.jpg', 'image/jpeg') }
         end
 
         it 'returns http 422' do
@@ -26,7 +26,7 @@ RSpec.describe Api::V1::MediaController, type: :controller do
       context 'when there is a generic error' do
         before do
           expect_any_instance_of(Account).to receive_message_chain(:media_attachments, :create!).and_raise(Paperclip::Error)
-          post :create, params: { file: fixture_file_upload('files/attachment.jpg', 'image/jpeg') }
+          post :create, params: { file: fixture_file_upload('attachment.jpg', 'image/jpeg') }
         end
 
         it 'returns http 422' do
@@ -37,7 +37,7 @@ RSpec.describe Api::V1::MediaController, type: :controller do
 
     context 'image/jpeg' do
       before do
-        post :create, params: { file: fixture_file_upload('files/attachment.jpg', 'image/jpeg') }
+        post :create, params: { file: fixture_file_upload('attachment.jpg', 'image/jpeg') }
       end
 
       it 'returns http success' do
@@ -59,7 +59,7 @@ RSpec.describe Api::V1::MediaController, type: :controller do
 
     context 'image/gif' do
       before do
-        post :create, params: { file: fixture_file_upload('files/attachment.gif', 'image/gif') }
+        post :create, params: { file: fixture_file_upload('attachment.gif', 'image/gif') }
       end
 
       it 'returns http success' do
@@ -81,7 +81,7 @@ RSpec.describe Api::V1::MediaController, type: :controller do
 
     context 'video/webm' do
       before do
-        post :create, params: { file: fixture_file_upload('files/attachment.webm', 'video/webm') }
+        post :create, params: { file: fixture_file_upload('attachment.webm', 'video/webm') }
       end
 
       it do
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index e73a08a0e..458298a6b 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -42,20 +42,6 @@ describe ApplicationController, type: :controller do
     include_examples 'respond_with_error', 422
   end
 
-  it "does not force ssl if Rails.env.production? is not 'true'" do
-    routes.draw { get 'success' => 'anonymous#success' }
-    allow(Rails.env).to receive(:production?).and_return(false)
-    get 'success'
-    expect(response).to have_http_status(200)
-  end
-
-  it "forces ssl if Rails.env.production? is 'true'" do
-    routes.draw { get 'success' => 'anonymous#success' }
-    allow(Rails.env).to receive(:production?).and_return(true)
-    get 'success'
-    expect(response).to redirect_to('https://test.host/success')
-  end
-
   describe 'helper_method :current_account' do
     it 'returns nil if not signed in' do
       expect(controller.view_context.current_account).to be_nil
diff --git a/spec/controllers/settings/imports_controller_spec.rb b/spec/controllers/settings/imports_controller_spec.rb
index 7a9b02195..b8caf5941 100644
--- a/spec/controllers/settings/imports_controller_spec.rb
+++ b/spec/controllers/settings/imports_controller_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe Settings::ImportsController, type: :controller do
       post :create, params: {
         import: {
           type: 'following',
-          data: fixture_file_upload('files/imports.txt')
+          data: fixture_file_upload('imports.txt')
         }
       }
 
@@ -34,7 +34,7 @@ RSpec.describe Settings::ImportsController, type: :controller do
       post :create, params: {
         import: {
           type: 'blocking',
-          data: fixture_file_upload('files/imports.txt')
+          data: fixture_file_upload('imports.txt')
         }
       }
 
diff --git a/spec/controllers/settings/profiles_controller_spec.rb b/spec/controllers/settings/profiles_controller_spec.rb
index 5b1fe3aca..1ac286254 100644
--- a/spec/controllers/settings/profiles_controller_spec.rb
+++ b/spec/controllers/settings/profiles_controller_spec.rb
@@ -33,7 +33,7 @@ RSpec.describe Settings::ProfilesController, type: :controller do
       account = Fabricate(:account, user: @user, display_name: 'AvatarTest')
       expect(account.avatar.instance.avatar_file_name).to be_nil
 
-      put :update, params: { account: { avatar: fixture_file_upload('files/avatar.gif', 'image/gif') } }
+      put :update, params: { account: { avatar: fixture_file_upload('avatar.gif', 'image/gif') } }
       expect(response).to redirect_to(settings_profile_path)
       expect(account.reload.avatar.instance.avatar_file_name).not_to be_nil
       expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_async).with(account.id)
@@ -44,7 +44,7 @@ RSpec.describe Settings::ProfilesController, type: :controller do
     it 'gives the user an error message' do
       allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async)
       account = Fabricate(:account, user: @user, display_name: 'AvatarTest')
-      put :update, params: { account: { avatar: fixture_file_upload('files/4096x4097.png', 'image/png') } }
+      put :update, params: { account: { avatar: fixture_file_upload('4096x4097.png', 'image/png') } }
       expect(response.body).to include('images are not supported')
     end
   end
diff --git a/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb b/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb
index cdfeef8d6..7b86513be 100644
--- a/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb
+++ b/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb
@@ -11,7 +11,7 @@ describe Settings::TwoFactorAuthentication::ConfirmationsController do
       subject
 
       expect(assigns(:confirmation)).to be_instance_of Form::TwoFactorConfirmation
-      expect(assigns(:provision_url)).to eq 'otpauth://totp/local-part@domain?secret=thisisasecretforthespecofnewview&issuer=cb6e6126.ngrok.io'
+      expect(assigns(:provision_url)).to eq 'otpauth://totp/cb6e6126.ngrok.io:local-part%40domain?secret=thisisasecretforthespecofnewview&issuer=cb6e6126.ngrok.io'
       expect(assigns(:qrcode)).to be_instance_of RQRCode::QRCode
       expect(response).to have_http_status(200)
       expect(response).to render_template(:new)
diff --git a/spec/models/setting_spec.rb b/spec/models/setting_spec.rb
index 1cc528674..3ccc21d6c 100644
--- a/spec/models/setting_spec.rb
+++ b/spec/models/setting_spec.rb
@@ -99,11 +99,12 @@ RSpec.describe Setting, type: :model do
         end
 
         it 'does not query the database' do
-          expect do |callback|
-            ActiveSupport::Notifications.subscribed callback, 'sql.active_record' do
-              described_class[key]
-            end
-          end.not_to yield_control
+          callback = double
+          allow(callback).to receive(:call)
+          ActiveSupport::Notifications.subscribed callback, 'sql.active_record' do
+            described_class[key]
+          end
+          expect(callback).not_to have_received(:call)
         end
 
         it 'returns the cached value' do
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 1dae43536..5db249be2 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -175,7 +175,7 @@ RSpec.describe User, type: :model do
       user = Fabricate(:user)
       ActiveJob::Base.queue_adapter = :test
 
-      expect { user.send_confirmation_instructions }.to have_enqueued_job(ActionMailer::DeliveryJob)
+      expect { user.send_confirmation_instructions }.to have_enqueued_job(ActionMailer::MailDeliveryJob)
     end
   end