mirror of
https://github.com/mastodon/mastodon.git
synced 2025-05-07 20:26:15 +00:00
Compare commits
5 Commits
6d2696ca55
...
173ad2494e
Author | SHA1 | Date | |
---|---|---|---|
![]() |
173ad2494e | ||
![]() |
fbe9728f36 | ||
![]() |
3bbf3e9709 | ||
![]() |
79931bf3ae | ||
![]() |
41118205be |
27
CHANGELOG.md
27
CHANGELOG.md
|
@ -2,9 +2,34 @@
|
|||
|
||||
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
|
||||
|
||||
### Add
|
||||
### Added
|
||||
|
||||
- Add delay to profile updates to debounce them (#34137 by @ClearlyClaire)
|
||||
- Add support for paginating partial collections in `SynchronizeFollowersService` (#34272 and #34277 by @ClearlyClaire)
|
||||
|
|
|
@ -77,6 +77,17 @@ 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) {
|
||||
|
|
|
@ -144,5 +144,10 @@ 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,13 +15,15 @@ class ActivityPub::Parser::MediaAttachmentParser
|
|||
end
|
||||
|
||||
def remote_url
|
||||
Addressable::URI.parse(@json['url'])&.normalize&.to_s
|
||||
url = Addressable::URI.parse(@json['url'])&.normalize&.to_s
|
||||
url unless unsupported_uri_scheme?(url)
|
||||
rescue Addressable::URI::InvalidURIError
|
||||
nil
|
||||
end
|
||||
|
||||
def thumbnail_remote_url
|
||||
Addressable::URI.parse(@json['icon'].is_a?(Hash) ? @json['icon']['url'] : @json['icon'])&.normalize&.to_s
|
||||
url = Addressable::URI.parse(@json['icon'].is_a?(Hash) ? @json['icon']['url'] : @json['icon'])&.normalize&.to_s
|
||||
url unless unsupported_uri_scheme?(url)
|
||||
rescue Addressable::URI::InvalidURIError
|
||||
nil
|
||||
end
|
||||
|
|
|
@ -29,7 +29,10 @@ class ActivityPub::Parser::StatusParser
|
|||
end
|
||||
|
||||
def url
|
||||
url_to_href(@object['url'], 'text/html') if @object['url'].present?
|
||||
return if @object['url'].blank?
|
||||
|
||||
url = url_to_href(@object['url'], 'text/html')
|
||||
url unless unsupported_uri_scheme?(url)
|
||||
end
|
||||
|
||||
def text
|
||||
|
|
|
@ -4,6 +4,7 @@ require 'singleton'
|
|||
|
||||
class ActivityPub::TagManager
|
||||
include Singleton
|
||||
include JsonLdHelper
|
||||
include RoutingHelper
|
||||
|
||||
CONTEXT = 'https://www.w3.org/ns/activitystreams'
|
||||
|
@ -17,7 +18,7 @@ class ActivityPub::TagManager
|
|||
end
|
||||
|
||||
def url_for(target)
|
||||
return target.url if target.respond_to?(:local?) && !target.local?
|
||||
return unsupported_uri_scheme?(target.url) ? nil : target.url if target.respond_to?(:local?) && !target.local?
|
||||
|
||||
return unless target.respond_to?(:object_type)
|
||||
|
||||
|
|
|
@ -106,12 +106,11 @@ class FetchLinkCardService < BaseService
|
|||
end
|
||||
|
||||
def attempt_oembed
|
||||
service = FetchOEmbedService.new
|
||||
url_domain = Addressable::URI.parse(@url).normalized_host
|
||||
cached_endpoint = Rails.cache.read("oembed_endpoint:#{url_domain}")
|
||||
service = FetchOEmbedService.new
|
||||
|
||||
embed = service.call(@url, cached_endpoint: cached_endpoint) unless cached_endpoint.nil?
|
||||
embed = service.call(@url, use_cached_endpoint: true)
|
||||
embed ||= service.call(@url, html: html) unless html.nil?
|
||||
embed ||= service.call(@url, use_cached_endpoint: true) if @url != @original_url.to_s
|
||||
|
||||
return false if embed.nil?
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ class FetchOEmbedService
|
|||
@url = url
|
||||
@options = options
|
||||
|
||||
if @options[:cached_endpoint]
|
||||
if @options[:use_cached_endpoint]
|
||||
parse_cached_endpoint!
|
||||
else
|
||||
discover_endpoint!
|
||||
|
@ -57,9 +57,9 @@ class FetchOEmbedService
|
|||
end
|
||||
|
||||
def parse_cached_endpoint!
|
||||
cached = @options[:cached_endpoint]
|
||||
cached = Rails.cache.read(cache_key)
|
||||
|
||||
return if cached[:endpoint].nil? || cached[:format].nil?
|
||||
return if cached.nil? || cached[:endpoint].nil? || cached[:format].nil?
|
||||
|
||||
@endpoint_url = Addressable::Template.new(cached[:endpoint]).expand(url: @url).to_s
|
||||
@format = cached[:format]
|
||||
|
@ -68,14 +68,16 @@ class FetchOEmbedService
|
|||
def cache_endpoint!
|
||||
return unless URL_REGEX.match?(@endpoint_url)
|
||||
|
||||
url_domain = Addressable::URI.parse(@url).normalized_host
|
||||
|
||||
endpoint_hash = {
|
||||
endpoint: @endpoint_url.gsub(URL_REGEX, '={url}'),
|
||||
format: @format,
|
||||
}
|
||||
|
||||
Rails.cache.write("oembed_endpoint:#{url_domain}", endpoint_hash, expires_in: ENDPOINT_CACHE_EXPIRES_IN)
|
||||
Rails.cache.write(cache_key, endpoint_hash, expires_in: ENDPOINT_CACHE_EXPIRES_IN)
|
||||
end
|
||||
|
||||
def cache_key
|
||||
"oembed_endpoint:#{Addressable::URI.parse(@url).normalized_host}"
|
||||
end
|
||||
|
||||
def fetch!
|
||||
|
|
|
@ -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.7
|
||||
image: ghcr.io/mastodon/mastodon:v4.3.8
|
||||
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.7
|
||||
image: ghcr.io/mastodon/mastodon-streaming:v4.3.8
|
||||
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.7
|
||||
image: ghcr.io/mastodon/mastodon:v4.3.8
|
||||
restart: always
|
||||
env_file: .env.production
|
||||
command: bundle exec sidekiq
|
||||
|
|
|
@ -17,7 +17,7 @@ module Mastodon
|
|||
end
|
||||
|
||||
def default_prerelease
|
||||
'alpha.4'
|
||||
'alpha.5'
|
||||
end
|
||||
|
||||
def prerelease
|
||||
|
|
|
@ -13,6 +13,7 @@ RSpec.describe FetchLinkCardService do
|
|||
stub_request(:get, 'http://example.com/not-found').to_return(status: 404, headers: { 'Content-Type' => 'text/html' }, body: html)
|
||||
stub_request(:get, 'http://example.com/text').to_return(status: 404, headers: { 'Content-Type' => 'text/plain' }, body: 'Hello')
|
||||
stub_request(:get, 'http://example.com/redirect').to_return(status: 302, headers: { 'Location' => 'http://example.com/html' })
|
||||
stub_request(:get, 'http://example.net/redirect-to-other-domain').to_return(status: 302, headers: { 'Location' => 'http://example.com/html' })
|
||||
stub_request(:get, 'http://example.com/redirect-to-404').to_return(status: 302, headers: { 'Location' => 'http://example.com/not-found' })
|
||||
stub_request(:get, 'http://example.com/oembed?url=http://example.com/html').to_return(headers: { 'Content-Type' => 'application/json' }, body: '{ "version": "1.0", "type": "link", "title": "oEmbed title" }')
|
||||
stub_request(:get, 'http://example.com/oembed?format=json&url=http://example.com/html').to_return(headers: { 'Content-Type' => 'application/json' }, body: '{ "version": "1.0", "type": "link", "title": "oEmbed title" }')
|
||||
|
@ -264,6 +265,39 @@ RSpec.describe FetchLinkCardService do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when oEmbed endpoint cache populated with redirect target' do
|
||||
let(:status) { Fabricate(:status, text: 'http://example.net/redirect-to-other-domain') }
|
||||
let(:oembed_cache) { { endpoint: 'http://example.com/oembed?format=json&url={url}', format: :json } }
|
||||
|
||||
it 'uses the cached oEmbed response' do
|
||||
expect(a_request(:get, 'http://example.net/redirect-to-other-domain')).to have_been_made
|
||||
expect(a_request(:get, 'http://example.com/oembed?url=http://example.com/html')).to have_been_made
|
||||
end
|
||||
|
||||
it 'creates preview card' do
|
||||
expect(status.preview_card).to_not be_nil
|
||||
expect(status.preview_card.url).to eq 'http://example.com/html'
|
||||
expect(status.preview_card.title).to eq 'oEmbed title'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when oEmbed endpoint cache populated with redirect target but page contains no oEmbed tags' do
|
||||
let(:status) { Fabricate(:status, text: 'http://example.net/redirect-to-other-domain') }
|
||||
let(:html) { 'Please fill out CAPTCHA' }
|
||||
let(:oembed_cache) { { endpoint: 'http://example.com/oembed?format=json&url={url}', format: :json } }
|
||||
|
||||
it 'uses the cached oEmbed response' do
|
||||
expect(a_request(:get, 'http://example.net/redirect-to-other-domain')).to have_been_made
|
||||
expect(a_request(:get, 'http://example.com/oembed?format=json&url=http://example.com/html')).to have_been_made
|
||||
end
|
||||
|
||||
it 'creates preview card' do
|
||||
expect(status.preview_card).to_not be_nil
|
||||
expect(status.preview_card.url).to eq 'http://example.com/html'
|
||||
expect(status.preview_card.title).to eq 'oEmbed title'
|
||||
end
|
||||
end
|
||||
|
||||
# If the original HTML URL for whatever reason (e.g. DOS protection) redirects to
|
||||
# an error page, we can still use the cached oEmbed but should not use the
|
||||
# redirect URL on the card.
|
||||
|
|
|
@ -160,10 +160,12 @@ RSpec.describe FetchOEmbedService do
|
|||
headers: { 'Content-Type': 'text/html' },
|
||||
body: request_fixture('oembed_json_empty.html')
|
||||
)
|
||||
|
||||
Rails.cache.write('oembed_endpoint:www.youtube.com', { endpoint: 'http://www.youtube.com/oembed?format=json&url={url}', format: :json })
|
||||
end
|
||||
|
||||
it 'returns new provider without fetching original URL first' do
|
||||
subject.call('https://www.youtube.com/watch?v=dqwpQarrDwk', cached_endpoint: { endpoint: 'http://www.youtube.com/oembed?format=json&url={url}', format: :json })
|
||||
subject.call('https://www.youtube.com/watch?v=dqwpQarrDwk', use_cached_endpoint: true)
|
||||
expect(a_request(:get, 'https://www.youtube.com/watch?v=dqwpQarrDwk')).to_not have_been_made
|
||||
expect(subject.endpoint_url).to eq 'http://www.youtube.com/oembed?format=json&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DdqwpQarrDwk'
|
||||
expect(subject.format).to eq :json
|
||||
|
|
Loading…
Reference in New Issue
Block a user