Compare commits

...

14 Commits

Author SHA1 Message Date
nachtjasmin 54bcf3dc11
Add styles for "multiple choice" toggle 2023-12-29 20:00:00 +01:00
nachtjasmin 427f510187
Remove wrong negation to fix the alt text badge 2023-12-29 17:15:20 +01:00
nachtjasmin ab5df86dd2
Merge tag 'v4.2.3' into lets-bump-hometown-to-mastodon-4.2 2023-12-29 17:15:15 +01:00
nachtjasmin ded251fffc
Move inline CSS into our overrides scss 2023-12-29 17:14:35 +01:00
nachtjasmin 6af838b2ba
Compare rendered mails with correct site title 2023-12-29 17:14:35 +01:00
nachtjasmin 15d191f50c
Allow non-public posts to be pinned 2023-12-29 17:14:35 +01:00
nachtjasmin 07cfc26116
Ensure correct functionality of new ActivityPub messages 2023-12-29 17:14:35 +01:00
nachtjasmin d39e16d5cc
Remove h1 conversion spec 2023-12-29 17:14:35 +01:00
nachtjasmin 1cc6d4bfcf
Align html sanitizing closer to upstream 2023-12-29 17:14:35 +01:00
nachtjasmin ca313dd4fe
Fix ruby specs 2023-12-29 17:14:35 +01:00
nachtjasmin 6ffaafbdde
Manually bump json-canonicalization to 0.3.3
0.3.2 does not exist anymore, therefore the GitHub Actions are failing
  right now.
2023-12-29 17:14:35 +01:00
nachtjasmin 4c01f78480
Automatic rubocop fixing 2023-12-29 17:14:35 +01:00
Claire 90371a4fc4 Bump version to v4.2.3 2023-12-05 15:35:05 +01:00
Claire 71b60b09f4 Update dependency json-ld to v3.3.1 2023-12-05 15:35:05 +01:00
23 changed files with 146 additions and 97 deletions

View File

@ -1,6 +1,6 @@
# This configuration was generated by
# `rubocop --auto-gen-config --auto-gen-only-exclude --no-exclude-limit --no-offense-counts --no-auto-gen-timestamp`
# using RuboCop version 1.56.1.
# using RuboCop version 1.56.3.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
@ -54,6 +54,11 @@ Layout/SpaceInLambdaLiteral:
- 'config/environments/production.rb'
- 'config/initializers/content_security_policy.rb'
# Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches.
Lint/DuplicateBranch:
Exclude:
- 'app/lib/account_statuses_filter.rb'
# Configuration parameters: AllowComments, AllowEmptyLambdas.
Lint/EmptyBlock:
Exclude:
@ -105,7 +110,7 @@ Lint/UselessAssignment:
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
Metrics/AbcSize:
Max: 144
Max: 149
# Configuration parameters: CountBlocks, Max.
Metrics/BlockNesting:
@ -289,6 +294,14 @@ RSpec/MultipleMemoizedHelpers:
RSpec/NestedGroups:
Max: 6
RSpec/RepeatedDescription:
Exclude:
- 'spec/controllers/activitypub/outboxes_controller_spec.rb'
RSpec/RepeatedExample:
Exclude:
- 'spec/controllers/activitypub/outboxes_controller_spec.rb'
# This cop supports unsafe autocorrection (--autocorrect-all).
Rails/ApplicationController:
Exclude:
@ -314,6 +327,12 @@ Rails/DuplicateAssociation:
- 'app/serializers/activitypub/collection_serializer.rb'
- 'app/serializers/activitypub/note_serializer.rb'
# Configuration parameters: Include.
# Include: app/**/*.rb, config/**/*.rb, lib/**/*.rb
Rails/Exit:
Exclude:
- 'config/initializers/sidekiq.rb'
# Configuration parameters: Include.
# Include: app/models/**/*.rb
Rails/HasAndBelongsToMany:
@ -364,7 +383,6 @@ Rails/NegateInclude:
- 'app/models/custom_filter.rb'
- 'app/services/activitypub/process_status_update_service.rb'
- 'app/services/fetch_link_card_service.rb'
- 'app/services/search_service.rb'
- 'app/workers/web/push_notification_worker.rb'
- 'lib/paperclip/color_extractor.rb'
@ -400,7 +418,9 @@ Rails/ReversibleMigration:
- 'db/migrate/20171226094803_more_faster_index_on_notifications.rb'
- 'db/migrate/20180106000232_add_index_on_statuses_for_api_v1_accounts_account_id_statuses.rb'
- 'db/migrate/20180617162849_remove_unused_indexes.rb'
- 'db/migrate/20190726034905_add_is_exclusive_to_lists.rb'
- 'db/migrate/20220827195229_change_canonical_email_blocks_nullable.rb'
- 'db/migrate/20221202035831_add_keep_local_to_account_statuses_cleanup_policies.rb'
# Configuration parameters: ForbiddenMethods, AllowedMethods.
# ForbiddenMethods: decrement!, decrement_counter, increment!, increment_counter, insert, insert!, insert_all, insert_all!, toggle!, touch, touch_all, update_all, update_attribute, update_column, update_columns, update_counters, upsert, upsert_all
@ -466,8 +486,10 @@ Rails/ThreeStateBooleanColumn:
- 'db/migrate/20170209184350_add_reply_to_statuses.rb'
- 'db/migrate/20170330163835_create_imports.rb'
- 'db/migrate/20170905165803_add_local_to_statuses.rb'
- 'db/migrate/20171210213213_add_local_only_flag_to_statuses.rb'
- 'db/migrate/20181203021853_add_discoverable_to_accounts.rb'
- 'db/migrate/20190509164208_add_by_moderator_to_tombstone.rb'
- 'db/migrate/20190726034905_add_is_exclusive_to_lists.rb'
- 'db/migrate/20190805123746_add_capabilities_to_tags.rb'
- 'db/migrate/20191212163405_add_hide_collections_to_accounts.rb'
- 'db/migrate/20200309150742_add_forwarded_to_reports.rb'
@ -478,6 +500,7 @@ Rails/ThreeStateBooleanColumn:
- 'db/migrate/20220202200743_add_trendable_to_accounts.rb'
- 'db/migrate/20220202200926_add_trendable_to_statuses.rb'
- 'db/migrate/20220303000827_add_ordered_media_attachment_ids_to_status_edits.rb'
- 'db/migrate/20221202035831_add_keep_local_to_account_statuses_cleanup_policies.rb'
# Configuration parameters: Include.
# Include: app/models/**/*.rb
@ -756,7 +779,6 @@ Style/RedundantReturn:
Style/SafeNavigation:
Exclude:
- 'app/models/concerns/account_finder_concern.rb'
- 'app/models/status.rb'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyle.

View File

@ -2,6 +2,12 @@
All notable changes to this project will be documented in this file.
## [4.2.3] - 2023-12-05
### Fixed
- Fix dependency on `json-canonicalization` version that has been made unavailable since last release
## [4.2.2] - 2023-12-04
### Changed

View File

@ -148,6 +148,7 @@ GEM
net-http-persistent (~> 4.0)
nokogiri (~> 1, >= 1.10.8)
base64 (0.1.1)
bcp47_spec (0.2.1)
bcrypt (3.1.18)
better_errors (2.10.1)
erubi (>= 1.0.0)
@ -377,19 +378,19 @@ GEM
ipaddress (0.8.3)
jmespath (1.6.2)
json (2.6.3)
json-canonicalization (0.3.2)
json-canonicalization (1.0.0)
json-jwt (1.15.3)
activesupport (>= 4.2)
aes_key_wrap
bindata
httpclient
json-ld (3.2.5)
json-ld (3.3.1)
htmlentities (~> 4.3)
json-canonicalization (~> 0.3, >= 0.3.2)
json-canonicalization (~> 1.0)
link_header (~> 0.0, >= 0.0.8)
multi_json (~> 1.15)
rack (>= 2.2, < 4)
rdf (~> 3.2, >= 3.2.10)
rdf (~> 3.3)
json-ld-preloaded (3.2.2)
json-ld (~> 3.2)
rdf (~> 3.2)
@ -593,7 +594,8 @@ GEM
zeitwerk (~> 2.5)
rainbow (3.1.1)
rake (13.0.6)
rdf (3.2.11)
rdf (3.3.1)
bcp47_spec (~> 0.2)
link_header (~> 0.0, >= 0.0.8)
rdf-normalize (0.6.1)
rdf (~> 3.2)

View File

@ -101,7 +101,7 @@ class Item extends PureComponent {
height = 50;
}
const hasMediaDescription = !attachment.get('description')?.length > 0;
const hasMediaDescription = attachment.get('description')?.length > 0;
if (hasMediaDescription) {
badges.push(<span key='alt' className='media-gallery__gifv__label'>ALT</span>);
}

View File

@ -164,6 +164,8 @@ class PollForm extends ImmutablePureComponent {
<ul>
{options.map((title, i) => <Option title={title} lang={lang} key={i} index={i} onChange={onChangeOption} onRemove={onRemoveOption} isPollMultiple={isMultiple} onToggleMultiple={this.handleToggleMultiple} autoFocus={i === autoFocusIndex} {...other} />)}
</ul>
{/* Hometown: Clicking the poll checkboxes is not accessible at all, therefore we add a dedicated toggle. */}
<div className='is-multiple-toggle'>
<Toggle className='is-multiple-checkbox' checked={isMultiple} onChange={this.handleToggleMultiple} />
<span className='is-multiple-toggle__label'>

View File

@ -43,3 +43,21 @@
.dismissable-banner:has([href='/explore']) {
display: none;
}
// app/views/statuses/_simple_status.html.haml
// Set width and height for the local-only indicator
.status__action-bar-button.icon-button:has(.fw.fa-chain-broken) {
font-size: 18px;
width: 23.1429px;
height: 23.1429px;
line-height: 23.15px;
}
// app/javascript/mastodon/features/compose/components/poll_form.jsx
// Add some custom styling for the "multiple choice" selection button
.compose-form__poll-wrapper .is-multiple-toggle {
padding: 10px; // same as the poll options above it
display: inline-flex;
align-items: center;
gap: 10px; // same as the padding
}

View File

@ -20,7 +20,7 @@ class ActivityPub::Activity::Add < ActivityPub::Activity
def add_featured
status = status_from_object
return unless !status.nil? && status.account_id == @account.id && !@account.pinned?(status) && status.distributable?
return unless !status.nil? && status.account_id == @account.id && !@account.pinned?(status)
StatusPin.create!(account: @account, status: status)
end

View File

@ -111,33 +111,32 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
def process_status_params
@status_parser = ActivityPub::Parser::StatusParser.new(@json, followers_collection: @account.followers_url)
@params = begin
{
uri: @status_parser.uri,
url: @status_parser.url || @status_parser.uri,
account: @account,
text: text_from_content || '',
language: @status_parser.language,
spoiler_text: converted_object_type? ? '' : (@status_parser.spoiler_text || (@object['type'] == 'Article' && text_from_name) || ''),
created_at: @status_parser.created_at,
edited_at: @status_parser.edited_at && @status_parser.edited_at != @status_parser.created_at ? @status_parser.edited_at : nil,
override_timestamps: @options[:override_timestamps],
reply: @status_parser.reply,
sensitive: @account.sensitized? || @status_parser.sensitive || false,
visibility: @status_parser.visibility,
thread: replied_to_status,
conversation: conversation_from_uri(@object['conversation']),
media_attachment_ids: process_attachments.take(4).map(&:id),
poll: process_poll,
activity_pub_type: @object['type']
}
end
@params = {
uri: @status_parser.uri,
url: @status_parser.url || @status_parser.uri,
account: @account,
text: converted_object_type? ? converted_text : (@status_parser.text || ''),
language: @status_parser.language,
spoiler_text: converted_object_type? ? '' : (@status_parser.spoiler_text || (@object['type'] == 'Article' && text_from_name) || ''),
created_at: @status_parser.created_at,
edited_at: @status_parser.edited_at && @status_parser.edited_at != @status_parser.created_at ? @status_parser.edited_at : nil,
override_timestamps: @options[:override_timestamps],
reply: @status_parser.reply,
sensitive: @account.sensitized? || @status_parser.sensitive || false,
visibility: @status_parser.visibility,
thread: replied_to_status,
conversation: conversation_from_uri(@object['conversation']),
media_attachment_ids: process_attachments.take(4).map(&:id),
poll: process_poll,
activity_pub_type: @object['type'],
}
end
class Handler < ::Ox::Sax
attr_reader :srcs
attr_reader :alts
def initialize(block)
attr_reader :srcs, :alts
def initialize(_block)
super
@stack = []
@srcs = []
@alts = {}
@ -147,7 +146,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
@stack << [element_name, {}]
end
def end_element(element_name)
def end_element(_element_name)
self_name, self_attributes = @stack[-1]
if self_name == :img && !self_attributes[:src].nil?
@srcs << self_attributes[:src]
@ -159,11 +158,12 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
def attr(attribute_name, attribute_value)
_name, attributes = @stack.last
attributes[attribute_name] = attribute_value
attributes
end
end
def process_inline_images
proc = Proc.new { |name| puts name }
proc = proc { |name| Rails.logger.debug name }
handler = Handler.new(proc)
Ox.sax_parse(handler, @object['content'])
handler.srcs.each do |src|
@ -436,7 +436,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
return article_format(@object['content']) if @object['content'].present? && @object['type'] == 'Article'
return @status_parser.text || ''
@status_parser.text || ''
end
def text_from_name

View File

@ -122,13 +122,11 @@ class PostStatusService < BaseService
spoiler_text&.include?(':local_only')
return true
end
if local_only.nil?
if in_reply_to && in_reply_to.local_only
return true
end
if in_reply_to && !in_reply_to.local_only
return false
end
return true if in_reply_to&.local_only
return false if in_reply_to && !in_reply_to.local_only
return !federation_setting
end
local_only
@ -139,9 +137,7 @@ class PostStatusService < BaseService
Trends.tags.register(@status)
LinkCrawlWorker.perform_async(@status.id)
DistributionWorker.perform_async(@status.id)
unless @status.local_only?
ActivityPub::DistributionWorker.perform_async(@status.id)
end
ActivityPub::DistributionWorker.perform_async(@status.id) unless @status.local_only?
PollExpirationNotifyWorker.perform_at(@status.poll.expires_at, @status.poll.id) if @status.poll
end

View File

@ -30,9 +30,7 @@ class ReblogService < BaseService
Trends.register!(reblog)
DistributionWorker.perform_async(reblog.id)
unless reblogged_status.local_only?
ActivityPub::DistributionWorker.perform_async(reblog.id)
end
ActivityPub::DistributionWorker.perform_async(reblog.id) unless reblogged_status.local_only?
create_notification(reblog)
bump_potential_friendship(account, reblog)

View File

@ -69,5 +69,5 @@
%span.status__action-bar-button.icon-button
= fa_icon 'star fw'
- if status.local_only
%span.status__action-bar-button.icon-button.disabled{style: 'font-size: 18px; width: 23.1429px; height: 23.1429px; line-height: 23.15px;'}<
%span.status__action-bar-button.icon-button.disabled
= fa_icon 'chain-broken fw', 'title': t('statuses.local_only')

View File

@ -4,7 +4,7 @@ require_relative '../../lib/mastodon/sidekiq_middleware'
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.'
warn 'ERROR: Database replication is not currently supported in Sidekiq workers. Check your configuration.'
exit 1
end

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
class AddLocalOnlyFlagToStatuses < ActiveRecord::Migration[5.1]
def change
add_column :statuses, :local_only, :boolean

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
class AddActivityPubTypeToStatuses < ActiveRecord::Migration[5.2]
def change
add_column :statuses, :activity_pub_type, :string

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
class AddIsExclusiveToLists < ActiveRecord::Migration[5.2]
def change
add_column :lists, :is_exclusive, :boolean

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
class AddKeepLocalToAccountStatusesCleanupPolicies < ActiveRecord::Migration[6.1]
def change
add_column :account_statuses_cleanup_policies, :keep_local, :boolean

View File

@ -56,7 +56,7 @@ services:
web:
build: .
image: ghcr.io/mastodon/mastodon:v4.2.2
image: ghcr.io/mastodon/mastodon:v4.2.3
restart: always
env_file: .env.production
command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000"
@ -77,7 +77,7 @@ services:
streaming:
build: .
image: ghcr.io/mastodon/mastodon:v4.2.2
image: ghcr.io/mastodon/mastodon:v4.2.3
restart: always
env_file: .env.production
command: node ./streaming
@ -95,7 +95,7 @@ services:
sidekiq:
build: .
image: ghcr.io/mastodon/mastodon:v4.2.2
image: ghcr.io/mastodon/mastodon:v4.2.3
restart: always
env_file: .env.production
command: bundle exec sidekiq

View File

@ -13,7 +13,7 @@ module Mastodon
end
def patch
2
3
end
def default_prerelease

View File

@ -68,13 +68,13 @@ class Sanitize
elements: %w(p br span a abbr del pre blockquote code b strong i em h1 h2 h3 h4 h5 ul ol li img u),
attributes: {
'abbr' => %w(title),
'abbr' => %w(title),
'blockquote' => %w(cite),
'img' => %w(src alt),
'a' => %w(href rel class translate title),
'span' => %w(class translate),
'ol' => %w(start reversed),
'li' => %w(value),
'img' => %w(src alt),
'a' => %w(href rel class translate title),
'span' => %w(class translate),
'ol' => %w(start reversed),
'li' => %w(value),
},
add_attributes: {
@ -84,10 +84,7 @@ class Sanitize
},
},
protocols: {
'a' => { 'href' => HTTP_PROTOCOLS },
'blockquote' => { 'cite' => HTTP_PROTOCOLS },
},
protocols: {},
transformers: [
CLASS_WHITELIST_TRANSFORMER,
@ -101,16 +98,15 @@ class Sanitize
elements: %w(audio embed iframe source video),
attributes: {
'audio' => %w(controls),
'embed' => %w(height src type width),
'audio' => %w(controls),
'embed' => %w(height src type width),
'iframe' => %w(allowfullscreen frameborder height scrolling src width),
'source' => %w(src type),
'video' => %w(controls height loop width),
'div' => [:data]
'video' => %w(controls height loop width),
},
protocols: {
'embed' => { 'src' => HTTP_PROTOCOLS },
'embed' => { 'src' => HTTP_PROTOCOLS },
'iframe' => { 'src' => HTTP_PROTOCOLS },
'source' => { 'src' => HTTP_PROTOCOLS },
},

View File

@ -6,10 +6,6 @@ describe Sanitize::Config do
describe '::MASTODON_STRICT' do
subject { Sanitize::Config::MASTODON_STRICT }
it 'converts h1 to p strong' do
expect(Sanitize.fragment('<h1>Foo</h1>', subject)).to eq '<p><strong>Foo</strong></p>'
end
it 'keeps ul' do
expect(Sanitize.fragment('<p>Check out:</p><ul><li>Foo</li><li>Bar</li></ul>', subject)).to eq '<p>Check out:</p><ul><li>Foo</li><li>Bar</li></ul>'
end

View File

@ -10,14 +10,15 @@ describe UserMailer do
it 'renders confirmation instructions' do
receiver.update!(locale: nil)
expect(mail.body.encoded).to include I18n.t('devise.mailer.confirmation_instructions.title')
expect(mail.body.encoded).to include I18n.t('devise.mailer.confirmation_instructions.title', title: Setting.site_title)
expect(mail.body.encoded).to include 'spec'
expect(mail.body.encoded).to include Rails.configuration.x.local_domain
end
include_examples 'localized subject',
'devise.mailer.confirmation_instructions.subject',
instance: Rails.configuration.x.local_domain
instance: Rails.configuration.x.local_domain,
title: Setting.site_title
end
describe 'reconfirmation_instructions' do
@ -25,12 +26,13 @@ describe UserMailer do
it 'renders reconfirmation instructions' do
receiver.update!(email: 'new-email@example.com', locale: nil)
expect(mail.body.encoded).to include I18n.t('devise.mailer.reconfirmation_instructions.title')
expect(mail.body.encoded).to include I18n.t('devise.mailer.reconfirmation_instructions.title', title: Setting.site_title)
expect(mail.body.encoded).to include 'spec'
expect(mail.body.encoded).to include Rails.configuration.x.local_domain
expect(mail.subject).to eq I18n.t('devise.mailer.reconfirmation_instructions.subject',
instance: Rails.configuration.x.local_domain,
locale: I18n.default_locale)
locale: I18n.default_locale,
title: Setting.site_title)
end
end
@ -39,12 +41,13 @@ describe UserMailer do
it 'renders reset password instructions' do
receiver.update!(locale: nil)
expect(mail.body.encoded).to include I18n.t('devise.mailer.reset_password_instructions.title')
expect(mail.body.encoded).to include I18n.t('devise.mailer.reset_password_instructions.title', title: Setting.site_title)
expect(mail.body.encoded).to include 'spec'
end
include_examples 'localized subject',
'devise.mailer.reset_password_instructions.subject'
'devise.mailer.reset_password_instructions.subject',
title: Setting.site_title
end
describe 'password_change' do
@ -52,11 +55,12 @@ describe UserMailer do
it 'renders password change notification' do
receiver.update!(locale: nil)
expect(mail.body.encoded).to include I18n.t('devise.mailer.password_change.title')
expect(mail.body.encoded).to include I18n.t('devise.mailer.password_change.title', title: Setting.site_title)
end
include_examples 'localized subject',
'devise.mailer.password_change.subject'
'devise.mailer.password_change.subject',
title: Setting.site_title
end
describe 'email_changed' do
@ -64,11 +68,12 @@ describe UserMailer do
it 'renders email change notification' do
receiver.update!(locale: nil)
expect(mail.body.encoded).to include I18n.t('devise.mailer.email_changed.title')
expect(mail.body.encoded).to include I18n.t('devise.mailer.email_changed.title', title: Setting.site_title)
end
include_examples 'localized subject',
'devise.mailer.email_changed.subject'
'devise.mailer.email_changed.subject',
title: Setting.site_title
end
describe 'warning' do

View File

@ -60,9 +60,9 @@ describe TagFeed, type: :service do
end
it 'excludes local-only posts when specified' do
status1.update(local_only: true)
results = described_class.new(tag1, nil, any: [tag2.name], without_local_only: true).get(20)
expect(results).to_not include status1
status_tagged_with_cats.update(local_only: true)
results = described_class.new(tag_cats, nil, any: [tag_dogs.name], without_local_only: true).get(20)
expect(results).to_not include status_tagged_with_cats
end
it 'allows replies to be included' do

View File

@ -84,18 +84,18 @@ RSpec.describe StatusPolicy, type: :model do
expect(subject).to_not permit(viewer, status)
end
end
it 'denies access when local-only and the viewer is not logged in' do
allow(status).to receive(:local_only?) { true }
it 'denies access when local-only and the viewer is not logged in' do
allow(status).to receive(:local_only?).and_return(true)
expect(subject).to_not permit(nil, status)
end
expect(subject).to_not permit(nil, status)
end
it 'denies access when local-only and the viewer is from another domain' do
viewer = Fabricate(:account, domain: 'remote-domain')
allow(status).to receive(:local_only?) { true }
expect(subject).to_not permit(viewer, status)
it 'denies access when local-only and the viewer is from another domain' do
viewer = Fabricate(:account, domain: 'remote-domain')
allow(status).to receive(:local_only?).and_return(true)
expect(subject).to_not permit(viewer, status)
end
end
end