Compare commits
8 Commits
e8c5f789d6
...
2465f9d180
Author | SHA1 | Date |
---|---|---|
Ducky | 2465f9d180 | |
Claire | ebf4f034c2 | |
Claire | 889102013f | |
Claire | d94a2c8aca | |
Claire | efd066670d | |
Claire | 13ec425b72 | |
Michael Stanclift | 7a99f0744d | |
Claire | 69c8f26946 |
20
CHANGELOG.md
20
CHANGELOG.md
|
@ -3,6 +3,26 @@ Changelog
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## [4.1.5] - 2023-07-21
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Add check preventing Sidekiq workers from running with Makara configured ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/25850))
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Change request timeout handling to use a longer deadline ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26055))
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fix moderation interface for remote instances with a .zip TLD ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/25886))
|
||||||
|
- Fix remote accounts being possibly persisted to database with incomplete protocol values ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/25886))
|
||||||
|
- Fix trending publishers table not rendering correctly on narrow screens ([vmstan](https://github.com/mastodon/mastodon/pull/25945))
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
- Fix CSP headers being unintentionally wide ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26105))
|
||||||
|
|
||||||
## [4.1.4] - 2023-07-07
|
## [4.1.4] - 2023-07-07
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -4,14 +4,22 @@ require 'ipaddr'
|
||||||
require 'socket'
|
require 'socket'
|
||||||
require 'resolv'
|
require 'resolv'
|
||||||
|
|
||||||
# Monkey-patch the HTTP.rb timeout class to avoid using a timeout block
|
# Use our own timeout class to avoid using HTTP.rb's timeout block
|
||||||
# around the Socket#open method, since we use our own timeout blocks inside
|
# around the Socket#open method, since we use our own timeout blocks inside
|
||||||
# that method
|
# that method
|
||||||
#
|
#
|
||||||
# Also changes how the read timeout behaves so that it is cumulative (closer
|
# Also changes how the read timeout behaves so that it is cumulative (closer
|
||||||
# to HTTP::Timeout::Global, but still having distinct timeouts for other
|
# to HTTP::Timeout::Global, but still having distinct timeouts for other
|
||||||
# operation types)
|
# operation types)
|
||||||
class HTTP::Timeout::PerOperation
|
class PerOperationWithDeadline < HTTP::Timeout::PerOperation
|
||||||
|
READ_DEADLINE = 30
|
||||||
|
|
||||||
|
def initialize(*args)
|
||||||
|
super
|
||||||
|
|
||||||
|
@read_deadline = options.fetch(:read_deadline, READ_DEADLINE)
|
||||||
|
end
|
||||||
|
|
||||||
def connect(socket_class, host, port, nodelay = false)
|
def connect(socket_class, host, port, nodelay = false)
|
||||||
@socket = socket_class.open(host, port)
|
@socket = socket_class.open(host, port)
|
||||||
@socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) if nodelay
|
@socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) if nodelay
|
||||||
|
@ -24,7 +32,7 @@ class HTTP::Timeout::PerOperation
|
||||||
|
|
||||||
# Read data from the socket
|
# Read data from the socket
|
||||||
def readpartial(size, buffer = nil)
|
def readpartial(size, buffer = nil)
|
||||||
@deadline ||= Process.clock_gettime(Process::CLOCK_MONOTONIC) + @read_timeout
|
@deadline ||= Process.clock_gettime(Process::CLOCK_MONOTONIC) + @read_deadline
|
||||||
|
|
||||||
timeout = false
|
timeout = false
|
||||||
loop do
|
loop do
|
||||||
|
@ -33,7 +41,8 @@ class HTTP::Timeout::PerOperation
|
||||||
return :eof if result.nil?
|
return :eof if result.nil?
|
||||||
|
|
||||||
remaining_time = @deadline - Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
remaining_time = @deadline - Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
||||||
raise HTTP::TimeoutError, "Read timed out after #{@read_timeout} seconds" if timeout || remaining_time <= 0
|
raise HTTP::TimeoutError, "Read timed out after #{@read_timeout} seconds" if timeout
|
||||||
|
raise HTTP::TimeoutError, "Read timed out after a total of #{@read_deadline} seconds" if remaining_time <= 0
|
||||||
return result if result != :wait_readable
|
return result if result != :wait_readable
|
||||||
|
|
||||||
# marking the socket for timeout. Why is this not being raised immediately?
|
# marking the socket for timeout. Why is this not being raised immediately?
|
||||||
|
@ -46,7 +55,7 @@ class HTTP::Timeout::PerOperation
|
||||||
# timeout. Else, the first timeout was a proper timeout.
|
# timeout. Else, the first timeout was a proper timeout.
|
||||||
# This hack has to be done because io/wait#wait_readable doesn't provide a value for when
|
# This hack has to be done because io/wait#wait_readable doesn't provide a value for when
|
||||||
# the socket is closed by the server, and HTTP::Parser doesn't provide the limit for the chunks.
|
# the socket is closed by the server, and HTTP::Parser doesn't provide the limit for the chunks.
|
||||||
timeout = true unless @socket.to_io.wait_readable(remaining_time)
|
timeout = true unless @socket.to_io.wait_readable([remaining_time, @read_timeout].min)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -57,7 +66,7 @@ class Request
|
||||||
# We enforce a 5s timeout on DNS resolving, 5s timeout on socket opening
|
# We enforce a 5s timeout on DNS resolving, 5s timeout on socket opening
|
||||||
# and 5s timeout on the TLS handshake, meaning the worst case should take
|
# and 5s timeout on the TLS handshake, meaning the worst case should take
|
||||||
# about 15s in total
|
# about 15s in total
|
||||||
TIMEOUT = { connect: 5, read: 10, write: 10 }.freeze
|
TIMEOUT = { connect_timeout: 5, read_timeout: 10, write_timeout: 10, read_deadline: 30 }.freeze
|
||||||
|
|
||||||
include RoutingHelper
|
include RoutingHelper
|
||||||
|
|
||||||
|
@ -69,6 +78,7 @@ class Request
|
||||||
@http_client = options.delete(:http_client)
|
@http_client = options.delete(:http_client)
|
||||||
@allow_local = options.delete(:allow_local)
|
@allow_local = options.delete(:allow_local)
|
||||||
@options = options.merge(socket_class: use_proxy? || @allow_local ? ProxySocket : Socket)
|
@options = options.merge(socket_class: use_proxy? || @allow_local ? ProxySocket : Socket)
|
||||||
|
@options = @options.merge(timeout_class: PerOperationWithDeadline, timeout_options: TIMEOUT)
|
||||||
@options = @options.merge(proxy_url) if use_proxy?
|
@options = @options.merge(proxy_url) if use_proxy?
|
||||||
@headers = {}
|
@headers = {}
|
||||||
|
|
||||||
|
@ -129,7 +139,7 @@ class Request
|
||||||
end
|
end
|
||||||
|
|
||||||
def http_client
|
def http_client
|
||||||
HTTP.use(:auto_inflate).timeout(TIMEOUT.dup).follow(max_hops: 3)
|
HTTP.use(:auto_inflate).follow(max_hops: 3)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -76,6 +76,9 @@ class ActivityPub::ProcessAccountService < BaseService
|
||||||
@account.suspended_at = domain_block.created_at if auto_suspend?
|
@account.suspended_at = domain_block.created_at if auto_suspend?
|
||||||
@account.suspension_origin = :local if auto_suspend?
|
@account.suspension_origin = :local if auto_suspend?
|
||||||
@account.silenced_at = domain_block.created_at if auto_silence?
|
@account.silenced_at = domain_block.created_at if auto_silence?
|
||||||
|
|
||||||
|
set_immediate_protocol_attributes!
|
||||||
|
|
||||||
@account.save
|
@account.save
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
- Trends::PreviewCardProviderFilter::KEYS.each do |key|
|
- Trends::PreviewCardProviderFilter::KEYS.each do |key|
|
||||||
= hidden_field_tag key, params[key] if params[key].present?
|
= hidden_field_tag key, params[key] if params[key].present?
|
||||||
|
|
||||||
.batch-table.optional
|
.batch-table
|
||||||
.batch-table__toolbar
|
.batch-table__toolbar
|
||||||
%label.batch-table__toolbar__select.batch-checkbox-all
|
%label.batch-table__toolbar__select.batch-checkbox-all
|
||||||
= check_box_tag :batch_checkbox_all, nil, false
|
= check_box_tag :batch_checkbox_all, nil, false
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
|
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
|
||||||
|
|
||||||
def host_to_url(str)
|
def host_to_url(str)
|
||||||
"http#{Rails.configuration.x.use_https ? 's' : ''}://#{str}".split('/').first if str.present?
|
"http#{Rails.configuration.x.use_https ? 's' : ''}://#{str.split('/').first}" if str.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
base_host = Rails.configuration.x.web_domain
|
base_host = Rails.configuration.x.web_domain
|
||||||
|
|
|
@ -3,6 +3,11 @@
|
||||||
require_relative '../../lib/mastodon/sidekiq_middleware'
|
require_relative '../../lib/mastodon/sidekiq_middleware'
|
||||||
|
|
||||||
Sidekiq.configure_server do |config|
|
Sidekiq.configure_server do |config|
|
||||||
|
if Rails.configuration.database_configuration.dig('production', 'adapter') == 'postgresql_makara'
|
||||||
|
STDERR.puts 'ERROR: Database replication is not currently supported in Sidekiq workers. Check your configuration.'
|
||||||
|
exit 1
|
||||||
|
end
|
||||||
|
|
||||||
config.redis = REDIS_SIDEKIQ_PARAMS
|
config.redis = REDIS_SIDEKIQ_PARAMS
|
||||||
|
|
||||||
config.server_middleware do |chain|
|
config.server_middleware do |chain|
|
||||||
|
|
|
@ -292,7 +292,7 @@ Rails.application.routes.draw do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :instances, only: [:index, :show, :destroy], constraints: { id: /[^\/]+/ } do
|
resources :instances, only: [:index, :show, :destroy], constraints: { id: /[^\/]+/ }, format: 'html' do
|
||||||
member do
|
member do
|
||||||
post :clear_delivery_errors
|
post :clear_delivery_errors
|
||||||
post :restart_delivery
|
post :restart_delivery
|
||||||
|
|
|
@ -56,7 +56,7 @@ services:
|
||||||
|
|
||||||
web:
|
web:
|
||||||
build: .
|
build: .
|
||||||
image: ghcr.io/mastodon/mastodon
|
image: ghcr.io/mastodon/mastodon:v4.1.5
|
||||||
restart: always
|
restart: always
|
||||||
env_file: .env.production
|
env_file: .env.production
|
||||||
command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000"
|
command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000"
|
||||||
|
@ -77,7 +77,7 @@ services:
|
||||||
|
|
||||||
streaming:
|
streaming:
|
||||||
build: .
|
build: .
|
||||||
image: ghcr.io/mastodon/mastodon
|
image: ghcr.io/mastodon/mastodon:v4.1.5
|
||||||
restart: always
|
restart: always
|
||||||
env_file: .env.production
|
env_file: .env.production
|
||||||
command: node ./streaming
|
command: node ./streaming
|
||||||
|
@ -95,7 +95,7 @@ services:
|
||||||
|
|
||||||
sidekiq:
|
sidekiq:
|
||||||
build: .
|
build: .
|
||||||
image: ghcr.io/mastodon/mastodon
|
image: ghcr.io/mastodon/mastodon:v4.1.5
|
||||||
restart: always
|
restart: always
|
||||||
env_file: .env.production
|
env_file: .env.production
|
||||||
command: bundle exec sidekiq
|
command: bundle exec sidekiq
|
||||||
|
|
|
@ -13,7 +13,7 @@ module Mastodon
|
||||||
end
|
end
|
||||||
|
|
||||||
def patch
|
def patch
|
||||||
4
|
5
|
||||||
end
|
end
|
||||||
|
|
||||||
def flags
|
def flags
|
||||||
|
@ -21,7 +21,7 @@ module Mastodon
|
||||||
end
|
end
|
||||||
|
|
||||||
def suffix
|
def suffix
|
||||||
'-gh23200'
|
'-gh23202'
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_a
|
def to_a
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe 'Content-Security-Policy' do
|
||||||
|
it 'sets the expected CSP headers' do
|
||||||
|
allow(SecureRandom).to receive(:base64).with(16).and_return('ZbA+JmE7+bK8F5qvADZHuQ==')
|
||||||
|
|
||||||
|
get '/'
|
||||||
|
expect(response.headers['Content-Security-Policy'].split(';').map(&:strip)).to contain_exactly(
|
||||||
|
"base-uri 'none'",
|
||||||
|
"default-src 'none'",
|
||||||
|
"frame-ancestors 'none'",
|
||||||
|
"font-src 'self' https://cb6e6126.ngrok.io",
|
||||||
|
"img-src 'self' https: data: blob: https://cb6e6126.ngrok.io",
|
||||||
|
"style-src 'self' https://cb6e6126.ngrok.io 'nonce-ZbA+JmE7+bK8F5qvADZHuQ=='",
|
||||||
|
"media-src 'self' https: data: https://cb6e6126.ngrok.io",
|
||||||
|
"frame-src 'self' https:",
|
||||||
|
"manifest-src 'self' https://cb6e6126.ngrok.io",
|
||||||
|
"form-action 'self'",
|
||||||
|
"child-src 'self' blob: https://cb6e6126.ngrok.io",
|
||||||
|
"worker-src 'self' blob: https://cb6e6126.ngrok.io",
|
||||||
|
"connect-src 'self' data: blob: https://cb6e6126.ngrok.io https://cb6e6126.ngrok.io ws://localhost:4000",
|
||||||
|
"script-src 'self' https://cb6e6126.ngrok.io 'wasm-unsafe-eval'"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
Reference in New Issue