Compare commits
No commits in common. "0da08099d64b8b8d1f76199b8bfe3153f28de827" and "c0bba38af9fedfb3ecffd91837608bdaf6a987bd" have entirely different histories.
0da08099d6
...
c0bba38af9
18 changed files with 35 additions and 120 deletions
27
CHANGELOG.md
27
CHANGELOG.md
|
@ -2,34 +2,9 @@
|
|||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [4.3.8] - 2025-05-06
|
||||
|
||||
### Security
|
||||
|
||||
- Update dependencies
|
||||
- Check scheme on account, profile, and media URLs ([GHSA-x2rc-v5wx-g3m5](https://github.com/mastodon/mastodon/security/advisories/GHSA-x2rc-v5wx-g3m5))
|
||||
|
||||
### Added
|
||||
|
||||
- Add warning for REDIS_NAMESPACE deprecation at startup (#34581 by @ClearlyClaire)
|
||||
- Add built-in context for interaction policies (#34574 by @ClearlyClaire)
|
||||
|
||||
### Changed
|
||||
|
||||
- Change activity distribution error handling to skip retrying for deleted accounts (#33617 by @ClearlyClaire)
|
||||
|
||||
### Removed
|
||||
|
||||
- Remove double-query for signed query strings (#34610 by @ClearlyClaire)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix incorrect redirect in response to unauthenticated API requests in limited federation mode (#34549 by @ClearlyClaire)
|
||||
- Fix sign-up e-mail confirmation page reloading on error or redirect (#34548 by @ClearlyClaire)
|
||||
|
||||
## [4.3.7] - 2025-04-02
|
||||
|
||||
### Added
|
||||
### Add
|
||||
|
||||
- Add delay to profile updates to debounce them (#34137 by @ClearlyClaire)
|
||||
- Add support for paginating partial collections in `SynchronizeFollowersService` (#34272 and #34277 by @ClearlyClaire)
|
||||
|
|
|
@ -190,7 +190,7 @@ GEM
|
|||
activerecord (>= 5.a)
|
||||
database_cleaner-core (~> 2.0.0)
|
||||
database_cleaner-core (2.0.1)
|
||||
date (3.4.1)
|
||||
date (3.3.4)
|
||||
debug (1.9.2)
|
||||
irb (~> 1.10)
|
||||
reline (>= 0.3.8)
|
||||
|
@ -447,7 +447,7 @@ GEM
|
|||
uri
|
||||
net-http-persistent (4.0.2)
|
||||
connection_pool (~> 2.2)
|
||||
net-imap (0.5.8)
|
||||
net-imap (0.4.19)
|
||||
date
|
||||
net-protocol
|
||||
net-ldap (0.19.0)
|
||||
|
@ -458,7 +458,7 @@ GEM
|
|||
net-smtp (0.5.1)
|
||||
net-protocol
|
||||
nio4r (2.7.3)
|
||||
nokogiri (1.18.8)
|
||||
nokogiri (1.18.3)
|
||||
mini_portile2 (~> 2.8.2)
|
||||
racc (~> 1.4)
|
||||
oj (3.16.6)
|
||||
|
|
|
@ -72,13 +72,6 @@ class Api::BaseController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
# Redefine `require_functional!` to properly output JSON instead of HTML redirects
|
||||
def require_functional!
|
||||
return if current_user.functional?
|
||||
|
||||
require_user!
|
||||
end
|
||||
|
||||
def render_empty
|
||||
render json: {}, status: 200
|
||||
end
|
||||
|
|
|
@ -71,23 +71,7 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
|
||||
def require_functional!
|
||||
return if current_user.functional?
|
||||
|
||||
respond_to do |format|
|
||||
format.any do
|
||||
redirect_to edit_user_registration_path
|
||||
end
|
||||
|
||||
format.json do
|
||||
if !current_user.confirmed?
|
||||
render json: { error: 'Your login is missing a confirmed e-mail address' }, status: 403
|
||||
elsif !current_user.approved?
|
||||
render json: { error: 'Your login is currently pending approval' }, status: 403
|
||||
elsif !current_user.functional?
|
||||
render json: { error: 'Your login is currently disabled' }, status: 403
|
||||
end
|
||||
end
|
||||
end
|
||||
redirect_to edit_user_registration_path unless current_user.functional?
|
||||
end
|
||||
|
||||
def skip_csrf_meta_tags?
|
||||
|
|
|
@ -25,13 +25,6 @@ module ContextHelper
|
|||
voters_count: { 'toot' => 'http://joinmastodon.org/ns#', 'votersCount' => 'toot:votersCount' },
|
||||
suspended: { 'toot' => 'http://joinmastodon.org/ns#', 'suspended' => 'toot:suspended' },
|
||||
attribution_domains: { 'toot' => 'http://joinmastodon.org/ns#', 'attributionDomains' => { '@id' => 'toot:attributionDomains', '@type' => '@id' } },
|
||||
interaction_policies: {
|
||||
'gts' => 'https://gotosocial.org/ns#',
|
||||
'interactionPolicy' => { '@id' => 'gts:interactionPolicy', '@type' => '@id' },
|
||||
'canQuote' => { '@id' => 'gts:canQuote', '@type' => '@id' },
|
||||
'automaticApproval' => { '@id' => 'gts:automaticApproval', '@type' => '@id' },
|
||||
'manualApproval' => { '@id' => 'gts:manualApproval', '@type' => '@id' },
|
||||
},
|
||||
}.freeze
|
||||
|
||||
def full_context
|
||||
|
|
|
@ -4,12 +4,9 @@ import axios from 'axios';
|
|||
import ready from '../mastodon/ready';
|
||||
|
||||
async function checkConfirmation() {
|
||||
const response = await axios.get('/api/v1/emails/check_confirmation', {
|
||||
headers: { Accept: 'application/json' },
|
||||
withCredentials: true,
|
||||
});
|
||||
const response = await axios.get('/api/v1/emails/check_confirmation');
|
||||
|
||||
if (response.status === 200 && response.data === true) {
|
||||
if (response.data) {
|
||||
window.location.href = '/start';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,17 +80,6 @@ export function normalizeStatus(status, normalOldStatus) {
|
|||
normalStatus.contentHtml = emojify(normalStatus.content, emojiMap);
|
||||
normalStatus.spoilerHtml = emojify(escapeTextContentForBrowser(spoilerText), emojiMap);
|
||||
normalStatus.hidden = expandSpoilers ? false : spoilerText.length > 0 || normalStatus.sensitive;
|
||||
|
||||
if (normalStatus.url && !(normalStatus.url.startsWith('http://') || normalStatus.url.startsWith('https://'))) {
|
||||
normalStatus.url = null;
|
||||
}
|
||||
|
||||
normalStatus.url ||= normalStatus.uri;
|
||||
|
||||
normalStatus.media_attachments.forEach(item => {
|
||||
if (item.remote_url && !(item.remote_url.startsWith('http://') || item.remote_url.startsWith('https://')))
|
||||
item.remote_url = null;
|
||||
});
|
||||
}
|
||||
|
||||
if (normalOldStatus) {
|
||||
|
|
|
@ -150,10 +150,5 @@ export function createAccountFromServerJSON(serverJSON: ApiAccountJSON) {
|
|||
),
|
||||
note_emojified: emojify(accountJSON.note, emojiMap),
|
||||
note_plain: unescapeHTML(accountJSON.note),
|
||||
url:
|
||||
accountJSON.url.startsWith('http://') ||
|
||||
accountJSON.url.startsWith('https://')
|
||||
? accountJSON.url
|
||||
: accountJSON.uri,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -15,15 +15,13 @@ class ActivityPub::Parser::MediaAttachmentParser
|
|||
end
|
||||
|
||||
def remote_url
|
||||
url = Addressable::URI.parse(@json['url'])&.normalize&.to_s
|
||||
url unless unsupported_uri_scheme?(url)
|
||||
Addressable::URI.parse(@json['url'])&.normalize&.to_s
|
||||
rescue Addressable::URI::InvalidURIError
|
||||
nil
|
||||
end
|
||||
|
||||
def thumbnail_remote_url
|
||||
url = Addressable::URI.parse(@json['icon'].is_a?(Hash) ? @json['icon']['url'] : @json['icon'])&.normalize&.to_s
|
||||
url unless unsupported_uri_scheme?(url)
|
||||
Addressable::URI.parse(@json['icon'].is_a?(Hash) ? @json['icon']['url'] : @json['icon'])&.normalize&.to_s
|
||||
rescue Addressable::URI::InvalidURIError
|
||||
nil
|
||||
end
|
||||
|
|
|
@ -28,10 +28,7 @@ class ActivityPub::Parser::StatusParser
|
|||
end
|
||||
|
||||
def url
|
||||
return if @object['url'].blank?
|
||||
|
||||
url = url_to_href(@object['url'], 'text/html')
|
||||
url unless unsupported_uri_scheme?(url)
|
||||
url_to_href(@object['url'], 'text/html') if @object['url'].present?
|
||||
end
|
||||
|
||||
def text
|
||||
|
|
|
@ -4,7 +4,6 @@ require 'singleton'
|
|||
|
||||
class ActivityPub::TagManager
|
||||
include Singleton
|
||||
include JsonLdHelper
|
||||
include RoutingHelper
|
||||
|
||||
CONTEXT = 'https://www.w3.org/ns/activitystreams'
|
||||
|
@ -18,7 +17,7 @@ class ActivityPub::TagManager
|
|||
end
|
||||
|
||||
def url_for(target)
|
||||
return unsupported_uri_scheme?(target.url) ? nil : target.url if target.respond_to?(:local?) && !target.local?
|
||||
return target.url if target.respond_to?(:local?) && !target.local?
|
||||
|
||||
return unless target.respond_to?(:object_type)
|
||||
|
||||
|
|
|
@ -6,13 +6,14 @@
|
|||
class HttpSignatureDraft
|
||||
REQUEST_TARGET = '(request-target)'
|
||||
|
||||
def initialize(keypair, key_id)
|
||||
def initialize(keypair, key_id, full_path: true)
|
||||
@keypair = keypair
|
||||
@key_id = key_id
|
||||
@full_path = full_path
|
||||
end
|
||||
|
||||
def request_target(verb, url)
|
||||
if url.query.nil?
|
||||
if url.query.nil? || !@full_path
|
||||
"#{verb} #{url.path}"
|
||||
else
|
||||
"#{verb} #{url.path}?#{url.query}"
|
||||
|
|
|
@ -75,6 +75,7 @@ class Request
|
|||
@url = Addressable::URI.parse(url).normalize
|
||||
@http_client = options.delete(:http_client)
|
||||
@allow_local = options.delete(:allow_local)
|
||||
@full_path = !options.delete(:omit_query_string)
|
||||
@options = {
|
||||
follow: {
|
||||
max_hops: 3,
|
||||
|
@ -101,7 +102,7 @@ class Request
|
|||
|
||||
key_id = ActivityPub::TagManager.instance.key_uri_for(actor)
|
||||
keypair = sign_with.present? ? OpenSSL::PKey::RSA.new(sign_with) : actor.keypair
|
||||
@signing = HttpSignatureDraft.new(keypair, key_id)
|
||||
@signing = HttpSignatureDraft.new(keypair, key_id, full_path: @full_path)
|
||||
|
||||
self
|
||||
end
|
||||
|
|
|
@ -37,7 +37,20 @@ class ActivityPub::FetchRepliesService < BaseService
|
|||
return unless @allow_synchronous_requests
|
||||
return if non_matching_uri_hosts?(@account.uri, collection_or_uri)
|
||||
|
||||
fetch_resource_without_id_validation(collection_or_uri, nil, true)
|
||||
# NOTE: For backward compatibility reasons, Mastodon signs outgoing
|
||||
# queries incorrectly by default.
|
||||
#
|
||||
# While this is relevant for all URLs with query strings, this is
|
||||
# the only code path where this happens in practice.
|
||||
#
|
||||
# Therefore, retry with correct signatures if this fails.
|
||||
begin
|
||||
fetch_resource_without_id_validation(collection_or_uri, nil, true)
|
||||
rescue Mastodon::UnexpectedResponseError => e
|
||||
raise unless e.response && e.response.code == 401 && Addressable::URI.parse(collection_or_uri).query.present?
|
||||
|
||||
fetch_resource_without_id_validation(collection_or_uri, nil, true, request_options: { omit_query_string: false })
|
||||
end
|
||||
end
|
||||
|
||||
def filtered_replies
|
||||
|
|
|
@ -62,7 +62,7 @@ class ActivityPub::DeliveryWorker
|
|||
stoplight_wrapper.run do
|
||||
request_pool.with(@host) do |http_client|
|
||||
build_request(http_client).perform do |response|
|
||||
raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response) || unsalvageable_authorization_failure?(response)
|
||||
raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response)
|
||||
|
||||
@performed = true
|
||||
end
|
||||
|
@ -70,10 +70,6 @@ class ActivityPub::DeliveryWorker
|
|||
end
|
||||
end
|
||||
|
||||
def unsalvageable_authorization_failure?(response)
|
||||
@source_account.permanently_unavailable? && response.code == 401
|
||||
end
|
||||
|
||||
def stoplight_wrapper
|
||||
Stoplight(@inbox_url)
|
||||
.with_threshold(STOPLIGHT_FAILURE_THRESHOLD)
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
if ENV['REDIS_NAMESPACE']
|
||||
es_configured = ENV['ES_ENABLED'] == 'true' || ENV.fetch('ES_HOST', 'localhost') != 'localhost' || ENV.fetch('ES_PORT', '9200') != '9200' || ENV.fetch('ES_PASS', 'password') != 'password'
|
||||
|
||||
warn <<~MESSAGE
|
||||
WARNING: the REDIS_NAMESPACE environment variable is deprecated and will be removed in Mastodon 4.4.0.
|
||||
|
||||
Please see documentation at https://github.com/mastodon/redis_namespace_migration
|
||||
MESSAGE
|
||||
|
||||
warn <<~MESSAGE if es_configured && !ENV['ES_PREFIX']
|
||||
|
||||
In addition, as REDIS_NAMESPACE is being used as a prefix for Elasticsearch, please do not forget to set ES_PREFIX to "#{ENV.fetch('REDIS_NAMESPACE')}".
|
||||
MESSAGE
|
||||
end
|
|
@ -59,7 +59,7 @@ services:
|
|||
web:
|
||||
# You can uncomment the following line if you want to not use the prebuilt image, for example if you have local code changes
|
||||
# build: .
|
||||
image: ghcr.io/mastodon/mastodon:v4.3.8
|
||||
image: ghcr.io/mastodon/mastodon:v4.3.7
|
||||
restart: always
|
||||
env_file: .env.production
|
||||
command: bundle exec puma -C config/puma.rb
|
||||
|
@ -83,7 +83,7 @@ services:
|
|||
# build:
|
||||
# dockerfile: ./streaming/Dockerfile
|
||||
# context: .
|
||||
image: ghcr.io/mastodon/mastodon-streaming:v4.3.8
|
||||
image: ghcr.io/mastodon/mastodon-streaming:v4.3.7
|
||||
restart: always
|
||||
env_file: .env.production
|
||||
command: node ./streaming/index.js
|
||||
|
@ -102,7 +102,7 @@ services:
|
|||
sidekiq:
|
||||
# You can uncomment the following line if you want to not use the prebuilt image, for example if you have local code changes
|
||||
# build: .
|
||||
image: ghcr.io/mastodon/mastodon:v4.3.8
|
||||
image: ghcr.io/mastodon/mastodon:v4.3.7
|
||||
restart: always
|
||||
env_file: .env.production
|
||||
command: bundle exec sidekiq
|
||||
|
|
|
@ -13,7 +13,7 @@ module Mastodon
|
|||
end
|
||||
|
||||
def patch
|
||||
8
|
||||
7
|
||||
end
|
||||
|
||||
def default_prerelease
|
||||
|
|
Loading…
Add table
Reference in a new issue