Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,26 @@

All notable changes to this project will be documented in this file.

## [4.5.3] - 2025-12-08

### Security

- Fix inconsistent error handling leaking information on existence of private posts ([GHSA-gwhw-gcjx-72v8](https://github.com/mastodon/mastodon/security/advisories/GHSA-gwhw-gcjx-72v8))

### Fixed

- Fix “Delete and Redraft” on a non-quote being treated as a quote post in some cases (#37140 by @ClearlyClaire)
- Fix YouTube embeds by sending referer (#37126 by @ChaosExAnima)
- Fix streamed quoted polls not being hydrated correctly (#37118 by @ClearlyClaire)
- Fix creation of duplicate conversations (#37108 by @oneiros)
- Fix extraneous `noreferrer` in external links (#37107 by @ChaosExAnima)
- Fix edge case error handling in some database migrations (#37079 by @ClearlyClaire)
- Fix error handling when re-fetching already-known statuses (#37077 by @ClearlyClaire)
- Fix post navigation in single-column mode when Advanced UI is enabled (#37044 by @diondiondion)
- Fix `tootctl status remove` removing quoted posts and remote quotes of local posts (#37009 by @ClearlyClaire)
- Fix known expensive S3 batch delete operation failing because of short timeouts (#37004 by @ClearlyClaire)
- Fix compose autosuggest always lowercasing input token (#36995 by @ClearlyClaire)

## [4.5.2] - 2025-11-20

### Changed
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/activitypub/likes_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def pundit_user
def set_status
@status = @account.statuses.find(params[:status_id])
authorize @status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def set_quote_authorization
return not_found unless @quote.status.present? && @quote.quoted_status.present?

authorize @quote.quoted_status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end
end
2 changes: 1 addition & 1 deletion app/controllers/activitypub/replies_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def pundit_user
def set_status
@status = @account.statuses.find(params[:status_id])
authorize @status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/activitypub/shares_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def pundit_user
def set_status
@status = @account.statuses.find(params[:status_id])
authorize @status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/api/v1/polls/votes_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def create
def set_poll
@poll = Poll.find(params[:poll_id])
authorize @poll.status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/api/v1/polls_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def show
def set_poll
@poll = Poll.find(params[:id])
authorize @poll.status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/api/v1/statuses/base_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class Api::V1::Statuses::BaseController < Api::BaseController
def set_status
@status = Status.find(params[:status_id])
authorize @status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end
end
2 changes: 1 addition & 1 deletion app/controllers/api/v1/statuses/bookmarks_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def destroy
bookmark&.destroy!

render json: @status, serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new([@status], current_account.id, bookmarks_map: { @status.id => false })
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end
end
2 changes: 1 addition & 1 deletion app/controllers/api/v1/statuses/favourites_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def destroy

relationships = StatusRelationshipsPresenter.new([@status], current_account.id, favourites_map: { @status.id => false }, attributes_map: { @status.id => { favourites_count: count } })
render json: @status, serializer: REST::StatusSerializer, relationships: relationships
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end
end
4 changes: 2 additions & 2 deletions app/controllers/api/v1/statuses/reblogs_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def destroy

relationships = StatusRelationshipsPresenter.new([@status], current_account.id, reblogs_map: { @reblog.id => false }, attributes_map: { @reblog.id => { reblogs_count: count } })
render json: @reblog, serializer: REST::StatusSerializer, relationships: relationships
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

Expand All @@ -45,7 +45,7 @@ def destroy
def set_reblog
@reblog = Status.find(params[:status_id])
authorize @reblog, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/api/v1/statuses_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def set_statuses
def set_status
@status = Status.find(params[:id])
authorize @status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/api/web/embeds_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def show
def set_status
@status = Status.find(params[:id])
authorize @status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end
end
2 changes: 1 addition & 1 deletion app/controllers/authorize_interactions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def show
def set_resource
@resource = located_resource
authorize(@resource, :show?) if @resource.is_a?(Status)
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/media_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def set_media_attachment

def verify_permitted_status!
authorize @media_attachment.status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/statuses_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def set_status
else
authorize @status, :show?
end
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

Expand Down
2 changes: 2 additions & 0 deletions app/javascript/mastodon/actions/statuses.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ export function fetchStatus(id, {
dispatch(fetchStatusSuccess(skipLoading));
}).catch(error => {
dispatch(fetchStatusFail(id, error, skipLoading, parentQuotePostId));
if (error.status === 404)
dispatch(deleteFromTimelines(id));
});
};
}
Expand Down
2 changes: 1 addition & 1 deletion app/javascript/mastodon/components/autosuggest_input.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const textAtCursorMatchesToken = (str, caretPosition, searchTokens) => {
return [null, null];
}

word = word.trim().toLowerCase();
word = word.trim();

if (word.length > 0) {
return [left + 1, word];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const textAtCursorMatchesToken = (str, caretPosition) => {
return [null, null];
}

word = word.trim().toLowerCase();
word = word.trim();

if (word.length > 0) {
return [left + 1, word];
Expand Down
2 changes: 1 addition & 1 deletion app/javascript/mastodon/components/status/handled_link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export const HandledLink: FC<HandledLinkProps & ComponentProps<'a'>> = ({
title={href}
className={classNames('unhandled-link', className)}
target='_blank'
rel='noreferrer noopener'
rel='noopener'
translate='no'
>
{children}
Expand Down
5 changes: 4 additions & 1 deletion app/javascript/mastodon/features/status/components/card.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ const handleIframeUrl = (html, url, providerName) => {
iframeUrl.searchParams.set('autoplay', 1)
iframeUrl.searchParams.set('auto_play', 1)

if (startTime && providerName === "YouTube") iframeUrl.searchParams.set('start', startTime)
if (providerName === 'YouTube') {
iframeUrl.searchParams.set('start', startTime || '');
iframe.referrerPolicy = 'strict-origin-when-cross-origin';
}

iframe.src = iframeUrl.href

Expand Down
7 changes: 4 additions & 3 deletions app/javascript/mastodon/features/ui/util/focusUtils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { initialState } from '@/mastodon/initial_state';

interface FocusColumnOptions {
index?: number;
focusItem?: 'first' | 'first-visible';
Expand All @@ -14,7 +12,10 @@ export function focusColumn({
focusItem = 'first',
}: FocusColumnOptions = {}) {
// Skip the leftmost drawer in multi-column mode
const indexOffset = initialState?.meta.advanced_layout ? 1 : 0;
const isMultiColumnLayout = !!document.querySelector(
'body.layout-multiple-columns',
);
const indexOffset = isMultiColumnLayout ? 1 : 0;

const column = document.querySelector(
`.column:nth-child(${index + indexOffset})`,
Expand Down
4 changes: 3 additions & 1 deletion app/javascript/mastodon/locales/ca.json
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@
"confirmations.missing_alt_text.title": "Hi voleu afegir text alternatiu?",
"confirmations.mute.confirm": "Silencia",
"confirmations.private_quote_notify.cancel": "Torna a l'edició",
"confirmations.private_quote_notify.confirm": "Publica la publicació",
"confirmations.private_quote_notify.do_not_show_again": "No tornis a mostrar-me aquest missatge",
"confirmations.private_quote_notify.message": "La persona que citeu i altres mencionades rebran una notificació i podran veure la vostra publicació, encara que no us segueixen.",
"confirmations.private_quote_notify.title": "Voleu compartir amb seguidors i usuaris mencionats?",
"confirmations.quiet_post_quote_info.dismiss": "No m'ho tornis a recordar",
Expand Down Expand Up @@ -339,7 +341,7 @@
"empty_column.bookmarked_statuses": "Encara no has marcat cap tut. Quan en marquis un, apareixerà aquí.",
"empty_column.community": "La línia de temps local és buida. Escriu alguna cosa públicament per posar-ho tot en marxa!",
"empty_column.direct": "Encara no tens mencions privades. Quan n'enviïs o en rebis una, et sortirà aquí.",
"empty_column.disabled_feed": "Aquest canal ha estat desactivat per l'administració del vostre servidor.",
"empty_column.disabled_feed": "L'administració del vostre servidor ha desactivat aquest canal.",
"empty_column.domain_blocks": "Encara no hi ha dominis blocats.",
"empty_column.explore_statuses": "No hi ha res en tendència ara mateix. Revisa-ho més tard!",
"empty_column.favourited_statuses": "Encara no has afavorit cap tut. Quan ho facis, apareixerà aquí.",
Expand Down
26 changes: 13 additions & 13 deletions app/javascript/mastodon/locales/da.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"about.rules": "Serverregler",
"account.account_note_header": "Personligt notat",
"account.add_or_remove_from_list": "Tilføj eller fjern fra lister",
"account.badges.bot": "Bot",
"account.badges.bot": "Automatisert",
"account.badges.group": "Gruppe",
"account.block": "Blokér @{name}",
"account.block_domain": "Blokér domænet {domain}",
Expand All @@ -28,7 +28,7 @@
"account.disable_notifications": "Giv mig ikke længere en notifikation, når @{name} laver indlæg",
"account.domain_blocking": "Blokerer domæne",
"account.edit_profile": "Redigér profil",
"account.edit_profile_short": "Redigér",
"account.edit_profile_short": "Rediger",
"account.enable_notifications": "Giv mig besked, når @{name} laver indlæg",
"account.endorse": "Fremhæv på profil",
"account.familiar_followers_many": "Følges af {name1}, {name2} og {othersCount, plural, one {# mere, man kender} other {# mere, du kender}}",
Expand Down Expand Up @@ -117,20 +117,20 @@
"annual_report.summary.archetype.lurker": "Lureren",
"annual_report.summary.archetype.oracle": "Oraklet",
"annual_report.summary.archetype.pollster": "Afstemningsmageren",
"annual_report.summary.archetype.replier": "Den social sommerfugl",
"annual_report.summary.archetype.replier": "Den sociale sommerfugl",
"annual_report.summary.followers.followers": "følgere",
"annual_report.summary.followers.total": "{count} i alt",
"annual_report.summary.here_it_is": "Her er dit {year} i sammendrag:",
"annual_report.summary.highlighted_post.by_favourites": "mest favoritmarkerede indlæg",
"annual_report.summary.highlighted_post.by_reblogs": "mest fremhævede indlæg",
"annual_report.summary.highlighted_post.by_replies": "mest besvarede indlæg",
"annual_report.summary.highlighted_post.by_replies": "indlæg med flest svar",
"annual_report.summary.highlighted_post.possessive": "{name}s",
"annual_report.summary.most_used_app.most_used_app": "mest benyttede app",
"annual_report.summary.most_used_hashtag.most_used_hashtag": "mest benyttede hashtag",
"annual_report.summary.most_used_hashtag.none": "Intet",
"annual_report.summary.new_posts.new_posts": "nye indlæg",
"annual_report.summary.percentile.text": "<topLabel>Dermed er du i top</topLabel><percentage></percentage><bottomLabel>af {domain}-brugere.</bottomLabel>",
"annual_report.summary.percentile.we_wont_tell_bernie": "Vi fortæller det ikke til Pernille Skipper.",
"annual_report.summary.percentile.we_wont_tell_bernie": "Vi fortæller det ikke til nogen.",
"annual_report.summary.thanks": "Tak for at være en del af Mastodon!",
"attachments_list.unprocessed": "(ubehandlet)",
"audio.hide": "Skjul lyd",
Expand All @@ -144,20 +144,20 @@
"block_modal.you_wont_see_mentions": "Du vil ikke se indlæg, som omtaler vedkommende.",
"boost_modal.combo": "Du kan trykke {combo} for at springe dette over næste gang",
"boost_modal.reblog": "Fremhæv indlæg?",
"boost_modal.undo_reblog": "Fjern fremhævning af indlæg?",
"boost_modal.undo_reblog": "Fjern fremhævelse af indlæg?",
"bundle_column_error.copy_stacktrace": "Kopiér fejlrapport",
"bundle_column_error.error.body": "Den anmodede side kunne ikke gengives. Dette kan skyldes flere typer fejl.",
"bundle_column_error.error.title": "Åh nej!",
"bundle_column_error.network.body": "En fejl opstod under forsøget på at indlæse denne side. Dette kan skyldes flere typer af fejl.",
"bundle_column_error.network.title": "Netværksfejl",
"bundle_column_error.retry": "Forsøg igen",
"bundle_column_error.return": "Tilbage til hjem",
"bundle_column_error.routing.body": "Den anmodede side kunne ikke findes. Er du sikker på, at URL'en er korrekt?",
"bundle_column_error.routing.body": "Den ønskede side kunne ikke findes. Er du sikker på, at URL'en i adresselinjen er korrekt?",
"bundle_column_error.routing.title": "404",
"bundle_modal_error.close": "Luk",
"bundle_modal_error.message": "Noget gik galt under indlæsningen af denne skærm.",
"bundle_modal_error.retry": "Forsøg igen",
"closed_registrations.other_server_instructions": "Da Mastodon er decentraliseret, kan du oprette en konto på en anden server og stadig interagere med denne.",
"closed_registrations.other_server_instructions": "Eftersom Mastodon er decentraliseret, kan du oprette en konto på en anden server og stadig interagere med denne.",
"closed_registrations_modal.description": "Oprettelse af en konto på {domain} er i øjeblikket ikke muligt, men husk på, at du ikke behøver en konto specifikt på {domain} for at bruge Mastodon.",
"closed_registrations_modal.find_another_server": "Find en anden server",
"closed_registrations_modal.preamble": "Mastodon er decentraliseret, så uanset hvor du opretter din konto, vil du være i stand til at følge og interagere med hvem som helst på denne server. Du kan endda selv være vært for den!",
Expand All @@ -168,7 +168,7 @@
"column.community": "Lokal tidslinje",
"column.create_list": "Opret liste",
"column.direct": "Private omtaler",
"column.directory": "Tjek profiler",
"column.directory": "Gennemse profiler",
"column.domain_blocks": "Blokerede domæner",
"column.edit_list": "Redigér liste",
"column.favourites": "Favoritter",
Expand Down Expand Up @@ -273,7 +273,7 @@
"confirmations.withdraw_request.title": "Annullér anmodning om at følge {name}?",
"content_warning.hide": "Skjul indlæg",
"content_warning.show": "Vis alligevel",
"content_warning.show_more": "Vis flere",
"content_warning.show_more": "Vis mere",
"conversation.delete": "Slet samtale",
"conversation.mark_as_read": "Markér som læst",
"conversation.open": "Vis samtale",
Expand Down Expand Up @@ -325,7 +325,7 @@
"emoji_button.not_found": "Ingen matchende emojis fundet",
"emoji_button.objects": "Objekter",
"emoji_button.people": "Personer",
"emoji_button.recent": "Oftest brugt",
"emoji_button.recent": "Ofte brugt",
"emoji_button.search": "Søg...",
"emoji_button.search_results": "Søgeresultater",
"emoji_button.symbols": "Symboler",
Expand All @@ -337,7 +337,7 @@
"empty_column.account_suspended": "Konto suspenderet",
"empty_column.account_timeline": "Ingen indlæg her!",
"empty_column.account_unavailable": "Profil utilgængelig",
"empty_column.blocks": "Ingen brugere blokeret endnu.",
"empty_column.blocks": "Du har ikke blokeret nogle brugere endnu.",
"empty_column.bookmarked_statuses": "Du har ingen bogmærkede indlæg endnu. Når du bogmærker ét, vil det dukke op hér.",
"empty_column.community": "Den lokale tidslinje er tom. Skriv noget offentligt for at sætte tingene i gang!",
"empty_column.direct": "Du har ikke nogen private omtaler endnu. Når du sender eller modtager en, vil den blive vist her.",
Expand Down Expand Up @@ -606,7 +606,7 @@
"notification.admin.report_statuses_other": "{name} anmeldte {target}",
"notification.admin.sign_up": "{name} tilmeldte sig",
"notification.admin.sign_up.name_and_others": "{name} og {count, plural, one {# anden} other {# andre}} tilmeldte sig",
"notification.annual_report.message": "{year} #Wrapstodon venter! Afslør årets højdepunkter og mindeværdige øjeblikke på Mastodon!",
"notification.annual_report.message": "Din {year} #Wrapstodon venter! Afslør årets højdepunkter og mindeværdige øjeblikke på Mastodon!",
"notification.annual_report.view": "Vis #Wrapstodon",
"notification.favourite": "{name} føjede dit indlæg til favoritter",
"notification.favourite.name_and_others_with_link": "{name} og <a>{count, plural, one {# anden} other {# andre}}</a> føjede dit indlæg til favoritter",
Expand Down
Loading
Loading