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
shrike
Claire 2021-03-24 10:44:31 +01:00 committed by GitHub
parent 82556834cf
commit cbd0ee1d07
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 204 additions and 159 deletions

10
Gemfile
View File

@ -6,7 +6,7 @@ ruby '>= 2.5.0', '< 3.0.0'
gem 'pkg-config', '~> 1.4' gem 'pkg-config', '~> 1.4'
gem 'puma', '~> 5.2' gem 'puma', '~> 5.2'
gem 'rails', '~> 5.2.4.5' gem 'rails', '~> 6.1.3'
gem 'sprockets', '~> 3.7.2' gem 'sprockets', '~> 3.7.2'
gem 'thor', '~> 1.1' gem 'thor', '~> 1.1'
gem 'rack', '~> 2.2.3' gem 'rack', '~> 2.2.3'
@ -34,7 +34,7 @@ gem 'iso-639'
gem 'chewy', '~> 5.2' gem 'chewy', '~> 5.2'
gem 'cld3', '~> 3.4.1' gem 'cld3', '~> 3.4.1'
gem 'devise', '~> 4.7' 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 group :pam_authentication, optional: true do
gem 'devise_pam_authenticatable2', '~> 9.2' 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 'mime-types', '~> 3.3.1', require: 'mime/types/columnar'
gem 'nilsimsa', git: 'https://github.com/witgo/nilsimsa', ref: 'fd184883048b922b176939f851338d0a4971a532' gem 'nilsimsa', git: 'https://github.com/witgo/nilsimsa', ref: 'fd184883048b922b176939f851338d0a4971a532'
gem 'nokogiri', '~> 1.11' gem 'nokogiri', '~> 1.11'
gem 'nsa', '~> 0.2' gem 'nsa', git: 'https://github.com/Gargron/nsa', ref: 'd1079e0cdafdfed7f9f35478d13b9bdaa65965c0'
gem 'oj', '~> 3.11' gem 'oj', '~> 3.11'
gem 'ox', '~> 2.14' gem 'ox', '~> 2.14'
gem 'parslet' gem 'parslet'
@ -75,7 +75,7 @@ gem 'pundit', '~> 2.1'
gem 'premailer-rails' gem 'premailer-rails'
gem 'rack-attack', '~> 6.5' gem 'rack-attack', '~> 6.5'
gem 'rack-cors', '~> 1.1', require: 'rack/cors' 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 'rails-settings-cached', '~> 0.6'
gem 'redis', '~> 4.2', require: ['redis', 'redis/connection/hiredis'] gem 'redis', '~> 4.2', require: ['redis', 'redis/connection/hiredis']
gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock' gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
@ -159,4 +159,4 @@ gem 'concurrent-ruby', require: false
gem 'connection_pool', require: false gem 'connection_pool', require: false
gem 'xorcist', '~> 1.1' gem 'xorcist', '~> 1.1'
gem 'pluck_each', '~> 0.1.3' gem 'pluck_each', git: 'https://github.com/nsommer/pluck_each', ref: '73be0947c52fc54bf6d7085378db008358aac5eb'

View File

@ -1,3 +1,26 @@
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 GIT
remote: https://github.com/ianheggie/health_check remote: https://github.com/ianheggie/health_check
revision: 0b799ead604f900ed50685e9b2d469cd2befba5b revision: 0b799ead604f900ed50685e9b2d469cd2befba5b
@ -6,6 +29,15 @@ GIT
health_check (4.0.0.pre) health_check (4.0.0.pre)
rails (>= 4.0) 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 GIT
remote: https://github.com/witgo/nilsimsa remote: https://github.com/witgo/nilsimsa
revision: fd184883048b922b176939f851338d0a4971a532 revision: fd184883048b922b176939f851338d0a4971a532
@ -16,53 +48,71 @@ GIT
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
actioncable (5.2.4.5) actioncable (6.1.3)
actionpack (= 5.2.4.5) actionpack (= 6.1.3)
activesupport (= 6.1.3)
nio4r (~> 2.0) nio4r (~> 2.0)
websocket-driver (>= 0.6.1) websocket-driver (>= 0.6.1)
actionmailer (5.2.4.5) actionmailbox (6.1.3)
actionpack (= 5.2.4.5) actionpack (= 6.1.3)
actionview (= 5.2.4.5) activejob (= 6.1.3)
activejob (= 5.2.4.5) 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) mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
actionpack (5.2.4.5) actionpack (6.1.3)
actionview (= 5.2.4.5) actionview (= 6.1.3)
activesupport (= 5.2.4.5) activesupport (= 6.1.3)
rack (~> 2.0, >= 2.0.8) rack (~> 2.0, >= 2.0.9)
rack-test (>= 0.6.3) rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2) rails-html-sanitizer (~> 1.0, >= 1.2.0)
actionview (5.2.4.5) actiontext (6.1.3)
activesupport (= 5.2.4.5) 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) builder (~> 3.1)
erubi (~> 1.4) erubi (~> 1.4)
rails-dom-testing (~> 2.0) 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) active_model_serializers (0.10.12)
actionpack (>= 4.1, < 6.2) actionpack (>= 4.1, < 6.2)
activemodel (>= 4.1, < 6.2) activemodel (>= 4.1, < 6.2)
case_transform (>= 0.2) case_transform (>= 0.2)
jsonapi-renderer (>= 0.1.1.beta1, < 0.3) jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
active_record_query_trace (1.8) active_record_query_trace (1.8)
activejob (5.2.4.5) activejob (6.1.3)
activesupport (= 5.2.4.5) activesupport (= 6.1.3)
globalid (>= 0.3.6) globalid (>= 0.3.6)
activemodel (5.2.4.5) activemodel (6.1.3)
activesupport (= 5.2.4.5) activesupport (= 6.1.3)
activerecord (5.2.4.5) activerecord (6.1.3)
activemodel (= 5.2.4.5) activemodel (= 6.1.3)
activesupport (= 5.2.4.5) activesupport (= 6.1.3)
arel (>= 9.0) activestorage (6.1.3)
activestorage (5.2.4.5) actionpack (= 6.1.3)
actionpack (= 5.2.4.5) activejob (= 6.1.3)
activerecord (= 5.2.4.5) activerecord (= 6.1.3)
activesupport (= 6.1.3)
marcel (~> 0.3.1) marcel (~> 0.3.1)
activesupport (5.2.4.5) mimemagic (~> 0.3.2)
activesupport (6.1.3)
concurrent-ruby (~> 1.0, >= 1.0.2) concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2) i18n (>= 1.6, < 2)
minitest (~> 5.1) minitest (>= 5.1)
tzinfo (~> 1.1) tzinfo (~> 2.0)
zeitwerk (~> 2.3)
addressable (2.7.0) addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0) public_suffix (>= 2.0.2, < 5.0)
airbrussh (1.4.0) airbrussh (1.4.0)
@ -71,7 +121,6 @@ GEM
annotate (3.1.1) annotate (3.1.1)
activerecord (>= 3.2, < 7.0) activerecord (>= 3.2, < 7.0)
rake (>= 10.4, < 14.0) rake (>= 10.4, < 14.0)
arel (9.0.0)
ast (2.4.2) ast (2.4.2)
attr_encrypted (3.1.0) attr_encrypted (3.1.0)
encryptor (~> 3.0.0) encryptor (~> 3.0.0)
@ -175,12 +224,6 @@ GEM
railties (>= 4.1.0) railties (>= 4.1.0)
responders responders
warden (~> 1.2.3) 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_pam_authenticatable2 (9.2.0)
devise (>= 4.0.0) devise (>= 4.0.0)
rpam2 (~> 4.0) rpam2 (~> 4.0)
@ -370,11 +413,6 @@ GEM
racc (~> 1.4) racc (~> 1.4)
nokogumbo (2.0.4) nokogumbo (2.0.4)
nokogiri (~> 1.8, >= 1.8.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) oj (3.11.3)
omniauth (1.9.1) omniauth (1.9.1)
hashie (>= 3.4.6) hashie (>= 3.4.6)
@ -414,9 +452,6 @@ GEM
pghero (2.8.0) pghero (2.8.0)
activerecord (>= 5) activerecord (>= 5)
pkg-config (1.4.5) pkg-config (1.4.5)
pluck_each (0.1.3)
activerecord (> 3.2.0)
activesupport (> 3.0.0)
posix-spawn (0.3.15) posix-spawn (0.3.15)
premailer (1.14.2) premailer (1.14.2)
addressable addressable
@ -450,18 +485,20 @@ GEM
rack rack
rack-test (1.1.0) rack-test (1.1.0)
rack (>= 1.0, < 3) rack (>= 1.0, < 3)
rails (5.2.4.5) rails (6.1.3)
actioncable (= 5.2.4.5) actioncable (= 6.1.3)
actionmailer (= 5.2.4.5) actionmailbox (= 6.1.3)
actionpack (= 5.2.4.5) actionmailer (= 6.1.3)
actionview (= 5.2.4.5) actionpack (= 6.1.3)
activejob (= 5.2.4.5) actiontext (= 6.1.3)
activemodel (= 5.2.4.5) actionview (= 6.1.3)
activerecord (= 5.2.4.5) activejob (= 6.1.3)
activestorage (= 5.2.4.5) activemodel (= 6.1.3)
activesupport (= 5.2.4.5) activerecord (= 6.1.3)
bundler (>= 1.3.0) activestorage (= 6.1.3)
railties (= 5.2.4.5) activesupport (= 6.1.3)
bundler (>= 1.15.0)
railties (= 6.1.3)
sprockets-rails (>= 2.0.0) sprockets-rails (>= 2.0.0)
rails-controller-testing (1.0.5) rails-controller-testing (1.0.5)
actionpack (>= 5.0.1.rc1) actionpack (>= 5.0.1.rc1)
@ -472,17 +509,17 @@ GEM
nokogiri (>= 1.6) nokogiri (>= 1.6)
rails-html-sanitizer (1.3.0) rails-html-sanitizer (1.3.0)
loofah (~> 2.3) loofah (~> 2.3)
rails-i18n (5.1.3) rails-i18n (6.0.0)
i18n (>= 0.7, < 2) i18n (>= 0.7, < 2)
railties (>= 5.0, < 6) railties (>= 6.0.0, < 7)
rails-settings-cached (0.6.6) rails-settings-cached (0.6.6)
rails (>= 4.2.0) rails (>= 4.2.0)
railties (5.2.4.5) railties (6.1.3)
actionpack (= 5.2.4.5) actionpack (= 6.1.3)
activesupport (= 5.2.4.5) activesupport (= 6.1.3)
method_source method_source
rake (>= 0.8.7) rake (>= 0.8.7)
thor (>= 0.19.0, < 2.0) thor (~> 1.0)
rainbow (3.0.0) rainbow (3.0.0)
rake (13.0.3) rake (13.0.3)
rdf (3.1.13) rdf (3.1.13)
@ -500,7 +537,7 @@ GEM
actionpack (>= 5.0) actionpack (>= 5.0)
railties (>= 5.0) railties (>= 5.0)
rexml (3.2.4) rexml (3.2.4)
rotp (2.1.2) rotp (6.2.0)
rpam2 (4.0.2) rpam2 (4.0.2)
rqrcode (1.2.0) rqrcode (1.2.0)
chunky_png (~> 1.0) chunky_png (~> 1.0)
@ -600,7 +637,7 @@ GEM
net-scp (>= 1.1.2) net-scp (>= 1.1.2)
net-ssh (>= 2.8.0) net-ssh (>= 2.8.0)
stackprof (0.2.16) stackprof (0.2.16)
statsd-ruby (1.4.0) statsd-ruby (1.5.0)
stoplight (2.2.1) stoplight (2.2.1)
streamio-ffmpeg (3.0.2) streamio-ffmpeg (3.0.2)
multi_json (~> 1.8) multi_json (~> 1.8)
@ -612,7 +649,6 @@ GEM
terrapin (0.6.0) terrapin (0.6.0)
climate_control (>= 0.0.3, < 1.0) climate_control (>= 0.0.3, < 1.0)
thor (1.1.0) thor (1.1.0)
thread_safe (0.3.6)
thwait (0.2.0) thwait (0.2.0)
e2mmap e2mmap
tilt (2.0.10) tilt (2.0.10)
@ -632,8 +668,8 @@ GEM
twitter-text (3.1.0) twitter-text (3.1.0)
idn-ruby idn-ruby
unf (~> 0.1.0) unf (~> 0.1.0)
tzinfo (1.2.9) tzinfo (2.0.4)
thread_safe (~> 0.1) concurrent-ruby (~> 1.0)
tzinfo-data (1.2021.1) tzinfo-data (1.2021.1)
tzinfo (>= 1.0.0) tzinfo (>= 1.0.0)
unf (0.1.4) unf (0.1.4)
@ -672,6 +708,7 @@ GEM
xorcist (1.1.2) xorcist (1.1.2)
xpath (3.2.0) xpath (3.2.0)
nokogiri (~> 1.8) nokogiri (~> 1.8)
zeitwerk (2.4.2)
PLATFORMS PLATFORMS
ruby ruby
@ -703,7 +740,7 @@ DEPENDENCIES
concurrent-ruby concurrent-ruby
connection_pool connection_pool
devise (~> 4.7) devise (~> 4.7)
devise-two-factor (~> 3.1) devise-two-factor!
devise_pam_authenticatable2 (~> 9.2) devise_pam_authenticatable2 (~> 9.2)
discard (~> 1.2) discard (~> 1.2)
doorkeeper (~> 5.5) doorkeeper (~> 5.5)
@ -741,7 +778,7 @@ DEPENDENCIES
net-ldap (~> 0.17) net-ldap (~> 0.17)
nilsimsa! nilsimsa!
nokogiri (~> 1.11) nokogiri (~> 1.11)
nsa (~> 0.2) nsa!
oj (~> 3.11) oj (~> 3.11)
omniauth (~> 1.9) omniauth (~> 1.9)
omniauth-cas (~> 2.0) omniauth-cas (~> 2.0)
@ -756,7 +793,7 @@ DEPENDENCIES
pg (~> 1.2) pg (~> 1.2)
pghero (~> 2.8) pghero (~> 2.8)
pkg-config (~> 1.4) pkg-config (~> 1.4)
pluck_each (~> 0.1.3) pluck_each!
posix-spawn posix-spawn
premailer-rails premailer-rails
private_address_check (~> 0.5) private_address_check (~> 0.5)
@ -767,9 +804,9 @@ DEPENDENCIES
rack (~> 2.2.3) rack (~> 2.2.3)
rack-attack (~> 6.5) rack-attack (~> 6.5)
rack-cors (~> 1.1) rack-cors (~> 1.1)
rails (~> 5.2.4.5) rails (~> 6.1.3)
rails-controller-testing (~> 1.0) rails-controller-testing (~> 1.0)
rails-i18n (~> 5.1) rails-i18n (~> 6.0)
rails-settings-cached (~> 0.6) rails-settings-cached (~> 0.6)
rdf-normalize (~> 0.4) rdf-normalize (~> 0.4)
redis (~> 4.2) redis (~> 4.2)

View File

@ -5,8 +5,6 @@ class ApplicationController < ActionController::Base
# For APIs, you may want to use :null_session instead. # For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception protect_from_forgery with: :exception
force_ssl if: :https_enabled?
include Localized include Localized
include UserTrackingConcern include UserTrackingConcern
include SessionTrackingConcern include SessionTrackingConcern
@ -42,10 +40,6 @@ class ApplicationController < ActionController::Base
private private
def https_enabled?
Rails.env.production? && !request.path.start_with?('/health') && !request.headers["Host"].end_with?(".onion")
end
def authorized_fetch_mode? def authorized_fetch_mode?
ENV['AUTHORIZED_FETCH'] == 'true' || Rails.configuration.x.whitelist_mode ENV['AUTHORIZED_FETCH'] == 'true' || Rails.configuration.x.whitelist_mode
end end

View File

@ -29,7 +29,7 @@ class DeliveryFailureTracker
class << self class << self
def without_unavailable(urls) 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| urls.reject do |url|
host = Addressable::URI.parse(url).normalized_host host = Addressable::URI.parse(url).normalized_host

View File

@ -533,12 +533,12 @@ class FeedManager
arr arr
end 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[: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).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).index_with(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[: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).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).index_with(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[: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).each_with_object({}) { |id, mapping| mapping[id] = 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 crutches
end end

View File

@ -63,7 +63,7 @@ module Settings
class << self class << self
def default_settings 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) Setting.default_settings.merge!(defaulting)
end end
end end

View File

@ -67,7 +67,7 @@ module AccountInteractions
private private
def follow_mapping(query, field) def follow_mapping(query, field)
query.pluck(field).each_with_object({}) { |id, mapping| mapping[id] = true } query.pluck(field).index_with(true)
end end
end end

View File

@ -32,7 +32,7 @@ class Report < ApplicationRecord
scope :unresolved, -> { where(action_taken: false) } scope :unresolved, -> { where(action_taken: false) }
scope :resolved, -> { where(action_taken: true) } 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 } validates :comment, length: { maximum: 1000 }

View File

@ -188,8 +188,7 @@ class DeleteAccountService < BaseService
ids = favourites.pluck(:status_id) ids = favourites.pluck(:status_id)
StatusStat.where(status_id: ids).update_all('favourites_count = GREATEST(0, favourites_count - 1)') StatusStat.where(status_id: ids).update_all('favourites_count = GREATEST(0, favourites_count - 1)')
Chewy.strategy.current.update(StatusesIndex::Status, ids) if Chewy.enabled? Chewy.strategy.current.update(StatusesIndex::Status, ids) if Chewy.enabled?
# Rails.cache.delete_multi would be better, but we don't have it yet Rails.cache.delete_multi(ids.map { |id| "statuses/#{id}" })
ids.each { |id| Rails.cache.delete("statuses/#{id}") }
favourites.delete_all favourites.delete_all
end end
end end

View File

@ -45,7 +45,7 @@ class ImportService < BaseService
items = @data.take(ROWS_PROCESSING_LIMIT).map { |row| row['#domain'].strip } items = @data.take(ROWS_PROCESSING_LIMIT).map { |row| row['#domain'].strip }
if @import.overwrite? 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| @account.domain_blocks.find_each do |domain_block|
if presence_hash[domain_block.domain] if presence_hash[domain_block.domain]
@ -96,7 +96,7 @@ class ImportService < BaseService
items = @data.take(ROWS_PROCESSING_LIMIT).map { |row| row['#uri'].strip } items = @data.take(ROWS_PROCESSING_LIMIT).map { |row| row['#uri'].strip }
if @import.overwrite? 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| @account.bookmarks.find_each do |bookmark|
if presence_hash[bookmark.status.uri] if presence_hash[bookmark.status.uri]

View File

@ -1,6 +1,5 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
require 'fileutils' require "fileutils"
include FileUtils
# path to your application root. # path to your application root.
APP_ROOT = File.expand_path('..', __dir__) APP_ROOT = File.expand_path('..', __dir__)
@ -9,22 +8,25 @@ def system!(*args)
system(*args) || abort("\n== Command #{args} failed ==") system(*args) || abort("\n== Command #{args} failed ==")
end end
chdir APP_ROOT do FileUtils.chdir APP_ROOT do
# This script is a starting point to setup your application. # 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. # Add necessary setup steps to this file.
puts '== Installing dependencies ==' puts '== Installing dependencies =='
system! 'gem install bundler --conservative' system! 'gem install bundler --conservative'
system('bundle check') || system!('bundle install') system('bundle check') || system!('bundle install')
system!('yarn install')
# Install JavaScript dependencies
system! 'bin/yarn'
# puts "\n== Copying sample files ==" # puts "\n== Copying sample files =="
# unless File.exist?('config/database.yml') # unless File.exist?('config/database.yml')
# cp 'config/database.yml.sample', 'config/database.yml' # FileUtils.cp 'config/database.yml.sample', 'config/database.yml'
# end # end
puts "\n== Preparing database ==" puts "\n== Preparing database =="
system! 'bin/rails db:setup' system! 'bin/rails db:prepare'
puts "\n== Removing old logs and tempfiles ==" puts "\n== Removing old logs and tempfiles =="
system! 'bin/rails log:clear tmp:clear' system! 'bin/rails log:clear tmp:clear'

View File

@ -1,9 +1,15 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
APP_ROOT = File.expand_path('..', __dir__) APP_ROOT = File.expand_path('..', __dir__)
Dir.chdir(APP_ROOT) do Dir.chdir(APP_ROOT) do
begin yarn = ENV["PATH"].split(File::PATH_SEPARATOR).
exec "yarnpkg", *ARGV select { |dir| File.expand_path(dir) != __dir__ }.
rescue Errno::ENOENT 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 "Yarn executable was not detected in the system."
$stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install"
exit 1 exit 1

View File

@ -39,7 +39,8 @@ require_relative '../lib/mastodon/redis_config'
module Mastodon module Mastodon
class Application < Rails::Application class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version. # 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. # Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers # Application configuration should go into files in config/initializers

View File

@ -44,6 +44,13 @@ Rails.application.configure do
# Allow to specify public IP of reverse proxy if it's needed # 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.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 # Use the lowest log level to ensure availability of diagnostic information
# when problems arise. # when problems arise.
config.log_level = ENV.fetch('RAILS_LOG_LEVEL', 'info').to_sym config.log_level = ENV.fetch('RAILS_LOG_LEVEL', 'info').to_sym

View File

@ -1,6 +1,8 @@
# Be sure to restart your server when you modify this file. # Be sure to restart your server when you modify this file.
# ApplicationController.renderer.defaults.merge!( # ActiveSupport::Reloader.to_prepare do
# http_host: 'example.org', # ApplicationController.renderer.defaults.merge!(
# https: false # http_host: 'example.org',
# ) # https: false
# )
# end

View File

@ -1,7 +1,8 @@
# Be sure to restart your server when you modify this file. # 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. # 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. # 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! # by setting BACKTRACE=1 before calling your invocation, like "BACKTRACE=1 ./bin/rails runner 'MyClass.perform'".
Rails.backtrace_cleaner.remove_silencers! if ENV["BACKTRACE"]

View File

@ -49,17 +49,7 @@ end
Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
# Monkey-patching Rails 5 Rails.application.config.content_security_policy_nonce_directives = %w(style-src)
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)
PgHero::HomeController.content_security_policy do |p| PgHero::HomeController.content_security_policy do |p|
p.script_src :self, :unsafe_inline, assets_host p.script_src :self, :unsafe_inline, assets_host

View File

@ -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

View File

@ -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

0
config/storage.yml Normal file
View File

View File

@ -69,7 +69,7 @@ namespace :emojis do
end end
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 = {} map = {}
existence_maps.each do |group| existence_maps.each do |group|

View File

@ -30,8 +30,8 @@ describe Api::V1::Accounts::CredentialsController do
patch :update, params: { patch :update, params: {
display_name: "Alice Isn't Dead", display_name: "Alice Isn't Dead",
note: "Hi!\n\nToot toot!", note: "Hi!\n\nToot toot!",
avatar: fixture_file_upload('files/avatar.gif', 'image/gif'), avatar: fixture_file_upload('avatar.gif', 'image/gif'),
header: fixture_file_upload('files/attachment.jpg', 'image/jpeg'), header: fixture_file_upload('attachment.jpg', 'image/jpeg'),
source: { source: {
privacy: 'unlisted', privacy: 'unlisted',
sensitive: true, sensitive: true,

View File

@ -15,7 +15,7 @@ RSpec.describe Api::V1::MediaController, type: :controller do
context 'when imagemagick cant identify the file type' do context 'when imagemagick cant identify the file type' do
before do before do
expect_any_instance_of(Account).to receive_message_chain(:media_attachments, :create!).and_raise(Paperclip::Errors::NotIdentifiedByImageMagickError) 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 end
it 'returns http 422' do 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 context 'when there is a generic error' do
before do before do
expect_any_instance_of(Account).to receive_message_chain(:media_attachments, :create!).and_raise(Paperclip::Error) 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 end
it 'returns http 422' do it 'returns http 422' do
@ -37,7 +37,7 @@ RSpec.describe Api::V1::MediaController, type: :controller do
context 'image/jpeg' do context 'image/jpeg' do
before 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 end
it 'returns http success' do it 'returns http success' do
@ -59,7 +59,7 @@ RSpec.describe Api::V1::MediaController, type: :controller do
context 'image/gif' do context 'image/gif' do
before 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 end
it 'returns http success' do it 'returns http success' do
@ -81,7 +81,7 @@ RSpec.describe Api::V1::MediaController, type: :controller do
context 'video/webm' do context 'video/webm' do
before 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 end
it do it do

View File

@ -42,20 +42,6 @@ describe ApplicationController, type: :controller do
include_examples 'respond_with_error', 422 include_examples 'respond_with_error', 422
end 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 describe 'helper_method :current_account' do
it 'returns nil if not signed in' do it 'returns nil if not signed in' do
expect(controller.view_context.current_account).to be_nil expect(controller.view_context.current_account).to be_nil

View File

@ -21,7 +21,7 @@ RSpec.describe Settings::ImportsController, type: :controller do
post :create, params: { post :create, params: {
import: { import: {
type: 'following', 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: { post :create, params: {
import: { import: {
type: 'blocking', type: 'blocking',
data: fixture_file_upload('files/imports.txt') data: fixture_file_upload('imports.txt')
} }
} }

View File

@ -33,7 +33,7 @@ RSpec.describe Settings::ProfilesController, type: :controller do
account = Fabricate(:account, user: @user, display_name: 'AvatarTest') account = Fabricate(:account, user: @user, display_name: 'AvatarTest')
expect(account.avatar.instance.avatar_file_name).to be_nil 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(response).to redirect_to(settings_profile_path)
expect(account.reload.avatar.instance.avatar_file_name).not_to be_nil expect(account.reload.avatar.instance.avatar_file_name).not_to be_nil
expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_async).with(account.id) 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 it 'gives the user an error message' do
allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async) allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async)
account = Fabricate(:account, user: @user, display_name: 'AvatarTest') 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') expect(response.body).to include('images are not supported')
end end
end end

View File

@ -11,7 +11,7 @@ describe Settings::TwoFactorAuthentication::ConfirmationsController do
subject subject
expect(assigns(:confirmation)).to be_instance_of Form::TwoFactorConfirmation 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(assigns(:qrcode)).to be_instance_of RQRCode::QRCode
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
expect(response).to render_template(:new) expect(response).to render_template(:new)

View File

@ -99,11 +99,12 @@ RSpec.describe Setting, type: :model do
end end
it 'does not query the database' do it 'does not query the database' do
expect do |callback| callback = double
ActiveSupport::Notifications.subscribed callback, 'sql.active_record' do allow(callback).to receive(:call)
described_class[key] ActiveSupport::Notifications.subscribed callback, 'sql.active_record' do
end described_class[key]
end.not_to yield_control end
expect(callback).not_to have_received(:call)
end end
it 'returns the cached value' do it 'returns the cached value' do

View File

@ -175,7 +175,7 @@ RSpec.describe User, type: :model do
user = Fabricate(:user) user = Fabricate(:user)
ActiveJob::Base.queue_adapter = :test 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
end end