Merge tag 'v2.5.2' into HEAD
This commit is contained in:
commit
7ec79ce03f
16 changed files with 118 additions and 30 deletions
14
CHANGELOG.md
Normal file
14
CHANGELOG.md
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
## 2.5.2
|
||||||
|
|
||||||
|
- Fix XSS vulnerability (#8959)
|
||||||
|
|
||||||
|
## 2.5.1
|
||||||
|
|
||||||
|
- Fix some local images not having their EXIF metadata stripped on upload (#8714)
|
||||||
|
- Fix class autoloading issue in ActivityPub Create handler (#8820)
|
||||||
|
- Fix cache statistics not being sent via statsd when statsd enabled (#8831)
|
||||||
|
- Fix being able to enable a disabled relay via ActivityPub Accept handler (#8864)
|
||||||
|
- Bump nokogiri from 1.8.4 to 1.8.5 (#8881)
|
||||||
|
- Bump puma from 3.11.4 to 3.12.0 (#8883)
|
||||||
|
- Fix database migrations for PostgreSQL below 9.5 (#8903)
|
||||||
|
- Fix being able to report statuses not belonging to the reported account (#8916)
|
2
Gemfile
2
Gemfile
|
@ -5,7 +5,7 @@ ruby '>= 2.3.0', '< 2.6.0'
|
||||||
|
|
||||||
gem 'pkg-config', '~> 1.3'
|
gem 'pkg-config', '~> 1.3'
|
||||||
|
|
||||||
gem 'puma', '~> 3.11'
|
gem 'puma', '~> 3.12'
|
||||||
gem 'rails', '~> 5.2.1'
|
gem 'rails', '~> 5.2.1'
|
||||||
gem 'thor', '~> 0.20'
|
gem 'thor', '~> 0.20'
|
||||||
|
|
||||||
|
|
|
@ -347,7 +347,7 @@ GEM
|
||||||
net-ssh (>= 2.6.5)
|
net-ssh (>= 2.6.5)
|
||||||
net-ssh (4.2.0)
|
net-ssh (4.2.0)
|
||||||
nio4r (2.3.1)
|
nio4r (2.3.1)
|
||||||
nokogiri (1.8.4)
|
nokogiri (1.8.5)
|
||||||
mini_portile2 (~> 2.3.0)
|
mini_portile2 (~> 2.3.0)
|
||||||
nokogumbo (1.5.0)
|
nokogumbo (1.5.0)
|
||||||
nokogiri
|
nokogiri
|
||||||
|
@ -412,7 +412,7 @@ GEM
|
||||||
pry-rails (0.3.6)
|
pry-rails (0.3.6)
|
||||||
pry (>= 0.10.4)
|
pry (>= 0.10.4)
|
||||||
public_suffix (3.0.2)
|
public_suffix (3.0.2)
|
||||||
puma (3.11.4)
|
puma (3.12.0)
|
||||||
pundit (1.1.0)
|
pundit (1.1.0)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
rack (2.0.5)
|
rack (2.0.5)
|
||||||
|
@ -721,7 +721,7 @@ DEPENDENCIES
|
||||||
private_address_check (~> 0.4.1)
|
private_address_check (~> 0.4.1)
|
||||||
pry-byebug (~> 3.6)
|
pry-byebug (~> 3.6)
|
||||||
pry-rails (~> 0.3)
|
pry-rails (~> 0.3)
|
||||||
puma (~> 3.11)
|
puma (~> 3.12)
|
||||||
pundit (~> 1.1)
|
pundit (~> 1.1)
|
||||||
rack-attack (~> 5.2)
|
rack-attack (~> 5.2)
|
||||||
rack-cors (~> 1.0)
|
rack-cors (~> 1.0)
|
||||||
|
@ -765,4 +765,4 @@ RUBY VERSION
|
||||||
ruby 2.5.0p0
|
ruby 2.5.0p0
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
1.16.3
|
1.16.5
|
||||||
|
|
|
@ -27,7 +27,7 @@ class Api::V1::ReportsController < Api::BaseController
|
||||||
private
|
private
|
||||||
|
|
||||||
def reported_status_ids
|
def reported_status_ids
|
||||||
Status.find(status_ids).pluck(:id)
|
reported_account.statuses.find(status_ids).pluck(:id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def status_ids
|
def status_ids
|
||||||
|
|
|
@ -22,6 +22,12 @@ module SignatureVerification
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if request.headers['Date'].present? && !matches_time_window?
|
||||||
|
@signature_verification_failure_reason = 'Signed request date outside acceptable time window'
|
||||||
|
@signed_request_account = nil
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
raw_signature = request.headers['Signature']
|
raw_signature = request.headers['Signature']
|
||||||
signature_params = {}
|
signature_params = {}
|
||||||
|
|
||||||
|
@ -76,7 +82,7 @@ module SignatureVerification
|
||||||
def build_signed_string(signed_headers)
|
def build_signed_string(signed_headers)
|
||||||
signed_headers = 'date' if signed_headers.blank?
|
signed_headers = 'date' if signed_headers.blank?
|
||||||
|
|
||||||
signed_headers.split(' ').map do |signed_header|
|
signed_headers.downcase.split(' ').map do |signed_header|
|
||||||
if signed_header == Request::REQUEST_TARGET
|
if signed_header == Request::REQUEST_TARGET
|
||||||
"#{Request::REQUEST_TARGET}: #{request.method.downcase} #{request.path}"
|
"#{Request::REQUEST_TARGET}: #{request.method.downcase} #{request.path}"
|
||||||
elsif signed_header == 'digest'
|
elsif signed_header == 'digest'
|
||||||
|
@ -89,12 +95,12 @@ module SignatureVerification
|
||||||
|
|
||||||
def matches_time_window?
|
def matches_time_window?
|
||||||
begin
|
begin
|
||||||
time_sent = DateTime.httpdate(request.headers['Date'])
|
time_sent = Time.httpdate(request.headers['Date'])
|
||||||
rescue ArgumentError
|
rescue ArgumentError
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
(Time.now.utc - time_sent).abs <= 30
|
(Time.now.utc - time_sent).abs <= 12.hours
|
||||||
end
|
end
|
||||||
|
|
||||||
def body_digest
|
def body_digest
|
||||||
|
|
|
@ -26,7 +26,7 @@ class ActivityPub::Activity::Accept < ActivityPub::Activity
|
||||||
end
|
end
|
||||||
|
|
||||||
def relay
|
def relay
|
||||||
@relay ||= Relay.find_by(follow_activity_id: object_uri)
|
@relay ||= Relay.find_by(follow_activity_id: object_uri) unless object_uri.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
def relay_follow?
|
def relay_follow?
|
||||||
|
|
|
@ -92,7 +92,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
|
||||||
return if tag['href'].blank?
|
return if tag['href'].blank?
|
||||||
|
|
||||||
account = account_from_uri(tag['href'])
|
account = account_from_uri(tag['href'])
|
||||||
account = FetchRemoteAccountService.new.call(tag['href'], id: false) if account.nil?
|
account = ::FetchRemoteAccountService.new.call(tag['href'], id: false) if account.nil?
|
||||||
return if account.nil?
|
return if account.nil?
|
||||||
account.mentions.create(status: status)
|
account.mentions.create(status: status)
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,6 +17,8 @@ class ActivityPub::Activity::Delete < ActivityPub::Activity
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete_note
|
def delete_note
|
||||||
|
return if object_uri.nil?
|
||||||
|
|
||||||
@status = Status.find_by(uri: object_uri, account: @account)
|
@status = Status.find_by(uri: object_uri, account: @account)
|
||||||
@status ||= Status.find_by(uri: @object['atomUri'], account: @account) if @object.is_a?(Hash) && @object['atomUri'].present?
|
@status ||= Status.find_by(uri: @object['atomUri'], account: @account) if @object.is_a?(Hash) && @object['atomUri'].present?
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ class ActivityPub::Activity::Reject < ActivityPub::Activity
|
||||||
end
|
end
|
||||||
|
|
||||||
def relay
|
def relay
|
||||||
@relay ||= Relay.find_by(follow_activity_id: object_uri)
|
@relay ||= Relay.find_by(follow_activity_id: object_uri) unless object_uri.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
def relay_follow?
|
def relay_follow?
|
||||||
|
|
|
@ -19,6 +19,8 @@ class ActivityPub::Activity::Undo < ActivityPub::Activity
|
||||||
private
|
private
|
||||||
|
|
||||||
def undo_announce
|
def undo_announce
|
||||||
|
return if object_uri.nil?
|
||||||
|
|
||||||
status = Status.find_by(uri: object_uri, account: @account)
|
status = Status.find_by(uri: object_uri, account: @account)
|
||||||
status ||= Status.find_by(uri: @object['atomUri'], account: @account) if @object.is_a?(Hash) && @object['atomUri'].present?
|
status ||= Status.find_by(uri: @object['atomUri'], account: @account) if @object.is_a?(Hash) && @object['atomUri'].present?
|
||||||
|
|
||||||
|
|
|
@ -90,8 +90,12 @@ class Formatter
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def html_entities
|
||||||
|
@html_entities ||= HTMLEntities.new
|
||||||
|
end
|
||||||
|
|
||||||
def encode(html)
|
def encode(html)
|
||||||
HTMLEntities.new.encode(html)
|
html_entities.encode(html)
|
||||||
end
|
end
|
||||||
|
|
||||||
def encode_and_link_urls(html, accounts = nil, options = {})
|
def encode_and_link_urls(html, accounts = nil, options = {})
|
||||||
|
@ -143,7 +147,7 @@ class Formatter
|
||||||
emoji = emoji_map[shortcode]
|
emoji = emoji_map[shortcode]
|
||||||
|
|
||||||
if emoji
|
if emoji
|
||||||
replacement = "<img draggable=\"false\" class=\"emojione\" alt=\":#{shortcode}:\" title=\":#{shortcode}:\" src=\"#{emoji}\" />"
|
replacement = "<img draggable=\"false\" class=\"emojione\" alt=\":#{encode(shortcode)}:\" title=\":#{encode(shortcode)}:\" src=\"#{encode(emoji)}\" />"
|
||||||
before_html = shortname_start_index.positive? ? html[0..shortname_start_index - 1] : ''
|
before_html = shortname_start_index.positive? ? html[0..shortname_start_index - 1] : ''
|
||||||
html = before_html + replacement + html[i + 1..-1]
|
html = before_html + replacement + html[i + 1..-1]
|
||||||
i += replacement.size - (shortcode.size + 2) - 1
|
i += replacement.size - (shortcode.size + 2) - 1
|
||||||
|
@ -212,7 +216,7 @@ class Formatter
|
||||||
return link_to_account(acct) unless linkable_accounts
|
return link_to_account(acct) unless linkable_accounts
|
||||||
|
|
||||||
account = linkable_accounts.find { |item| TagManager.instance.same_acct?(item.acct, acct) }
|
account = linkable_accounts.find { |item| TagManager.instance.same_acct?(item.acct, acct) }
|
||||||
account ? mention_html(account) : "@#{acct}"
|
account ? mention_html(account) : "@#{encode(acct)}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def link_to_account(acct)
|
def link_to_account(acct)
|
||||||
|
@ -221,7 +225,7 @@ class Formatter
|
||||||
domain = nil if TagManager.instance.local_domain?(domain)
|
domain = nil if TagManager.instance.local_domain?(domain)
|
||||||
account = EntityCache.instance.mention(username, domain)
|
account = EntityCache.instance.mention(username, domain)
|
||||||
|
|
||||||
account ? mention_html(account) : "@#{acct}"
|
account ? mention_html(account) : "@#{encode(acct)}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def link_to_hashtag(entity)
|
def link_to_hashtag(entity)
|
||||||
|
@ -239,10 +243,10 @@ class Formatter
|
||||||
end
|
end
|
||||||
|
|
||||||
def hashtag_html(tag)
|
def hashtag_html(tag)
|
||||||
"<a href=\"#{tag_url(tag.downcase)}\" class=\"mention hashtag\" rel=\"tag\">#<span>#{tag}</span></a>"
|
"<a href=\"#{encode(tag_url(tag.downcase))}\" class=\"mention hashtag\" rel=\"tag\">#<span>#{encode(tag)}</span></a>"
|
||||||
end
|
end
|
||||||
|
|
||||||
def mention_html(account)
|
def mention_html(account)
|
||||||
"<span class=\"h-card\"><a href=\"#{TagManager.instance.url_for(account)}\" class=\"u-url mention\">@<span>#{account.username}</span></a></span>"
|
"<span class=\"h-card\"><a href=\"#{encode(TagManager.instance.url_for(account))}\" class=\"u-url mention\">@<span>#{encode(account.username)}</span></a></span>"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,7 +9,7 @@ if ENV['STATSD_ADDR'].present?
|
||||||
::NSA.inform_statsd(statsd) do |informant|
|
::NSA.inform_statsd(statsd) do |informant|
|
||||||
informant.collect(:action_controller, :web)
|
informant.collect(:action_controller, :web)
|
||||||
informant.collect(:active_record, :db)
|
informant.collect(:active_record, :db)
|
||||||
informant.collect(:cache, :cache)
|
informant.collect(:active_support_cache, :cache)
|
||||||
informant.collect(:sidekiq, :sidekiq)
|
informant.collect(:sidekiq, :sidekiq)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,15 +3,10 @@ class CopyStatusStats < ActiveRecord::Migration[5.2]
|
||||||
|
|
||||||
def up
|
def up
|
||||||
safety_assured do
|
safety_assured do
|
||||||
Status.unscoped.select('id').find_in_batches(batch_size: 5_000) do |statuses|
|
if supports_upsert?
|
||||||
execute <<-SQL.squish
|
up_fast
|
||||||
INSERT INTO status_stats (status_id, reblogs_count, favourites_count, created_at, updated_at)
|
else
|
||||||
SELECT id, reblogs_count, favourites_count, created_at, updated_at
|
up_slow
|
||||||
FROM statuses
|
|
||||||
WHERE id IN (#{statuses.map(&:id).join(', ')})
|
|
||||||
ON CONFLICT (status_id) DO UPDATE
|
|
||||||
SET reblogs_count = EXCLUDED.reblogs_count, favourites_count = EXCLUDED.favourites_count
|
|
||||||
SQL
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -19,4 +14,41 @@ class CopyStatusStats < ActiveRecord::Migration[5.2]
|
||||||
def down
|
def down
|
||||||
# Nothing
|
# Nothing
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def supports_upsert?
|
||||||
|
version = select_one("SELECT current_setting('server_version_num') AS v")['v'].to_i
|
||||||
|
version >= 90500
|
||||||
|
end
|
||||||
|
|
||||||
|
def up_fast
|
||||||
|
say 'Upsert is available, importing counters using the fast method'
|
||||||
|
|
||||||
|
Status.unscoped.select('id').find_in_batches(batch_size: 5_000) do |statuses|
|
||||||
|
execute <<-SQL.squish
|
||||||
|
INSERT INTO status_stats (status_id, reblogs_count, favourites_count, created_at, updated_at)
|
||||||
|
SELECT id, reblogs_count, favourites_count, created_at, updated_at
|
||||||
|
FROM statuses
|
||||||
|
WHERE id IN (#{statuses.map(&:id).join(', ')})
|
||||||
|
ON CONFLICT (status_id) DO UPDATE
|
||||||
|
SET reblogs_count = EXCLUDED.reblogs_count, favourites_count = EXCLUDED.favourites_count
|
||||||
|
SQL
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def up_slow
|
||||||
|
say 'Upsert is not available in PostgreSQL below 9.5, falling back to slow import of counters'
|
||||||
|
|
||||||
|
# We cannot use bulk INSERT or overarching transactions here because of possible
|
||||||
|
# uniqueness violations that we need to skip over
|
||||||
|
Status.unscoped.select('id, reblogs_count, favourites_count, created_at, updated_at').find_each do |status|
|
||||||
|
begin
|
||||||
|
params = [[nil, status.id], [nil, status.reblogs_count], [nil, status.favourites_count], [nil, status.created_at], [nil, status.updated_at]]
|
||||||
|
exec_insert('INSERT INTO status_stats (status_id, reblogs_count, favourites_count, created_at, updated_at) VALUES ($1, $2, $3, $4, $5)', nil, params)
|
||||||
|
rescue ActiveRecord::RecordNotUnique
|
||||||
|
next
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,7 +13,7 @@ module Mastodon
|
||||||
end
|
end
|
||||||
|
|
||||||
def patch
|
def patch
|
||||||
0
|
2
|
||||||
end
|
end
|
||||||
|
|
||||||
def pre
|
def pre
|
||||||
|
|
|
@ -20,7 +20,7 @@ module Paperclip
|
||||||
private
|
private
|
||||||
|
|
||||||
def needs_convert?
|
def needs_convert?
|
||||||
needs_different_geometry? || needs_different_format?
|
needs_different_geometry? || needs_different_format? || needs_metadata_stripping?
|
||||||
end
|
end
|
||||||
|
|
||||||
def needs_different_geometry?
|
def needs_different_geometry?
|
||||||
|
@ -31,5 +31,9 @@ module Paperclip
|
||||||
def needs_different_format?
|
def needs_different_format?
|
||||||
@format.present? && @current_format != @format
|
@format.present? && @current_format != @format
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def needs_metadata_stripping?
|
||||||
|
@attachment.instance.respond_to?(:local?) && @attachment.instance.local?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -73,6 +73,30 @@ describe ApplicationController, type: :controller do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with request older than a day' do
|
||||||
|
before do
|
||||||
|
get :success
|
||||||
|
|
||||||
|
fake_request = Request.new(:get, request.url)
|
||||||
|
fake_request.add_headers({ 'Date' => 2.days.ago.utc.httpdate })
|
||||||
|
fake_request.on_behalf_of(author)
|
||||||
|
|
||||||
|
request.headers.merge!(fake_request.headers)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#signed_request?' do
|
||||||
|
it 'returns true' do
|
||||||
|
expect(controller.signed_request?).to be true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#signed_request_account' do
|
||||||
|
it 'returns nil' do
|
||||||
|
expect(controller.signed_request_account).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'with body' do
|
context 'with body' do
|
||||||
before do
|
before do
|
||||||
post :success, body: 'Hello world'
|
post :success, body: 'Hello world'
|
||||||
|
|
Loading…
Reference in a new issue