Merge security fixes of mastodon v4.0.13 (#1340)
There were some smaller merge conflicts (e.g. in `lib/version.rb`), but all of them were of smaller nature. Due to the fact that other v4.0.* versions are also included, it's a bit bigger than the other PR for 3.5. I won't repeat the changelog here, the upgrade is the usual *git pull and restart all mastodon processes*. --------- Co-authored-by: Michael Stanclift <mx@vmstan.com> Co-authored-by: Claire <claire.github-309c@sitedethib.com> Co-authored-by: Eugen Rochko <eugen@zeonfederated.com> Co-authored-by: Emelia Smith <ThisIsMissEm@users.noreply.github.com> Co-authored-by: Renaud Chaput <renchap@gmail.com> Co-authored-by: Daniel M Brasil <danielmbrasil@protonmail.com> Co-authored-by: yufushiro <62991447+yufushiro@users.noreply.github.com> Co-authored-by: Nicolai Søborg <NicolaiSoeborg@users.noreply.github.com> Co-authored-by: Essem <smswessem@gmail.com> Co-authored-by: Jakob Gillich <jakob@gillich.me> Co-authored-by: David Aaron <1858430+suddjian@users.noreply.github.com> Co-authored-by: Matt Jankowski <matt@jankowski.online>
This commit is contained in:
parent
3b69a29703
commit
13fa4f70cc
32
CHANGELOG.md
32
CHANGELOG.md
|
@ -5,8 +5,36 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
## End of life notice
|
||||
|
||||
**The 4.0.x branch will not receive any update after 2023-10-31.**
|
||||
This means that no security fix will be made available for this branch after this date, and you will need to update to a more recent version (such as the 4.1.x branch) to receive security fixes.
|
||||
**The 4.0.x branch has reached its end of life and will not receive any further update.**
|
||||
This means that no security fix will be made available for this branch after this date, and you will need to update to a more recent version (such as the 4.2.x branch) to receive security fixes.
|
||||
|
||||
## [4.0.13] - 2024-02-01
|
||||
|
||||
### Security
|
||||
|
||||
- Fix insufficient origin validation (CVE-2024-23832, [GHSA-3fjr-858r-92rw](https://github.com/mastodon/mastodon/security/advisories/GHSA-3fjr-858r-92rw))
|
||||
|
||||
## [4.0.12] - 2023-10-10
|
||||
|
||||
### Changed
|
||||
|
||||
- Change some worker lock TTLs to be shorter-lived ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27246))
|
||||
- Change user archive export allowed period from 7 days to 6 days ([suddjian](https://github.com/mastodon/mastodon/pull/27200))
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix mentions being matched in some URL query strings ([mjankowski](https://github.com/mastodon/mastodon/pull/25656))
|
||||
- Fix multiple instances of the trend refresh scheduler sometimes running at once ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27253))
|
||||
- Fix importer returning negative row estimates ([jgillich](https://github.com/mastodon/mastodon/pull/27258))
|
||||
- Fix filtering audit log for entries about disabling 2FA ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27186))
|
||||
- Fix tIME chunk not being properly removed from PNG uploads ([TheEssem](https://github.com/mastodon/mastodon/pull/27111))
|
||||
- Fix inefficient queries in “Follows and followers” as well as several admin pages ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27116), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/27306))
|
||||
|
||||
## [4.0.11] - 2023-09-20
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix post translation erroring out ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26990))
|
||||
|
||||
## [4.0.10] - 2023-09-19
|
||||
|
||||
|
|
130
Gemfile.lock
130
Gemfile.lock
|
@ -10,40 +10,40 @@ GIT
|
|||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
actioncable (6.1.7.4)
|
||||
actionpack (= 6.1.7.4)
|
||||
activesupport (= 6.1.7.4)
|
||||
actioncable (6.1.7.6)
|
||||
actionpack (= 6.1.7.6)
|
||||
activesupport (= 6.1.7.6)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (>= 0.6.1)
|
||||
actionmailbox (6.1.7.4)
|
||||
actionpack (= 6.1.7.4)
|
||||
activejob (= 6.1.7.4)
|
||||
activerecord (= 6.1.7.4)
|
||||
activestorage (= 6.1.7.4)
|
||||
activesupport (= 6.1.7.4)
|
||||
actionmailbox (6.1.7.6)
|
||||
actionpack (= 6.1.7.6)
|
||||
activejob (= 6.1.7.6)
|
||||
activerecord (= 6.1.7.6)
|
||||
activestorage (= 6.1.7.6)
|
||||
activesupport (= 6.1.7.6)
|
||||
mail (>= 2.7.1)
|
||||
actionmailer (6.1.7.4)
|
||||
actionpack (= 6.1.7.4)
|
||||
actionview (= 6.1.7.4)
|
||||
activejob (= 6.1.7.4)
|
||||
activesupport (= 6.1.7.4)
|
||||
actionmailer (6.1.7.6)
|
||||
actionpack (= 6.1.7.6)
|
||||
actionview (= 6.1.7.6)
|
||||
activejob (= 6.1.7.6)
|
||||
activesupport (= 6.1.7.6)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
actionpack (6.1.7.4)
|
||||
actionview (= 6.1.7.4)
|
||||
activesupport (= 6.1.7.4)
|
||||
actionpack (6.1.7.6)
|
||||
actionview (= 6.1.7.6)
|
||||
activesupport (= 6.1.7.6)
|
||||
rack (~> 2.0, >= 2.0.9)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||
actiontext (6.1.7.4)
|
||||
actionpack (= 6.1.7.4)
|
||||
activerecord (= 6.1.7.4)
|
||||
activestorage (= 6.1.7.4)
|
||||
activesupport (= 6.1.7.4)
|
||||
actiontext (6.1.7.6)
|
||||
actionpack (= 6.1.7.6)
|
||||
activerecord (= 6.1.7.6)
|
||||
activestorage (= 6.1.7.6)
|
||||
activesupport (= 6.1.7.6)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (6.1.7.4)
|
||||
activesupport (= 6.1.7.4)
|
||||
actionview (6.1.7.6)
|
||||
activesupport (= 6.1.7.6)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
|
@ -54,22 +54,22 @@ GEM
|
|||
case_transform (>= 0.2)
|
||||
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
|
||||
active_record_query_trace (1.8)
|
||||
activejob (6.1.7.4)
|
||||
activesupport (= 6.1.7.4)
|
||||
activejob (6.1.7.6)
|
||||
activesupport (= 6.1.7.6)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (6.1.7.4)
|
||||
activesupport (= 6.1.7.4)
|
||||
activerecord (6.1.7.4)
|
||||
activemodel (= 6.1.7.4)
|
||||
activesupport (= 6.1.7.4)
|
||||
activestorage (6.1.7.4)
|
||||
actionpack (= 6.1.7.4)
|
||||
activejob (= 6.1.7.4)
|
||||
activerecord (= 6.1.7.4)
|
||||
activesupport (= 6.1.7.4)
|
||||
activemodel (6.1.7.6)
|
||||
activesupport (= 6.1.7.6)
|
||||
activerecord (6.1.7.6)
|
||||
activemodel (= 6.1.7.6)
|
||||
activesupport (= 6.1.7.6)
|
||||
activestorage (6.1.7.6)
|
||||
actionpack (= 6.1.7.6)
|
||||
activejob (= 6.1.7.6)
|
||||
activerecord (= 6.1.7.6)
|
||||
activesupport (= 6.1.7.6)
|
||||
marcel (~> 1.0)
|
||||
mini_mime (>= 1.1.0)
|
||||
activesupport (6.1.7.4)
|
||||
activesupport (6.1.7.6)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 1.6, < 2)
|
||||
minitest (>= 5.1)
|
||||
|
@ -174,7 +174,7 @@ GEM
|
|||
cocoon (1.2.15)
|
||||
coderay (1.1.3)
|
||||
color_diff (0.1)
|
||||
concurrent-ruby (1.1.10)
|
||||
concurrent-ruby (1.2.2)
|
||||
connection_pool (2.3.0)
|
||||
cose (1.2.1)
|
||||
cbor (~> 0.5.9)
|
||||
|
@ -312,7 +312,7 @@ GEM
|
|||
httplog (1.6.0)
|
||||
rack (>= 2.0)
|
||||
rainbow (>= 2.0.0)
|
||||
i18n (1.12.0)
|
||||
i18n (1.14.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
i18n-tasks (1.0.12)
|
||||
activesupport (>= 4.0.2)
|
||||
|
@ -401,9 +401,9 @@ GEM
|
|||
mime-types (3.4.1)
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2022.0105)
|
||||
mini_mime (1.1.2)
|
||||
mini_portile2 (2.8.2)
|
||||
minitest (5.16.3)
|
||||
mini_mime (1.1.5)
|
||||
mini_portile2 (2.8.4)
|
||||
minitest (5.20.0)
|
||||
msgpack (1.5.4)
|
||||
multi_json (1.15.0)
|
||||
multipart-post (2.1.1)
|
||||
|
@ -412,7 +412,7 @@ GEM
|
|||
net-ssh (>= 2.6.5, < 8.0.0)
|
||||
net-ssh (7.0.1)
|
||||
nio4r (2.5.9)
|
||||
nokogiri (1.15.3)
|
||||
nokogiri (1.15.4)
|
||||
mini_portile2 (~> 2.8.2)
|
||||
racc (~> 1.4)
|
||||
nsa (0.2.8)
|
||||
|
@ -477,13 +477,13 @@ GEM
|
|||
pry-rails (0.3.9)
|
||||
pry (>= 0.10.4)
|
||||
public_suffix (5.0.0)
|
||||
puma (5.6.5)
|
||||
puma (5.6.7)
|
||||
nio4r (~> 2.0)
|
||||
pundit (2.2.0)
|
||||
activesupport (>= 3.0.0)
|
||||
raabro (1.4.0)
|
||||
racc (1.7.1)
|
||||
rack (2.2.7)
|
||||
rack (2.2.8)
|
||||
rack-attack (6.6.1)
|
||||
rack (>= 1.0, < 3)
|
||||
rack-cors (1.1.1)
|
||||
|
@ -498,20 +498,20 @@ GEM
|
|||
rack
|
||||
rack-test (2.0.2)
|
||||
rack (>= 1.3)
|
||||
rails (6.1.7.4)
|
||||
actioncable (= 6.1.7.4)
|
||||
actionmailbox (= 6.1.7.4)
|
||||
actionmailer (= 6.1.7.4)
|
||||
actionpack (= 6.1.7.4)
|
||||
actiontext (= 6.1.7.4)
|
||||
actionview (= 6.1.7.4)
|
||||
activejob (= 6.1.7.4)
|
||||
activemodel (= 6.1.7.4)
|
||||
activerecord (= 6.1.7.4)
|
||||
activestorage (= 6.1.7.4)
|
||||
activesupport (= 6.1.7.4)
|
||||
rails (6.1.7.6)
|
||||
actioncable (= 6.1.7.6)
|
||||
actionmailbox (= 6.1.7.6)
|
||||
actionmailer (= 6.1.7.6)
|
||||
actionpack (= 6.1.7.6)
|
||||
actiontext (= 6.1.7.6)
|
||||
actionview (= 6.1.7.6)
|
||||
activejob (= 6.1.7.6)
|
||||
activemodel (= 6.1.7.6)
|
||||
activerecord (= 6.1.7.6)
|
||||
activestorage (= 6.1.7.6)
|
||||
activesupport (= 6.1.7.6)
|
||||
bundler (>= 1.15.0)
|
||||
railties (= 6.1.7.4)
|
||||
railties (= 6.1.7.6)
|
||||
sprockets-rails (>= 2.0.0)
|
||||
rails-controller-testing (1.0.5)
|
||||
actionpack (>= 5.0.1.rc1)
|
||||
|
@ -527,9 +527,9 @@ GEM
|
|||
railties (>= 6.0.0, < 7)
|
||||
rails-settings-cached (0.6.6)
|
||||
rails (>= 4.2.0)
|
||||
railties (6.1.7.4)
|
||||
actionpack (= 6.1.7.4)
|
||||
activesupport (= 6.1.7.4)
|
||||
railties (6.1.7.6)
|
||||
actionpack (= 6.1.7.6)
|
||||
activesupport (= 6.1.7.6)
|
||||
method_source
|
||||
rake (>= 12.2)
|
||||
thor (~> 1.0)
|
||||
|
@ -609,8 +609,8 @@ GEM
|
|||
activerecord (>= 4.0.0)
|
||||
railties (>= 4.0.0)
|
||||
semantic_range (3.0.0)
|
||||
sidekiq (6.5.7)
|
||||
connection_pool (>= 2.2.5)
|
||||
sidekiq (6.5.11)
|
||||
connection_pool (>= 2.2.5, < 3)
|
||||
rack (~> 2.0)
|
||||
redis (>= 4.5.0, < 5)
|
||||
sidekiq-bulk (0.2.0)
|
||||
|
@ -718,14 +718,14 @@ GEM
|
|||
rack-proxy (>= 0.6.1)
|
||||
railties (>= 5.2)
|
||||
semantic_range (>= 2.3.0)
|
||||
websocket-driver (0.7.5)
|
||||
websocket-driver (0.7.6)
|
||||
websocket-extensions (>= 0.1.0)
|
||||
websocket-extensions (0.1.5)
|
||||
wisper (2.0.1)
|
||||
xorcist (1.1.3)
|
||||
xpath (3.2.0)
|
||||
nokogiri (~> 1.8)
|
||||
zeitwerk (2.6.8)
|
||||
zeitwerk (2.6.12)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
|
|
@ -13,6 +13,5 @@ A "vulnerability in Mastodon" is a vulnerability in the code distributed through
|
|||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 4.1.x | Yes |
|
||||
| 4.0.x | Until 2023-10-31 |
|
||||
| 3.5.x | Until 2023-12-31 |
|
||||
| < 3.5 | No |
|
||||
| 4.0.x | No |
|
||||
| < 4.0 | No |
|
||||
|
|
|
@ -246,7 +246,7 @@ module SignatureVerification
|
|||
stoplight_wrap_request { ResolveAccountService.new.call(key_id.gsub(/\Aacct:/, ''), suppress_errors: false) }
|
||||
elsif !ActivityPub::TagManager.instance.local_uri?(key_id)
|
||||
account = ActivityPub::TagManager.instance.uri_to_actor(key_id)
|
||||
account ||= stoplight_wrap_request { ActivityPub::FetchRemoteKeyService.new.call(key_id, id: false, suppress_errors: false) }
|
||||
account ||= stoplight_wrap_request { ActivityPub::FetchRemoteKeyService.new.call(key_id, suppress_errors: false) }
|
||||
account
|
||||
end
|
||||
rescue Mastodon::PrivateNetworkAddressError => e
|
||||
|
|
|
@ -157,8 +157,8 @@ module JsonLdHelper
|
|||
end
|
||||
end
|
||||
|
||||
def fetch_resource(uri, id, on_behalf_of = nil)
|
||||
unless id
|
||||
def fetch_resource(uri, id_is_known, on_behalf_of = nil)
|
||||
unless id_is_known
|
||||
json = fetch_resource_without_id_validation(uri, on_behalf_of)
|
||||
|
||||
return if !json.is_a?(Hash) || unsupported_uri_scheme?(json['id'])
|
||||
|
|
|
@ -152,7 +152,9 @@ class ActivityPub::Activity
|
|||
def fetch_remote_original_status
|
||||
if object_uri.start_with?('http')
|
||||
return if ActivityPub::TagManager.instance.local_uri?(object_uri)
|
||||
ActivityPub::FetchRemoteStatusService.new.call(object_uri, id: true, on_behalf_of: @account.followers.local.first)
|
||||
|
||||
|
||||
ActivityPub::FetchRemoteStatusService.new.call(object_uri, on_behalf_of: @account.followers.local.first)
|
||||
elsif @object['url'].present?
|
||||
::FetchRemoteStatusService.new.call(@object['url'])
|
||||
end
|
||||
|
|
|
@ -19,7 +19,7 @@ class ActivityPub::LinkedDataSignature
|
|||
return unless type == 'RsaSignature2017'
|
||||
|
||||
creator = ActivityPub::TagManager.instance.uri_to_actor(creator_uri)
|
||||
creator ||= ActivityPub::FetchRemoteKeyService.new.call(creator_uri, id: false)
|
||||
creator ||= ActivityPub::FetchRemoteKeyService.new.call(creator_uri)
|
||||
|
||||
return if creator.nil?
|
||||
|
||||
|
|
|
@ -34,7 +34,9 @@ class Importer::BaseImporter
|
|||
# Estimate the amount of documents that would be indexed. Not exact!
|
||||
# @returns [Integer]
|
||||
def estimate!
|
||||
ActiveRecord::Base.connection_pool.with_connection { |connection| connection.select_one("SELECT reltuples AS estimate FROM pg_class WHERE relname = '#{index.adapter.target.table_name}'")['estimate'].to_i }
|
||||
reltuples = ActiveRecord::Base.connection_pool.with_connection { |connection| connection.select_one("SELECT reltuples FROM pg_class WHERE relname = '#{index.adapter.target.table_name}'")['reltuples'].to_i }
|
||||
# If the table has never yet been vacuumed or analyzed, reltuples contains -1
|
||||
[reltuples, 0].max
|
||||
end
|
||||
|
||||
# Import data from the database into the index
|
||||
|
|
|
@ -46,7 +46,7 @@ class TranslationService::DeepL < TranslationService
|
|||
|
||||
raise UnexpectedResponseError unless json.is_a?(Hash)
|
||||
|
||||
Translation.new(text: json.dig('translations', 0, 'text'), detected_source_language: json.dig('translations', 0, 'detected_source_language')&.downcase, provider: 'DeepL.com')
|
||||
Translation.new(text: Sanitize.fragment(json.dig('translations', 0, 'text'), Sanitize::Config::MASTODON_STRICT), detected_source_language: json.dig('translations', 0, 'detected_source_language')&.downcase, provider: 'DeepL.com')
|
||||
rescue Oj::ParseError
|
||||
raise UnexpectedResponseError
|
||||
end
|
||||
|
|
|
@ -37,7 +37,7 @@ class TranslationService::LibreTranslate < TranslationService
|
|||
|
||||
raise UnexpectedResponseError unless json.is_a?(Hash)
|
||||
|
||||
Translation.new(text: json['translatedText'], detected_source_language: source_language, provider: 'LibreTranslate')
|
||||
Translation.new(text: Sanitize.fragment(json['translatedText'], Sanitize::Config::MASTODON_STRICT), detected_source_language: source_language, provider: 'LibreTranslate')
|
||||
rescue Oj::ParseError
|
||||
raise UnexpectedResponseError
|
||||
end
|
||||
|
|
|
@ -61,9 +61,9 @@ class Account < ApplicationRecord
|
|||
trust_level
|
||||
)
|
||||
|
||||
USERNAME_RE = /[a-z0-9_]+([a-z0-9_\.-]+[a-z0-9_]+)?/i
|
||||
MENTION_RE = /(?<=^|[^\/[:word:]])@((#{USERNAME_RE})(?:@[[:word:]\.\-]+[[:word:]]+)?)/i
|
||||
URL_PREFIX_RE = /\Ahttp(s?):\/\/[^\/]+/
|
||||
USERNAME_RE = /[a-z0-9_]+([a-z0-9_.-]+[a-z0-9_]+)?/i
|
||||
MENTION_RE = %r{(?<![=/[:word:]])@((#{USERNAME_RE})(?:@[[:word:].-]+[[:word:]]+)?)}i
|
||||
URL_PREFIX_RE = %r{\Ahttp(s?)://[^/]+}
|
||||
USERNAME_ONLY_RE = /\A#{USERNAME_RE}\z/i
|
||||
|
||||
include Attachmentable
|
||||
|
@ -114,8 +114,8 @@ class Account < ApplicationRecord
|
|||
scope :searchable, -> { without_unapproved.without_suspended.where(moved_to_account_id: nil) }
|
||||
scope :discoverable, -> { searchable.without_silenced.where(discoverable: true).left_outer_joins(:account_stat) }
|
||||
scope :followable_by, ->(account) { joins(arel_table.join(Follow.arel_table, Arel::Nodes::OuterJoin).on(arel_table[:id].eq(Follow.arel_table[:target_account_id]).and(Follow.arel_table[:account_id].eq(account.id))).join_sources).where(Follow.arel_table[:id].eq(nil)).joins(arel_table.join(FollowRequest.arel_table, Arel::Nodes::OuterJoin).on(arel_table[:id].eq(FollowRequest.arel_table[:target_account_id]).and(FollowRequest.arel_table[:account_id].eq(account.id))).join_sources).where(FollowRequest.arel_table[:id].eq(nil)) }
|
||||
scope :by_recent_status, -> { order(Arel.sql('(case when account_stats.last_status_at is null then 1 else 0 end) asc, account_stats.last_status_at desc, accounts.id desc')) }
|
||||
scope :by_recent_sign_in, -> { order(Arel.sql('(case when users.current_sign_in_at is null then 1 else 0 end) asc, users.current_sign_in_at desc, accounts.id desc')) }
|
||||
scope :by_recent_status, -> { includes(:account_stat).merge(AccountStat.order('last_status_at DESC NULLS LAST')).references(:account_stat) }
|
||||
scope :by_recent_sign_in, -> { order(Arel.sql('users.current_sign_in_at DESC NULLS LAST')) }
|
||||
scope :popular, -> { order('account_stats.followers_count desc') }
|
||||
scope :by_domain_and_subdomains, ->(domain) { where(domain: domain).or(where(arel_table[:domain].matches("%.#{domain}"))) }
|
||||
scope :not_excluded_by_account, ->(account) { where.not(id: account.excluded_from_timeline_account_ids) }
|
||||
|
|
|
@ -38,7 +38,7 @@ class Admin::ActionLogFilter
|
|||
destroy_status: { target_type: 'Status', action: 'destroy' }.freeze,
|
||||
destroy_user_role: { target_type: 'UserRole', action: 'destroy' }.freeze,
|
||||
destroy_canonical_email_block: { target_type: 'CanonicalEmailBlock', action: 'destroy' }.freeze,
|
||||
disable_2fa_user: { target_type: 'User', action: 'disable' }.freeze,
|
||||
disable_2fa_user: { target_type: 'User', action: 'disable_2fa' }.freeze,
|
||||
disable_custom_emoji: { target_type: 'CustomEmoji', action: 'disable' }.freeze,
|
||||
disable_user: { target_type: 'User', action: 'disable' }.freeze,
|
||||
enable_custom_emoji: { target_type: 'CustomEmoji', action: 'enable' }.freeze,
|
||||
|
|
|
@ -18,7 +18,7 @@ module AccountAvatar
|
|||
|
||||
included do
|
||||
# Avatar upload
|
||||
has_attached_file :avatar, styles: ->(f) { avatar_styles(f) }, convert_options: { all: '+profile "!icc,*" +set modify-date +set create-date' }, processors: [:lazy_thumbnail]
|
||||
has_attached_file :avatar, styles: ->(f) { avatar_styles(f) }, convert_options: { all: '+profile "!icc,*" +set date:modify +set date:create +set date:timestamp' }, processors: [:lazy_thumbnail]
|
||||
validates_attachment_content_type :avatar, content_type: IMAGE_MIME_TYPES
|
||||
validates_attachment_size :avatar, less_than: LIMIT
|
||||
remotable_attachment :avatar, LIMIT, suppress_errors: false
|
||||
|
|
|
@ -19,7 +19,7 @@ module AccountHeader
|
|||
|
||||
included do
|
||||
# Header upload
|
||||
has_attached_file :header, styles: ->(f) { header_styles(f) }, convert_options: { all: '+profile "!icc,*" +set modify-date +set create-date' }, processors: [:lazy_thumbnail]
|
||||
has_attached_file :header, styles: ->(f) { header_styles(f) }, convert_options: { all: '+profile "!icc,*" +set date:modify +set date:create +set date:timestamp' }, processors: [:lazy_thumbnail]
|
||||
validates_attachment_content_type :header, content_type: IMAGE_MIME_TYPES
|
||||
validates_attachment_size :header, less_than: LIMIT
|
||||
remotable_attachment :header, LIMIT, suppress_errors: false
|
||||
|
|
|
@ -37,7 +37,7 @@ class CustomEmoji < ApplicationRecord
|
|||
belongs_to :category, class_name: 'CustomEmojiCategory', optional: true
|
||||
has_one :local_counterpart, -> { where(domain: nil) }, class_name: 'CustomEmoji', primary_key: :shortcode, foreign_key: :shortcode
|
||||
|
||||
has_attached_file :image, styles: { static: { format: 'png', convert_options: '-coalesce +profile "!icc,*" +set modify-date +set create-date' } }, validate_media_type: false
|
||||
has_attached_file :image, styles: { static: { format: 'png', convert_options: '-coalesce +profile "!icc,*" +set date:modify +set date:create +set date:timestamp' } }, validate_media_type: false
|
||||
|
||||
before_validation :downcase_domain
|
||||
|
||||
|
|
|
@ -168,7 +168,7 @@ class MediaAttachment < ApplicationRecord
|
|||
}.freeze
|
||||
|
||||
GLOBAL_CONVERT_OPTIONS = {
|
||||
all: '-quality 90 +profile "!icc,*" +set modify-date +set create-date',
|
||||
all: '-quality 90 +profile "!icc,*" +set date:modify +set date:create +set date:timestamp',
|
||||
}.freeze
|
||||
|
||||
belongs_to :account, inverse_of: :media_attachments, optional: true
|
||||
|
|
|
@ -50,7 +50,7 @@ class PreviewCard < ApplicationRecord
|
|||
has_and_belongs_to_many :statuses
|
||||
has_one :trend, class_name: 'PreviewCardTrend', inverse_of: :preview_card, dependent: :destroy
|
||||
|
||||
has_attached_file :image, processors: [:thumbnail, :blurhash_transcoder], styles: ->(f) { image_styles(f) }, convert_options: { all: '-quality 90 +profile "!icc,*" +set modify-date +set create-date' }, validate_media_type: false
|
||||
has_attached_file :image, processors: [:thumbnail, :blurhash_transcoder], styles: ->(f) { image_styles(f) }, convert_options: { all: '-quality 90 +profile "!icc,*" +set date:modify +set date:create +set date:timestamp' }, validate_media_type: false
|
||||
|
||||
validates :url, presence: true, uniqueness: true
|
||||
validates_attachment_content_type :image, content_type: IMAGE_MIME_TYPES
|
||||
|
|
|
@ -25,7 +25,7 @@ class PreviewCardProvider < ApplicationRecord
|
|||
|
||||
validates :domain, presence: true, uniqueness: true, domain: true
|
||||
|
||||
has_attached_file :icon, styles: { static: { format: 'png', convert_options: '-coalesce +profile "!icc,*" +set modify-date +set create-date' } }, validate_media_type: false
|
||||
has_attached_file :icon, styles: { static: { format: 'png', convert_options: '-coalesce +profile "!icc,*" +set date:modify +set date:create +set date:timestamp' } }, validate_media_type: false
|
||||
validates_attachment :icon, content_type: { content_type: ICON_MIME_TYPES }, size: { less_than: LIMIT }
|
||||
remotable_attachment :icon, LIMIT
|
||||
|
||||
|
|
|
@ -60,13 +60,13 @@ class RelationshipFilter
|
|||
def relationship_scope(value)
|
||||
case value
|
||||
when 'following'
|
||||
account.following.eager_load(:account_stat).reorder(nil)
|
||||
account.following.includes(:account_stat).reorder(nil)
|
||||
when 'followed_by'
|
||||
account.followers.eager_load(:account_stat).reorder(nil)
|
||||
account.followers.includes(:account_stat).reorder(nil)
|
||||
when 'mutual'
|
||||
account.followers.eager_load(:account_stat).reorder(nil).merge(Account.where(id: account.following))
|
||||
account.followers.includes(:account_stat).reorder(nil).merge(Account.where(id: account.following))
|
||||
when 'invited'
|
||||
Account.joins(user: :invite).merge(Invite.where(user: account.user)).eager_load(:account_stat).reorder(nil)
|
||||
Account.joins(user: :invite).merge(Invite.where(user: account.user)).includes(:account_stat).reorder(nil)
|
||||
else
|
||||
raise Mastodon::InvalidParameterError, "Unknown relationship: #{value}"
|
||||
end
|
||||
|
@ -112,7 +112,7 @@ class RelationshipFilter
|
|||
def activity_scope(value)
|
||||
case value
|
||||
when 'dormant'
|
||||
AccountStat.where(last_status_at: nil).or(AccountStat.where(AccountStat.arel_table[:last_status_at].lt(1.month.ago)))
|
||||
Account.joins(:account_stat).where(account_stat: { last_status_at: [nil, ...1.month.ago] })
|
||||
else
|
||||
raise Mastodon::InvalidParameterError, "Unknown activity: #{value}"
|
||||
end
|
||||
|
|
|
@ -40,7 +40,7 @@ class SiteUpload < ApplicationRecord
|
|||
mascot: {}.freeze,
|
||||
}.freeze
|
||||
|
||||
has_attached_file :file, styles: ->(file) { STYLES[file.instance.var.to_sym] }, convert_options: { all: '-coalesce +profile "!icc,*" +set modify-date +set create-date' }, processors: [:lazy_thumbnail, :blurhash_transcoder, :type_corrector]
|
||||
has_attached_file :file, styles: ->(file) { STYLES[file.instance.var.to_sym] }, convert_options: { all: '-coalesce +profile "!icc,*" +set date:modify +set date:create +set date:timestamp' }, processors: [:lazy_thumbnail, :blurhash_transcoder, :type_corrector]
|
||||
|
||||
validates_attachment_content_type :file, content_type: /\Aimage\/.*\z/
|
||||
validates :file, presence: true
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class BackupPolicy < ApplicationPolicy
|
||||
MIN_AGE = 1.week
|
||||
MIN_AGE = 6.days
|
||||
|
||||
def create?
|
||||
user_signed_in? && current_user.backups.where('created_at >= ?', MIN_AGE.ago).count.zero?
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
class ActivityPub::FetchRemoteAccountService < ActivityPub::FetchRemoteActorService
|
||||
# Does a WebFinger roundtrip on each call, unless `only_key` is true
|
||||
def call(uri, id: true, prefetched_body: nil, break_on_redirect: false, only_key: false, suppress_errors: true)
|
||||
def call(uri, prefetched_body: nil, break_on_redirect: false, only_key: false, suppress_errors: true)
|
||||
actor = super
|
||||
return actor if actor.nil? || actor.is_a?(Account)
|
||||
|
||||
|
|
|
@ -10,15 +10,15 @@ class ActivityPub::FetchRemoteActorService < BaseService
|
|||
SUPPORTED_TYPES = %w(Application Group Organization Person Service).freeze
|
||||
|
||||
# Does a WebFinger roundtrip on each call, unless `only_key` is true
|
||||
def call(uri, id: true, prefetched_body: nil, break_on_redirect: false, only_key: false, suppress_errors: true)
|
||||
def call(uri, prefetched_body: nil, break_on_redirect: false, only_key: false, suppress_errors: true)
|
||||
return if domain_not_allowed?(uri)
|
||||
return ActivityPub::TagManager.instance.uri_to_actor(uri) if ActivityPub::TagManager.instance.local_uri?(uri)
|
||||
|
||||
@json = begin
|
||||
if prefetched_body.nil?
|
||||
fetch_resource(uri, id)
|
||||
fetch_resource(uri, true)
|
||||
else
|
||||
body_to_json(prefetched_body, compare_id: id ? uri : nil)
|
||||
body_to_json(prefetched_body, compare_id: uri)
|
||||
end
|
||||
rescue Oj::ParseError
|
||||
raise Error, "Error parsing JSON-LD document #{uri}"
|
||||
|
|
|
@ -6,23 +6,10 @@ class ActivityPub::FetchRemoteKeyService < BaseService
|
|||
class Error < StandardError; end
|
||||
|
||||
# Returns actor that owns the key
|
||||
def call(uri, id: true, prefetched_body: nil, suppress_errors: true)
|
||||
def call(uri, suppress_errors: true)
|
||||
raise Error, 'No key URI given' if uri.blank?
|
||||
|
||||
if prefetched_body.nil?
|
||||
if id
|
||||
@json = fetch_resource_without_id_validation(uri)
|
||||
if actor_type?
|
||||
@json = fetch_resource(@json['id'], true)
|
||||
elsif uri != @json['id']
|
||||
raise Error, "Fetched URI #{uri} has wrong id #{@json['id']}"
|
||||
end
|
||||
else
|
||||
@json = fetch_resource(uri, id)
|
||||
end
|
||||
else
|
||||
@json = body_to_json(prefetched_body, compare_id: id ? uri : nil)
|
||||
end
|
||||
@json = fetch_resource(uri, false)
|
||||
|
||||
raise Error, "Unable to fetch key JSON at #{uri}" if @json.nil?
|
||||
raise Error, "Unsupported JSON-LD context for document #{uri}" unless supported_context?(@json)
|
||||
|
|
|
@ -4,12 +4,12 @@ class ActivityPub::FetchRemoteStatusService < BaseService
|
|||
include JsonLdHelper
|
||||
|
||||
# Should be called when uri has already been checked for locality
|
||||
def call(uri, id: true, prefetched_body: nil, on_behalf_of: nil)
|
||||
def call(uri, prefetched_body: nil, on_behalf_of: nil)
|
||||
@json = begin
|
||||
if prefetched_body.nil?
|
||||
fetch_resource(uri, id, on_behalf_of)
|
||||
fetch_resource(uri, true, on_behalf_of)
|
||||
else
|
||||
body_to_json(prefetched_body, compare_id: id ? uri : nil)
|
||||
body_to_json(prefetched_body, compare_id: uri)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -52,7 +52,7 @@ class ActivityPub::FetchRemoteStatusService < BaseService
|
|||
|
||||
def account_from_uri(uri)
|
||||
actor = ActivityPub::TagManager.instance.uri_to_resource(uri, Account)
|
||||
actor = ActivityPub::FetchRemoteAccountService.new.call(uri, id: true) if actor.nil? || actor.possibly_stale?
|
||||
actor = ActivityPub::FetchRemoteAccountService.new.call(uri) if actor.nil? || actor.possibly_stale?
|
||||
actor
|
||||
end
|
||||
|
||||
|
|
|
@ -257,7 +257,7 @@ class ActivityPub::ProcessAccountService < BaseService
|
|||
|
||||
def moved_account
|
||||
account = ActivityPub::TagManager.instance.uri_to_resource(@json['movedTo'], Account)
|
||||
account ||= ActivityPub::FetchRemoteAccountService.new.call(@json['movedTo'], id: true, break_on_redirect: true)
|
||||
account ||= ActivityPub::FetchRemoteAccountService.new.call(@json['movedTo'], break_on_redirect: true)
|
||||
account
|
||||
end
|
||||
|
||||
|
|
|
@ -47,7 +47,15 @@ class FetchResourceService < BaseService
|
|||
body = response.body_with_limit
|
||||
json = body_to_json(body)
|
||||
|
||||
[json['id'], { prefetched_body: body, id: true }] if supported_context?(json) && (equals_or_includes_any?(json['type'], ActivityPub::FetchRemoteActorService::SUPPORTED_TYPES) || expected_type?(json))
|
||||
return unless supported_context?(json) && (equals_or_includes_any?(json['type'], ActivityPub::FetchRemoteActorService::SUPPORTED_TYPES) || expected_type?(json))
|
||||
|
||||
if json['id'] != @url
|
||||
return if terminal
|
||||
|
||||
return process(json['id'], terminal: true)
|
||||
end
|
||||
|
||||
[@url, { prefetched_body: body }]
|
||||
elsif !terminal
|
||||
link_header = response['Link'] && parse_link_header(response)
|
||||
|
||||
|
|
|
@ -12,8 +12,8 @@ class TranslateStatusService < BaseService
|
|||
@content = status_content_format(@status)
|
||||
@target_language = target_language
|
||||
|
||||
Rails.cache.fetch("translations/#{@status.language}/#{@target_language}/#{content_hash}", expires_in: CACHE_TTL) do
|
||||
Sanitize.fragment(translation_backend.translate(@content, @status.language, @target_language), Sanitize::Config::MASTODON_STRICT)
|
||||
Rails.cache.fetch("translations:v2/#{@status.language}/#{@target_language}/#{content_hash}", expires_in: CACHE_TTL) do
|
||||
translation_backend.translate(@content, @status.language, @target_language)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
class AccountDeletionWorker
|
||||
include Sidekiq::Worker
|
||||
|
||||
sidekiq_options queue: 'pull', lock: :until_executed
|
||||
sidekiq_options queue: 'pull', lock: :until_executed, lock_ttl: 1.week.to_i
|
||||
|
||||
def perform(account_id, options = {})
|
||||
reserve_username = options.with_indifferent_access.fetch(:reserve_username, true)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
class ActivityPub::SynchronizeFeaturedCollectionWorker
|
||||
include Sidekiq::Worker
|
||||
|
||||
sidekiq_options queue: 'pull', lock: :until_executed
|
||||
sidekiq_options queue: 'pull', lock: :until_executed, lock_ttl: 1.day.to_i
|
||||
|
||||
def perform(account_id, options = {})
|
||||
options = { note: true, hashtag: false }.deep_merge(options.deep_symbolize_keys)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
class ActivityPub::SynchronizeFeaturedTagsCollectionWorker
|
||||
include Sidekiq::Worker
|
||||
|
||||
sidekiq_options queue: 'pull', lock: :until_executed
|
||||
sidekiq_options queue: 'pull', lock: :until_executed, lock_ttl: 1.day.to_i
|
||||
|
||||
def perform(account_id, url)
|
||||
ActivityPub::FetchFeaturedTagsCollectionService.new.call(Account.find(account_id), url)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub::UpdateDistributionWorker < ActivityPub::RawDistributionWorker
|
||||
sidekiq_options queue: 'push', lock: :until_executed
|
||||
sidekiq_options queue: 'push', lock: :until_executed, lock_ttl: 1.day.to_i
|
||||
|
||||
# Distribute an profile update to servers that might have a copy
|
||||
# of the account in question
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
class Admin::AccountDeletionWorker
|
||||
include Sidekiq::Worker
|
||||
|
||||
sidekiq_options queue: 'pull', lock: :until_executed
|
||||
sidekiq_options queue: 'pull', lock: :until_executed, lock_ttl: 1.week.to_i
|
||||
|
||||
def perform(account_id)
|
||||
DeleteAccountService.new.call(Account.find(account_id), reserve_username: true, reserve_email: true)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
class Admin::DomainPurgeWorker
|
||||
include Sidekiq::Worker
|
||||
|
||||
sidekiq_options queue: 'pull', lock: :until_executed
|
||||
sidekiq_options queue: 'pull', lock: :until_executed, lock_ttl: 1.week.to_i
|
||||
|
||||
def perform(domain)
|
||||
PurgeDomainService.new.call(domain)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
class PublishScheduledStatusWorker
|
||||
include Sidekiq::Worker
|
||||
|
||||
sidekiq_options lock: :until_executed
|
||||
sidekiq_options lock: :until_executed, lock_ttl: 1.hour.to_i
|
||||
|
||||
def perform(scheduled_status_id)
|
||||
scheduled_status = ScheduledStatus.find(scheduled_status_id)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
class ResolveAccountWorker
|
||||
include Sidekiq::Worker
|
||||
|
||||
sidekiq_options queue: 'pull', lock: :until_executed
|
||||
sidekiq_options queue: 'pull', lock: :until_executed, lock_ttl: 1.day.to_i
|
||||
|
||||
def perform(uri)
|
||||
ResolveAccountService.new.call(uri)
|
||||
|
|
|
@ -4,7 +4,7 @@ class Scheduler::IndexingScheduler
|
|||
include Sidekiq::Worker
|
||||
include Redisable
|
||||
|
||||
sidekiq_options retry: 0
|
||||
sidekiq_options retry: 0, lock: :until_executed, lock_ttl: 30.minutes.to_i
|
||||
|
||||
IMPORT_BATCH_SIZE = 1000
|
||||
SCAN_BATCH_SIZE = 10 * IMPORT_BATCH_SIZE
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
class Scheduler::ScheduledStatusesScheduler
|
||||
include Sidekiq::Worker
|
||||
|
||||
sidekiq_options retry: 0
|
||||
sidekiq_options retry: 0, lock: :until_executed, lock_ttl: 1.hour.to_i
|
||||
|
||||
def perform
|
||||
publish_scheduled_statuses!
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
class Scheduler::Trends::RefreshScheduler
|
||||
include Sidekiq::Worker
|
||||
|
||||
sidekiq_options retry: 0
|
||||
sidekiq_options retry: 0, lock: :until_executed, lock_ttl: 30.minutes.to_i
|
||||
|
||||
def perform
|
||||
Trends.refresh!
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
class VerifyAccountLinksWorker
|
||||
include Sidekiq::Worker
|
||||
|
||||
sidekiq_options queue: 'default', retry: false, lock: :until_executed
|
||||
sidekiq_options queue: 'default', retry: false, lock: :until_executed, lock_ttl: 1.hour.to_i
|
||||
|
||||
def perform(account_id)
|
||||
account = Account.find(account_id)
|
||||
|
|
|
@ -56,7 +56,7 @@ services:
|
|||
|
||||
web:
|
||||
build: .
|
||||
image: ghcr.io/mastodon/mastodon:v4.0.10
|
||||
image: ghcr.io/mastodon/mastodon:v4.0.13
|
||||
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.0.10
|
||||
image: ghcr.io/mastodon/mastodon:v4.0.13
|
||||
restart: always
|
||||
env_file: .env.production
|
||||
command: node ./streaming
|
||||
|
@ -95,7 +95,7 @@ services:
|
|||
|
||||
sidekiq:
|
||||
build: .
|
||||
image: ghcr.io/mastodon/mastodon:v4.0.10
|
||||
image: ghcr.io/mastodon/mastodon:v4.0.13
|
||||
restart: always
|
||||
env_file: .env.production
|
||||
command: bundle exec sidekiq
|
||||
|
|
|
@ -13,7 +13,7 @@ module Mastodon
|
|||
end
|
||||
|
||||
def patch
|
||||
10
|
||||
13
|
||||
end
|
||||
|
||||
def flags
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
Fabricator(:account_stat) do
|
||||
account nil
|
||||
statuses_count ""
|
||||
following_count ""
|
||||
followers_count ""
|
||||
account { Fabricate.build(:account) }
|
||||
statuses_count '123'
|
||||
following_count '456'
|
||||
followers_count '789'
|
||||
end
|
||||
|
|
|
@ -689,7 +689,7 @@ RSpec.describe Account, type: :model do
|
|||
expect(subject.match('Check this out https://medium.com/@alice/some-article#.abcdef123')).to be_nil
|
||||
end
|
||||
|
||||
xit 'does not match URL querystring' do
|
||||
it 'does not match URL query string' do
|
||||
expect(subject.match('https://example.com/?x=@alice')).to be_nil
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,32 +6,60 @@ describe RelationshipFilter do
|
|||
let(:account) { Fabricate(:account) }
|
||||
|
||||
describe '#results' do
|
||||
context 'when default params are used' do
|
||||
let(:subject) do
|
||||
RelationshipFilter.new(account, 'order' => 'active').results
|
||||
let(:account_of_7_months) { Fabricate(:account_stat, statuses_count: 1, last_status_at: 7.months.ago).account }
|
||||
let(:account_of_1_day) { Fabricate(:account_stat, statuses_count: 1, last_status_at: 1.day.ago).account }
|
||||
let(:account_of_3_days) { Fabricate(:account_stat, statuses_count: 1, last_status_at: 3.days.ago).account }
|
||||
let(:silent_account) { Fabricate(:account_stat, statuses_count: 0, last_status_at: nil).account }
|
||||
|
||||
before do
|
||||
account.follow!(account_of_7_months)
|
||||
account.follow!(account_of_1_day)
|
||||
account.follow!(account_of_3_days)
|
||||
account.follow!(silent_account)
|
||||
end
|
||||
|
||||
context 'when ordering by last activity' do
|
||||
context 'when not filtering' do
|
||||
subject do
|
||||
described_class.new(account, 'order' => 'active').results
|
||||
end
|
||||
|
||||
it 'returns followings ordered by last activity' do
|
||||
expect(subject).to eq [account_of_1_day, account_of_3_days, account_of_7_months, silent_account]
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
add_following_account_with(last_status_at: 7.days.ago)
|
||||
add_following_account_with(last_status_at: 1.day.ago)
|
||||
add_following_account_with(last_status_at: 3.days.ago)
|
||||
context 'when filtering for dormant accounts' do
|
||||
subject do
|
||||
described_class.new(account, 'order' => 'active', 'activity' => 'dormant').results
|
||||
end
|
||||
|
||||
it 'returns dormant followings ordered by last activity' do
|
||||
expect(subject).to eq [account_of_7_months, silent_account]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when ordering by account creation' do
|
||||
context 'when not filtering' do
|
||||
subject do
|
||||
described_class.new(account, 'order' => 'recent').results
|
||||
end
|
||||
|
||||
it 'returns followings ordered by last account creation' do
|
||||
expect(subject).to eq [silent_account, account_of_3_days, account_of_1_day, account_of_7_months]
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns followings ordered by last activity' do
|
||||
expected_result = account.following.eager_load(:account_stat).reorder(nil).by_recent_status
|
||||
context 'when filtering for dormant accounts' do
|
||||
subject do
|
||||
described_class.new(account, 'order' => 'recent', 'activity' => 'dormant').results
|
||||
end
|
||||
|
||||
expect(subject).to eq expected_result
|
||||
it 'returns dormant followings ordered by last activity' do
|
||||
expect(subject).to eq [silent_account, account_of_7_months]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def add_following_account_with(last_status_at:)
|
||||
following_account = Fabricate(:account)
|
||||
Fabricate(:account_stat, account: following_account,
|
||||
last_status_at: last_status_at,
|
||||
statuses_count: 1,
|
||||
following_count: 0,
|
||||
followers_count: 0)
|
||||
Fabricate(:follow, account: account, target_account: following_account).account
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,7 +16,7 @@ RSpec.describe ActivityPub::FetchRemoteAccountService, type: :service do
|
|||
end
|
||||
|
||||
describe '#call' do
|
||||
let(:account) { subject.call('https://example.com/alice', id: true) }
|
||||
let(:account) { subject.call('https://example.com/alice') }
|
||||
|
||||
shared_examples 'sets profile data' do
|
||||
it 'returns an account' do
|
||||
|
|
|
@ -16,7 +16,7 @@ RSpec.describe ActivityPub::FetchRemoteActorService, type: :service do
|
|||
end
|
||||
|
||||
describe '#call' do
|
||||
let(:account) { subject.call('https://example.com/alice', id: true) }
|
||||
let(:account) { subject.call('https://example.com/alice') }
|
||||
|
||||
shared_examples 'sets profile data' do
|
||||
it 'returns an account' do
|
||||
|
|
|
@ -43,7 +43,7 @@ RSpec.describe ActivityPub::FetchRemoteKeyService, type: :service do
|
|||
end
|
||||
|
||||
describe '#call' do
|
||||
let(:account) { subject.call(public_key_id, id: false) }
|
||||
let(:account) { subject.call(public_key_id) }
|
||||
|
||||
context 'when the key is a sub-object from the actor' do
|
||||
before do
|
||||
|
|
|
@ -54,7 +54,7 @@ RSpec.describe FetchResourceService, type: :service do
|
|||
|
||||
let(:json) do
|
||||
{
|
||||
id: 1,
|
||||
id: 'http://example.com/foo',
|
||||
'@context': ActivityPub::TagManager::CONTEXT,
|
||||
type: 'Note',
|
||||
}.to_json
|
||||
|
@ -79,14 +79,14 @@ RSpec.describe FetchResourceService, type: :service do
|
|||
let(:content_type) { 'application/activity+json; charset=utf-8' }
|
||||
let(:body) { json }
|
||||
|
||||
it { is_expected.to eq [1, { prefetched_body: body, id: true }] }
|
||||
it { is_expected.to eq ['http://example.com/foo', { prefetched_body: body }] }
|
||||
end
|
||||
|
||||
context 'when content type is ld+json with profile' do
|
||||
let(:content_type) { 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' }
|
||||
let(:body) { json }
|
||||
|
||||
it { is_expected.to eq [1, { prefetched_body: body, id: true }] }
|
||||
it { is_expected.to eq ['http://example.com/foo', { prefetched_body: body }] }
|
||||
end
|
||||
|
||||
before do
|
||||
|
@ -97,14 +97,14 @@ RSpec.describe FetchResourceService, type: :service do
|
|||
context 'when link header is present' do
|
||||
let(:headers) { { 'Link' => '<http://example.com/foo>; rel="alternate"; type="application/activity+json"', } }
|
||||
|
||||
it { is_expected.to eq [1, { prefetched_body: json, id: true }] }
|
||||
it { is_expected.to eq ['http://example.com/foo', { prefetched_body: json }] }
|
||||
end
|
||||
|
||||
context 'when content type is text/html' do
|
||||
let(:content_type) { 'text/html' }
|
||||
let(:body) { '<html><head><link rel="alternate" href="http://example.com/foo" type="application/activity+json"/></head></html>' }
|
||||
|
||||
it { is_expected.to eq [1, { prefetched_body: json, id: true }] }
|
||||
it { is_expected.to eq ['http://example.com/foo', { prefetched_body: json }] }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -139,6 +139,7 @@ describe ResolveURLService, type: :service do
|
|||
stub_request(:get, url).to_return(status: 302, headers: { 'Location' => status_url })
|
||||
body = ActiveModelSerializers::SerializableResource.new(status, serializer: ActivityPub::NoteSerializer, adapter: ActivityPub::Adapter).to_json
|
||||
stub_request(:get, status_url).to_return(body: body, headers: { 'Content-Type' => 'application/activity+json' })
|
||||
stub_request(:get, uri).to_return(body: body, headers: { 'Content-Type' => 'application/activity+json' })
|
||||
end
|
||||
|
||||
it 'returns status by url' do
|
||||
|
|
Loading…
Reference in New Issue