Skip to content

Commit

Permalink
Merge commit 'a02ff33f0ef2026d776b40dcdbb81ce9785e7443' into kb-draft…
Browse files Browse the repository at this point in the history
…-5.22-lts
  • Loading branch information
kmycode committed Aug 16, 2024
2 parents 31ad8c7 + a02ff33 commit 3ab6626
Show file tree
Hide file tree
Showing 43 changed files with 212 additions and 68 deletions.
33 changes: 33 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,39 @@

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

## |4.2.11] - 2024-08-16

### Added

- Add support for incoming `<s>` tag ([mediaformat](https://github.com/mastodon/mastodon/pull/31375))

### Changed

- Change logic of block/mute bypass for mentions from moderators to only apply to visible roles with moderation powers ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/31271))

### Fixed

- Fix incorrect rate limit on PUT requests ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/31356))
- Fix presence of `ß` in adjacent word preventing mention and hashtag matching ([adamniedzielski](https://github.com/mastodon/mastodon/pull/31122))
- Fix processing of webfinger responses with multiple `self` links ([adamniedzielski](https://github.com/mastodon/mastodon/pull/31110))
- Fix duplicate `orderedItems` in user archive's `outbox.json` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/31099))
- Fix click event handling when clicking outside of an open dropdown menu ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/31251))
- Fix status processing failing halfway when a remote post has a malformed `replies` attribute ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/31246))
- Fix `--verbose` option of `tootctl media remove`, which was previously erroneously removed ([mjankowski](https://github.com/mastodon/mastodon/pull/30536))
- Fix division by zero on some video/GIF files ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/30600))
- Fix Web UI trying to save user settings despite being logged out ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/30324))
- Fix hashtag regexp matching some link anchors ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/30190))
- Fix local account search on LDAP login being case-sensitive ([raucao](https://github.com/mastodon/mastodon/pull/30113))
- Fix development environment admin account not being auto-approved ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/29958))
- Fix report reason selector in moderation interface not unselecting rules when changing category ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/29026))
- Fix already-invalid reports failing to resolve ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/29027))
- Fix OCR when using S3/CDN for assets ([vmstan](https://github.com/mastodon/mastodon/pull/28551))
- Fix error when encountering malformed `Tag` objects from Kbin ([ShadowJonathan](https://github.com/mastodon/mastodon/pull/28235))
- Fix not all allowed image formats showing in file picker when uploading custom emoji ([june128](https://github.com/mastodon/mastodon/pull/28076))
- Fix search popout listing unusable search options when logged out ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27918))
- Fix processing of featured collections lacking an `items` attribute ([tribela](https://github.com/mastodon/mastodon/pull/27581))
- Fix `mastodon:stats` decoration of stats rake task ([mjankowski](https://github.com/mastodon/mastodon/pull/31104))

## [4.2.10] - 2024-07-04

### Security
Expand Down
6 changes: 3 additions & 3 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -604,8 +604,8 @@ GEM
responders (3.1.0)
actionpack (>= 5.2)
railties (>= 5.2)
rexml (3.2.8)
strscan (>= 3.0.9)
rexml (3.3.5)
strscan
rotp (6.3.0)
rouge (4.1.2)
rpam2 (4.0.2)
Expand Down Expand Up @@ -733,7 +733,7 @@ GEM
redlock (~> 1.0)
strong_migrations (0.8.0)
activerecord (>= 5.2)
strscan (3.0.9)
strscan (3.1.0)
swd (1.3.0)
activesupport (>= 3)
attr_required (>= 0.0.5)
Expand Down
2 changes: 1 addition & 1 deletion app/javascript/mastodon/actions/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export function changeSetting(path, value) {
}

const debouncedSave = debounce((dispatch, getState) => {
if (getState().getIn(['settings', 'saved'])) {
if (getState().getIn(['settings', 'saved']) || !getState().getIn(['meta', 'me'])) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ class ReportReasonSelector extends PureComponent {

api().put(`/api/v1/admin/reports/${id}`, {
category,
rule_ids,
rule_ids: category === 'violation' ? rule_ids : [],
}).catch(err => {
console.error(err);
});
Expand Down
1 change: 1 addition & 0 deletions app/javascript/mastodon/components/dropdown_menu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class DropdownMenu extends PureComponent {
if (this.node && !this.node.contains(e.target)) {
this.props.onClose();
e.stopPropagation();
e.preventDefault();
}
};

Expand Down
11 changes: 8 additions & 3 deletions app/javascript/mastodon/features/compose/components/search.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ class Search extends PureComponent {
}

_calculateOptions (value) {
const { signedIn } = this.context.identity;
const trimmedValue = value.trim();
const options = [];

Expand All @@ -301,7 +302,7 @@ class Search extends PureComponent {

const couldBeStatusSearch = searchEnabled;

if (couldBeStatusSearch) {
if (couldBeStatusSearch && signedIn) {
options.push({ key: 'status-search', label: <FormattedMessage id='search.quick_action.status_search' defaultMessage='Posts matching {x}' values={{ x: <mark>{trimmedValue}</mark> }} />, action: this.handleStatusSearch });
}

Expand Down Expand Up @@ -378,7 +379,7 @@ class Search extends PureComponent {

<h4><FormattedMessage id='search_popout.options' defaultMessage='Search options' /></h4>

{searchEnabled ? (
{searchEnabled && signedIn ? (
<div className='search__popout__menu'>
{this.defaultOptions.map(({ key, label, action }, i) => (
<button key={key} onMouseDown={action} className={classNames('search__popout__menu__item', { selected: selectedOption === ((options.length || recent.size) + i) })}>
Expand All @@ -388,7 +389,11 @@ class Search extends PureComponent {
</div>
) : (
<div className='search__popout__menu__message'>
<FormattedMessage id='search_popout.full_text_search_disabled_message' defaultMessage='Not available on {domain}.' values={{ domain }} />
{searchEnabled ? (
<FormattedMessage id='search_popout.full_text_search_logged_out_message' defaultMessage='Only available when logged in.' />
) : (
<FormattedMessage id='search_popout.full_text_search_disabled_message' defaultMessage='Not available on {domain}.' values={{ domain }} />
)}
</div>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ class FocalPointModal extends ImmutablePureComponent {
const worker = createWorker({
workerPath: tesseractWorkerPath,
corePath: tesseractCorePath,
langPath: `${assetHost}/ocr/lang-data/`,
langPath: `${assetHost}/ocr/lang-data`,
logger: ({ status, progress }) => {
if (status === 'recognizing text') {
this.setState({ ocrStatus: 'detecting', progress });
Expand Down
1 change: 1 addition & 0 deletions app/javascript/mastodon/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,7 @@
"searchability.unlisted.short": "Followers and reactionners",
"search_popout.domain": "domain",
"search_popout.full_text_search_disabled_message": "Not available on {domain}.",
"search_popout.full_text_search_logged_out_message": "Only available when logged in.",
"search_popout.language_code": "ISO language code",
"search_popout.options": "Search options",
"search_popout.quick_actions": "Quick actions",
Expand Down
4 changes: 3 additions & 1 deletion app/lib/activitypub/activity/create.rb
Original file line number Diff line number Diff line change
Expand Up @@ -365,13 +365,15 @@ def resolve_thread(status)

def fetch_replies(status)
collection = @object['replies']
return if collection.nil?
return if collection.blank?

replies = ActivityPub::FetchRepliesService.new.call(status, collection, allow_synchronous_requests: false, request_id: @options[:request_id])
return unless replies.nil?

uri = value_or_id(collection)
ActivityPub::FetchRepliesWorker.perform_async(status.id, uri, { 'request_id' => @options[:request_id] }) unless uri.nil?
rescue => e
Rails.logger.warn "Error fetching replies: #{e}"
end

def conversation_from_uri(uri)
Expand Down
2 changes: 1 addition & 1 deletion app/lib/activitypub/adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ def serializable_hash(options = nil)
serialized_hash = serialized_hash.select { |k, _| options[:fields].include?(k) } if options[:fields]
serialized_hash = self.class.transform_key_casing!(serialized_hash, instance_options)

{ '@context' => serialized_context(named_contexts, context_extensions) }.merge(serialized_hash)
{ '@context': serialized_context(named_contexts, context_extensions) }.merge(serialized_hash)
end
end
10 changes: 8 additions & 2 deletions app/lib/video_metadata_extractor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ def parse_metadata
@colorspace = video_stream[:pix_fmt]
@width = video_stream[:width]
@height = video_stream[:height]
@frame_rate = video_stream[:avg_frame_rate] == '0/0' ? nil : Rational(video_stream[:avg_frame_rate])
@r_frame_rate = video_stream[:r_frame_rate] == '0/0' ? nil : Rational(video_stream[:r_frame_rate])
@frame_rate = parse_framerate(video_stream[:avg_frame_rate])
@r_frame_rate = parse_framerate(video_stream[:r_frame_rate])
# For some video streams the frame_rate reported by `ffprobe` will be 0/0, but for these streams we
# should use `r_frame_rate` instead. Video screencast generated by Gnome Screencast have this issue.
@frame_rate ||= @r_frame_rate
Expand All @@ -55,4 +55,10 @@ def parse_metadata

@invalid = true if @metadata.key?(:error)
end

def parse_framerate(raw)
Rational(raw)
rescue ZeroDivisionError
nil
end
end
17 changes: 15 additions & 2 deletions app/lib/webfinger.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ class GoneError < Error; end
class RedirectError < Error; end

class Response
ACTIVITYPUB_READY_TYPE = ['application/activity+json', 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'].freeze

attr_reader :uri

def initialize(uri, body)
Expand All @@ -20,17 +22,28 @@ def subject
end

def link(rel, attribute)
links.dig(rel, attribute)
links.dig(rel, 0, attribute)
end

def self_link_href
self_link.fetch('href')
end

private

def links
@links ||= @json['links'].index_by { |link| link['rel'] }
@links ||= @json.fetch('links', []).group_by { |link| link['rel'] }
end

def self_link
links.fetch('self', []).find do |link|
ACTIVITYPUB_READY_TYPE.include?(link['type'])
end
end

def validate_response!
raise Webfinger::Error, "Missing subject in response for #{@uri}" if subject.blank?
raise Webfinger::Error, "Missing self link in response for #{@uri}" if self_link.blank?
end
end

Expand Down
2 changes: 1 addition & 1 deletion app/models/account.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class Account < ApplicationRecord
BACKGROUND_REFRESH_INTERVAL = 1.week.freeze

USERNAME_RE = /[a-z0-9_]+([a-z0-9_.-]+[a-z0-9_]+)?/i
MENTION_RE = %r{(?<![=/[:word:]])@((#{USERNAME_RE})(?:@[[:word:].-]+[[:word:]]+)?)}i
MENTION_RE = %r{(?<![=/[:word:]])@((#{USERNAME_RE})(?:@[[:word:].-]+[[:word:]]+)?)}
URL_PREFIX_RE = %r{\Ahttp(s?)://[^/]+}
USERNAME_ONLY_RE = /\A#{USERNAME_RE}\z/i

Expand Down
2 changes: 1 addition & 1 deletion app/models/concerns/ldap_authenticable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def ldap_get_user(attributes = {})
safe_username = safe_username.gsub(keys, replacement)
end

resource = joins(:account).find_by(accounts: { username: safe_username })
resource = joins(:account).merge(Account.where(Account.arel_table[:username].lower.eq safe_username.downcase)).take

if resource.blank?
resource = new(email: attributes[Devise.ldap_mail.to_sym].first, agreement: true, account_attributes: { username: safe_username }, admin: false, external: true, confirmed_at: Time.now.utc)
Expand Down
6 changes: 2 additions & 4 deletions app/models/report.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ class Report < ApplicationRecord
delegate :local?, to: :account

validates :comment, length: { maximum: 1_000 }, if: :local?
validates :rule_ids, absence: true, unless: :violation?
validates :rule_ids, absence: true, if: -> { (category_changed? || rule_ids_changed?) && !violation? }

validate :validate_rule_ids
validate :validate_rule_ids, if: -> { (category_changed? || rule_ids_changed?) && violation? }

# entries here need to be kept in sync with the front-end:
# - app/javascript/mastodon/features/notifications/components/report.jsx
Expand Down Expand Up @@ -154,8 +154,6 @@ def set_uri
end

def validate_rule_ids
return unless violation?

errors.add(:rule_ids, I18n.t('reports.errors.invalid_rules')) unless rules.size == rule_ids&.size
end

Expand Down
2 changes: 1 addition & 1 deletion app/models/tag.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class Tag < ApplicationRecord
HASHTAG_LAST_SEQUENCE = '([[:word:]_]*[[:alpha:]][[:word:]_]*)'
HASHTAG_NAME_PAT = "#{HASHTAG_FIRST_SEQUENCE}|#{HASHTAG_LAST_SEQUENCE}"

HASHTAG_RE = %r{(?<![=/)\w])#(#{HASHTAG_NAME_PAT})}i
HASHTAG_RE = %r{(?<![=/)\p{Alnum}])#(#{HASHTAG_NAME_PAT})}
HASHTAG_NAME_RE = /\A(#{HASHTAG_NAME_PAT})\z/i
HASHTAG_INVALID_CHARS_RE = /[^[:alnum:]#{HASHTAG_SEPARATORS}]/

Expand Down
2 changes: 2 additions & 0 deletions app/services/activitypub/fetch_featured_collection_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ def fetch_collection(collection_or_uri)
end

def process_items(items)
return if items.nil?

process_note_items(items) if @options[:note]
process_hashtag_items(items) if @options[:hashtag]
end
Expand Down
5 changes: 2 additions & 3 deletions app/services/activitypub/fetch_remote_actor_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def check_webfinger!
confirmed_username, confirmed_domain = split_acct(webfinger.subject)

if @username.casecmp(confirmed_username).zero? && @domain.casecmp(confirmed_domain).zero?
raise Error, "Webfinger response for #{@username}@#{@domain} does not loop back to #{@uri}" if webfinger.link('self', 'href') != @uri
raise Error, "Webfinger response for #{@username}@#{@domain} does not loop back to #{@uri}" if webfinger.self_link_href != @uri

return
end
Expand All @@ -58,8 +58,7 @@ def check_webfinger!
@username, @domain = split_acct(webfinger.subject)

raise Webfinger::RedirectError, "Too many webfinger redirects for URI #{@uri} (stopped at #{@username}@#{@domain})" unless confirmed_username.casecmp(@username).zero? && confirmed_domain.casecmp(@domain).zero?

raise Error, "Webfinger response for #{@username}@#{@domain} does not loop back to #{@uri}" if webfinger.link('self', 'href') != @uri
raise Error, "Webfinger response for #{@username}@#{@domain} does not loop back to #{@uri}" if webfinger.self_link_href != @uri
rescue Webfinger::RedirectError => e
raise Error, e.message
rescue Webfinger::Error => e
Expand Down
4 changes: 2 additions & 2 deletions app/services/activitypub/process_status_update_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,9 @@ def read_metadata

as_array(@json['tag']).each do |tag|
if equals_or_includes?(tag['type'], 'Hashtag')
@raw_tags << tag['name']
@raw_tags << tag['name'] if tag['name'].present?
elsif equals_or_includes?(tag['type'], 'Mention')
@raw_mentions << tag['href']
@raw_mentions << tag['href'] if tag['href'].present?
elsif equals_or_includes?(tag['type'], 'Emoji')
@raw_emojis << tag
end
Expand Down
6 changes: 3 additions & 3 deletions app/services/backup_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ def call(backup)

def build_outbox_json!(file)
skeleton = serialize(collection_presenter, ActivityPub::CollectionSerializer)
skeleton['@context'] = full_context
skeleton['orderedItems'] = ['!PLACEHOLDER!']
skeleton[:@context] = full_context
skeleton[:orderedItems] = ['!PLACEHOLDER!']
skeleton = Oj.dump(skeleton)
prepend, append = skeleton.split('"!PLACEHOLDER!"')
add_comma = false
Expand All @@ -33,7 +33,7 @@ def build_outbox_json!(file)

file.write(statuses.map do |status|
item = serialize_payload(ActivityPub::ActivityPresenter.from_status(status, use_bearcap: false), ActivityPub::ActivitySerializer)
item.delete('@context')
item.delete(:@context)

unless item[:type] == 'Announce' || item[:object][:attachment].blank?
item[:object][:attachment].each do |attachment|
Expand Down
3 changes: 2 additions & 1 deletion app/services/notify_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ def response_to_recipient?
end

def from_staff?
@notification.from_account.local? && @notification.from_account.user.present? && @notification.from_account.user_role&.overrides?(@recipient.user_role)
sender = @notification.from_account
sender.local? && sender.user.present? && sender.user_role&.overrides?(@recipient.user_role) && @sender.user_role&.highlighted? && sender.user_role&.can?(*UserRole::Flags::CATEGORIES[:moderation])
end

def optional_non_following_and_direct?
Expand Down
8 changes: 1 addition & 7 deletions app/services/resolve_account_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,6 @@ def split_acct(acct)
end

def fetch_account!
return unless activitypub_ready?

with_redis_lock("resolve:#{@username}@#{@domain}") do
@account = ActivityPub::FetchRemoteAccountService.new.call(actor_url, suppress_errors: @options[:suppress_errors])
end
Expand All @@ -120,12 +118,8 @@ def webfinger_update_due?
@options[:skip_cache] || @account.nil? || @account.possibly_stale?
end

def activitypub_ready?
['application/activity+json', 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'].include?(@webfinger.link('self', 'type'))
end

def actor_url
@actor_url ||= @webfinger.link('self', 'href')
@actor_url ||= @webfinger.self_link_href
end

def gone_from_origin?
Expand Down
2 changes: 1 addition & 1 deletion app/views/admin/custom_emojis/new.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
.fields-group
= f.input :shortcode, wrapper: :with_label, label: t('admin.custom_emojis.shortcode'), hint: t('admin.custom_emojis.shortcode_hint')
.fields-group
= f.input :image, wrapper: :with_label, input_html: { accept: CustomEmoji::IMAGE_MIME_TYPES.join(' ') }, hint: t('admin.custom_emojis.image_hint', size: number_to_human_size(CustomEmoji::LIMIT))
= f.input :image, wrapper: :with_label, input_html: { accept: CustomEmoji::IMAGE_MIME_TYPES.join(',') }, hint: t('admin.custom_emojis.image_hint', size: number_to_human_size(CustomEmoji::LIMIT))

.actions
= f.button :button, t('admin.custom_emojis.upload'), type: :submit
4 changes: 1 addition & 3 deletions config/initializers/rack_attack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,8 @@ def paging_request?
req.session[:attempt_user_id] || req.params.dig('user', 'email').presence if req.post? && req.path_matches?('/auth/sign_in')
end

API_CREATE_EMOJI_REACTION_REGEX = %r{\A/api/v1/statuses/\d+/emoji_reactions}

throttle('throttle_password_change/account', limit: 10, period: 10.minutes) do |req|
req.warden_user_id if (req.put? && !req.path.match?(API_CREATE_EMOJI_REACTION_REGEX)) || (req.patch? && req.path_matches?('/auth'))
req.warden_user_id if (req.put? || req.patch?) && (req.path_matches?('/auth') || req.path_matches?('/auth/password'))
end

self.throttled_responder = lambda do |request|
Expand Down
4 changes: 3 additions & 1 deletion db/seeds/04_admin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,7 @@
admin = Account.where(username: 'admin').first_or_initialize(username: 'admin')
admin.save(validate: false)

User.where(email: "admin@#{domain}").first_or_initialize(email: "admin@#{domain}", password: 'mastodonadmin', password_confirmation: 'mastodonadmin', confirmed_at: Time.now.utc, role: UserRole.find_by(name: 'Owner'), account: admin, agreement: true, approved: true).save!
user = User.where(email: "admin@#{domain}").first_or_initialize(email: "admin@#{domain}", password: 'mastodonadmin', password_confirmation: 'mastodonadmin', confirmed_at: Time.now.utc, role: UserRole.find_by(name: 'Owner'), account: admin, agreement: true, approved: true)
user.save!
user.approve!
end
Loading

0 comments on commit 3ab6626

Please sign in to comment.