Merge commit 'd27eb181f6ab419d1745a1fe9b94094be17a618f' into glitch-soc/merge-upstream
Conflicts: - `spec/requests/api/v2/instance_spec.rb`: Conflict due to glitch-soc having a different default site name. Updated the tests as upstream did, keeping glitch-soc's default name.main-rebase-security-fix
commit
15f6d2d038
|
@ -11,6 +11,6 @@ linters:
|
||||||
MiddleDot:
|
MiddleDot:
|
||||||
enabled: true
|
enabled: true
|
||||||
LineLength:
|
LineLength:
|
||||||
max: 320
|
max: 300
|
||||||
ViewLength:
|
ViewLength:
|
||||||
max: 200 # Override default value of 100 inherited from rubocop
|
max: 200 # Override default value of 100 inherited from rubocop
|
||||||
|
|
|
@ -39,7 +39,7 @@ Layout/FirstHashElementIndentation:
|
||||||
# Reason: Currently disabled in .rubocop_todo.yml
|
# Reason: Currently disabled in .rubocop_todo.yml
|
||||||
# https://docs.rubocop.org/rubocop/cops_layout.html#layoutlinelength
|
# https://docs.rubocop.org/rubocop/cops_layout.html#layoutlinelength
|
||||||
Layout/LineLength:
|
Layout/LineLength:
|
||||||
Max: 320 # Default of 120 causes a duplicate entry in generated todo file
|
Max: 300 # Default of 120 causes a duplicate entry in generated todo file
|
||||||
|
|
||||||
## Disable most Metrics/*Length cops
|
## Disable most Metrics/*Length cops
|
||||||
# Reason: those are often triggered and force significant refactors when this happend
|
# Reason: those are often triggered and force significant refactors when this happend
|
||||||
|
|
3
Gemfile
3
Gemfile
|
@ -69,7 +69,6 @@ gem 'nsa'
|
||||||
gem 'oj', '~> 3.14'
|
gem 'oj', '~> 3.14'
|
||||||
gem 'ox', '~> 2.14'
|
gem 'ox', '~> 2.14'
|
||||||
gem 'parslet'
|
gem 'parslet'
|
||||||
gem 'posix-spawn'
|
|
||||||
gem 'public_suffix', '~> 5.0'
|
gem 'public_suffix', '~> 5.0'
|
||||||
gem 'pundit', '~> 2.3'
|
gem 'pundit', '~> 2.3'
|
||||||
gem 'premailer-rails'
|
gem 'premailer-rails'
|
||||||
|
@ -89,7 +88,7 @@ gem 'sidekiq-unique-jobs', '~> 7.1'
|
||||||
gem 'sidekiq-bulk', '~> 0.2.0'
|
gem 'sidekiq-bulk', '~> 0.2.0'
|
||||||
gem 'simple-navigation', '~> 4.4'
|
gem 'simple-navigation', '~> 4.4'
|
||||||
gem 'simple_form', '~> 5.2'
|
gem 'simple_form', '~> 5.2'
|
||||||
gem 'stoplight', '~> 3.0.1'
|
gem 'stoplight', '~> 4.1'
|
||||||
gem 'strong_migrations', '1.8.0'
|
gem 'strong_migrations', '1.8.0'
|
||||||
gem 'tty-prompt', '~> 0.23', require: false
|
gem 'tty-prompt', '~> 0.23', require: false
|
||||||
gem 'twitter-text', '~> 3.1.0'
|
gem 'twitter-text', '~> 3.1.0'
|
||||||
|
|
|
@ -245,7 +245,7 @@ GEM
|
||||||
tzinfo
|
tzinfo
|
||||||
excon (0.110.0)
|
excon (0.110.0)
|
||||||
fabrication (2.31.0)
|
fabrication (2.31.0)
|
||||||
faker (3.3.0)
|
faker (3.3.1)
|
||||||
i18n (>= 1.8.11, < 2)
|
i18n (>= 1.8.11, < 2)
|
||||||
faraday (1.10.3)
|
faraday (1.10.3)
|
||||||
faraday-em_http (~> 1.0)
|
faraday-em_http (~> 1.0)
|
||||||
|
@ -509,7 +509,6 @@ GEM
|
||||||
pg (1.5.6)
|
pg (1.5.6)
|
||||||
pghero (3.4.1)
|
pghero (3.4.1)
|
||||||
activerecord (>= 6)
|
activerecord (>= 6)
|
||||||
posix-spawn (0.3.15)
|
|
||||||
premailer (1.23.0)
|
premailer (1.23.0)
|
||||||
addressable
|
addressable
|
||||||
css_parser (>= 1.12.0)
|
css_parser (>= 1.12.0)
|
||||||
|
@ -733,7 +732,7 @@ GEM
|
||||||
smart_properties (1.17.0)
|
smart_properties (1.17.0)
|
||||||
stackprof (0.2.26)
|
stackprof (0.2.26)
|
||||||
statsd-ruby (1.5.0)
|
statsd-ruby (1.5.0)
|
||||||
stoplight (3.0.2)
|
stoplight (4.1.0)
|
||||||
redlock (~> 1.0)
|
redlock (~> 1.0)
|
||||||
stringio (3.1.0)
|
stringio (3.1.0)
|
||||||
strong_migrations (1.8.0)
|
strong_migrations (1.8.0)
|
||||||
|
@ -899,7 +898,6 @@ DEPENDENCIES
|
||||||
parslet
|
parslet
|
||||||
pg (~> 1.5)
|
pg (~> 1.5)
|
||||||
pghero
|
pghero
|
||||||
posix-spawn
|
|
||||||
premailer-rails
|
premailer-rails
|
||||||
private_address_check (~> 0.5)
|
private_address_check (~> 0.5)
|
||||||
propshaft
|
propshaft
|
||||||
|
@ -941,7 +939,7 @@ DEPENDENCIES
|
||||||
simplecov (~> 0.22)
|
simplecov (~> 0.22)
|
||||||
simplecov-lcov (~> 0.8)
|
simplecov-lcov (~> 0.8)
|
||||||
stackprof
|
stackprof
|
||||||
stoplight (~> 3.0.1)
|
stoplight (~> 4.1)
|
||||||
strong_migrations (= 1.8.0)
|
strong_migrations (= 1.8.0)
|
||||||
test-prof
|
test-prof
|
||||||
thor (~> 1.2)
|
thor (~> 1.2)
|
||||||
|
|
|
@ -66,7 +66,7 @@ module SignatureVerification
|
||||||
compare_signed_string = build_signed_string(include_query_string: false)
|
compare_signed_string = build_signed_string(include_query_string: false)
|
||||||
return actor unless verify_signature(actor, signature, compare_signed_string).nil?
|
return actor unless verify_signature(actor, signature, compare_signed_string).nil?
|
||||||
|
|
||||||
actor = stoplight_wrap_request { actor_refresh_key!(actor) }
|
actor = stoplight_wrapper.run { actor_refresh_key!(actor) }
|
||||||
|
|
||||||
raise SignatureVerificationError, "Could not refresh public key #{signature_params['keyId']}" if actor.nil?
|
raise SignatureVerificationError, "Could not refresh public key #{signature_params['keyId']}" if actor.nil?
|
||||||
|
|
||||||
|
@ -226,10 +226,10 @@ module SignatureVerification
|
||||||
end
|
end
|
||||||
|
|
||||||
if key_id.start_with?('acct:')
|
if key_id.start_with?('acct:')
|
||||||
stoplight_wrap_request { ResolveAccountService.new.call(key_id.delete_prefix('acct:'), suppress_errors: false) }
|
stoplight_wrapper.run { ResolveAccountService.new.call(key_id.delete_prefix('acct:'), suppress_errors: false) }
|
||||||
elsif !ActivityPub::TagManager.instance.local_uri?(key_id)
|
elsif !ActivityPub::TagManager.instance.local_uri?(key_id)
|
||||||
account = ActivityPub::TagManager.instance.uri_to_actor(key_id)
|
account = ActivityPub::TagManager.instance.uri_to_actor(key_id)
|
||||||
account ||= stoplight_wrap_request { ActivityPub::FetchRemoteKeyService.new.call(key_id, suppress_errors: false) }
|
account ||= stoplight_wrapper.run { ActivityPub::FetchRemoteKeyService.new.call(key_id, suppress_errors: false) }
|
||||||
account
|
account
|
||||||
end
|
end
|
||||||
rescue Mastodon::PrivateNetworkAddressError => e
|
rescue Mastodon::PrivateNetworkAddressError => e
|
||||||
|
@ -238,12 +238,11 @@ module SignatureVerification
|
||||||
raise SignatureVerificationError, e.message
|
raise SignatureVerificationError, e.message
|
||||||
end
|
end
|
||||||
|
|
||||||
def stoplight_wrap_request(&block)
|
def stoplight_wrapper
|
||||||
Stoplight("source:#{request.remote_ip}", &block)
|
Stoplight("source:#{request.remote_ip}")
|
||||||
.with_threshold(1)
|
.with_threshold(1)
|
||||||
.with_cool_off_time(5.minutes.seconds)
|
.with_cool_off_time(5.minutes.seconds)
|
||||||
.with_error_handler { |error, handle| error.is_a?(HTTP::Error) || error.is_a?(OpenSSL::SSL::SSLError) ? handle.call(error) : raise(error) }
|
.with_error_handler { |error, handle| error.is_a?(HTTP::Error) || error.is_a?(OpenSSL::SSL::SSLError) ? handle.call(error) : raise(error) }
|
||||||
.run
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def actor_refresh_key!(actor)
|
def actor_refresh_key!(actor)
|
||||||
|
|
|
@ -10104,9 +10104,10 @@ noscript {
|
||||||
}
|
}
|
||||||
|
|
||||||
.filtered-notifications-banner__badge {
|
.filtered-notifications-banner__badge {
|
||||||
background-color: $highlight-text-color;
|
background: $ui-button-background-color;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 1px 6px;
|
padding: 1px 6px;
|
||||||
|
color: $white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -491,10 +491,10 @@ class FeedManager
|
||||||
# @param [List] list
|
# @param [List] list
|
||||||
# @return [Boolean]
|
# @return [Boolean]
|
||||||
def filter_from_list?(status, list)
|
def filter_from_list?(status, list)
|
||||||
if status.reply? && status.in_reply_to_account_id != status.account_id
|
if status.reply? && status.in_reply_to_account_id != status.account_id # Status is a reply to account other than status account
|
||||||
should_filter = status.in_reply_to_account_id != list.account_id
|
should_filter = status.in_reply_to_account_id != list.account_id # Status replies to account id other than list account
|
||||||
should_filter &&= !list.show_followed?
|
should_filter &&= !list.show_followed? # List show_followed? is false
|
||||||
should_filter &&= !(list.show_list? && ListAccount.exists?(list_id: list.id, account_id: status.in_reply_to_account_id))
|
should_filter &&= !(list.show_list? && ListAccount.exists?(list_id: list.id, account_id: status.in_reply_to_account_id)) # If show_list? true, check for a ListAccount with list and reply to account
|
||||||
|
|
||||||
return !!should_filter
|
return !!should_filter
|
||||||
end
|
end
|
||||||
|
@ -509,7 +509,11 @@ class FeedManager
|
||||||
# @param [Hash] crutches
|
# @param [Hash] crutches
|
||||||
# @return [Boolean]
|
# @return [Boolean]
|
||||||
def filter_from_tags?(status, receiver_id, crutches)
|
def filter_from_tags?(status, receiver_id, crutches)
|
||||||
receiver_id == status.account_id || ((crutches[:active_mentions][status.id] || []) + [status.account_id]).any? { |target_account_id| crutches[:blocking][target_account_id] || crutches[:muting][target_account_id] } || crutches[:blocked_by][status.account_id] || crutches[:domain_blocking][status.account.domain]
|
receiver_id == status.account_id || # Receiver is status account?
|
||||||
|
((crutches[:active_mentions][status.id] || []) + [status.account_id]) # For mentioned accounts or status account:
|
||||||
|
.any? { |target_account_id| crutches[:blocking][target_account_id] || crutches[:muting][target_account_id] } || # - Target account is muted or blocked?
|
||||||
|
crutches[:blocked_by][status.account_id] || # Blocked by status account?
|
||||||
|
crutches[:domain_blocking][status.account.domain] # Blocking domain of status account?
|
||||||
end
|
end
|
||||||
|
|
||||||
# Adds a status to an account's feed, returning true if a status was
|
# Adds a status to an account's feed, returning true if a status was
|
||||||
|
|
|
@ -15,4 +15,6 @@ class UserIp < ApplicationRecord
|
||||||
self.primary_key = :user_id
|
self.primary_key = :user_id
|
||||||
|
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
|
|
||||||
|
scope :by_latest_used, -> { order(used_at: :desc) }
|
||||||
end
|
end
|
||||||
|
|
|
@ -54,6 +54,7 @@ class REST::InstanceSerializer < ActiveModel::Serializer
|
||||||
|
|
||||||
accounts: {
|
accounts: {
|
||||||
max_featured_tags: FeaturedTag::LIMIT,
|
max_featured_tags: FeaturedTag::LIMIT,
|
||||||
|
max_pinned_statuses: StatusPinValidator::PIN_LIMIT,
|
||||||
},
|
},
|
||||||
|
|
||||||
statuses: {
|
statuses: {
|
||||||
|
|
|
@ -10,7 +10,7 @@ class BulkImportRowService
|
||||||
when :following, :blocking, :muting, :lists
|
when :following, :blocking, :muting, :lists
|
||||||
target_acct = @data['acct']
|
target_acct = @data['acct']
|
||||||
target_domain = domain(target_acct)
|
target_domain = domain(target_acct)
|
||||||
@target_account = stoplight_wrap_request(target_domain) { ResolveAccountService.new.call(target_acct, { check_delivery_availability: true }) }
|
@target_account = stoplight_wrapper(target_domain).run { ResolveAccountService.new.call(target_acct, { check_delivery_availability: true }) }
|
||||||
return false if @target_account.nil?
|
return false if @target_account.nil?
|
||||||
when :bookmarks
|
when :bookmarks
|
||||||
target_uri = @data['uri']
|
target_uri = @data['uri']
|
||||||
|
@ -18,7 +18,7 @@ class BulkImportRowService
|
||||||
@target_status = ActivityPub::TagManager.instance.uri_to_resource(target_uri, Status)
|
@target_status = ActivityPub::TagManager.instance.uri_to_resource(target_uri, Status)
|
||||||
return false if @target_status.nil? && ActivityPub::TagManager.instance.local_uri?(target_uri)
|
return false if @target_status.nil? && ActivityPub::TagManager.instance.local_uri?(target_uri)
|
||||||
|
|
||||||
@target_status ||= stoplight_wrap_request(target_domain) { ActivityPub::FetchRemoteStatusService.new.call(target_uri) }
|
@target_status ||= stoplight_wrapper(target_domain).run { ActivityPub::FetchRemoteStatusService.new.call(target_uri) }
|
||||||
return false if @target_status.nil?
|
return false if @target_status.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -51,16 +51,15 @@ class BulkImportRowService
|
||||||
TagManager.instance.local_domain?(domain) ? nil : TagManager.instance.normalize_domain(domain)
|
TagManager.instance.local_domain?(domain) ? nil : TagManager.instance.normalize_domain(domain)
|
||||||
end
|
end
|
||||||
|
|
||||||
def stoplight_wrap_request(domain, &block)
|
def stoplight_wrapper(domain)
|
||||||
if domain.present?
|
if domain.present?
|
||||||
Stoplight("source:#{domain}", &block)
|
Stoplight("source:#{domain}")
|
||||||
.with_fallback { nil }
|
.with_fallback { nil }
|
||||||
.with_threshold(1)
|
.with_threshold(1)
|
||||||
.with_cool_off_time(5.minutes.seconds)
|
.with_cool_off_time(5.minutes.seconds)
|
||||||
.with_error_handler { |error, handle| error.is_a?(HTTP::Error) || error.is_a?(OpenSSL::SSL::SSLError) ? handle.call(error) : raise(error) }
|
.with_error_handler { |error, handle| error.is_a?(HTTP::Error) || error.is_a?(OpenSSL::SSL::SSLError) ? handle.call(error) : raise(error) }
|
||||||
.run
|
|
||||||
else
|
else
|
||||||
yield
|
Stoplight('domain-blank')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -62,13 +62,7 @@
|
||||||
%td
|
%td
|
||||||
%time.formatted{ datetime: account.created_at.iso8601, title: l(account.created_at) }= l account.created_at
|
%time.formatted{ datetime: account.created_at.iso8601, title: l(account.created_at) }= l account.created_at
|
||||||
%td
|
%td
|
||||||
- recent_ips = account.user.ips.order(used_at: :desc).to_a
|
= render partial: 'admin/accounts/user_ip', collection: account.user.ips.by_latest_used
|
||||||
- recent_ips.each_with_index do |recent_ip, i|
|
|
||||||
%tr
|
|
||||||
- if i.zero?
|
|
||||||
%th{ rowspan: recent_ips.size }= t('admin.accounts.most_recent_ip')
|
|
||||||
%td= recent_ip.ip
|
|
||||||
%td= table_link_to 'search', t('admin.accounts.search_same_ip'), admin_accounts_path(ip: recent_ip.ip)
|
|
||||||
%tr
|
%tr
|
||||||
%th= t('admin.accounts.most_recent_activity')
|
%th= t('admin.accounts.most_recent_activity')
|
||||||
%td
|
%td
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
%tr
|
||||||
|
- if user_ip_iteration.first?
|
||||||
|
%th{ rowspan: user_ip_iteration.size }= t('admin.accounts.most_recent_ip')
|
||||||
|
%td= user_ip.ip
|
||||||
|
%td= table_link_to 'search', t('admin.accounts.search_same_ip'), admin_accounts_path(ip: user_ip.ip)
|
|
@ -59,7 +59,7 @@ class ActivityPub::DeliveryWorker
|
||||||
end
|
end
|
||||||
|
|
||||||
def perform_request
|
def perform_request
|
||||||
light = Stoplight(@inbox_url) do
|
stoplight_wrapper.run do
|
||||||
request_pool.with(@host) do |http_client|
|
request_pool.with(@host) do |http_client|
|
||||||
build_request(http_client).perform do |response|
|
build_request(http_client).perform do |response|
|
||||||
raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response)
|
raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response)
|
||||||
|
@ -68,10 +68,12 @@ class ActivityPub::DeliveryWorker
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
light.with_threshold(STOPLIGHT_FAILURE_THRESHOLD)
|
def stoplight_wrapper
|
||||||
|
Stoplight(@inbox_url)
|
||||||
|
.with_threshold(STOPLIGHT_FAILURE_THRESHOLD)
|
||||||
.with_cool_off_time(STOPLIGHT_COOLDOWN)
|
.with_cool_off_time(STOPLIGHT_COOLDOWN)
|
||||||
.run
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def failure_tracker
|
def failure_tracker
|
||||||
|
|
|
@ -11,7 +11,7 @@ class Import::RelationshipWorker
|
||||||
def perform(account_id, target_account_uri, relationship, options)
|
def perform(account_id, target_account_uri, relationship, options)
|
||||||
from_account = Account.find(account_id)
|
from_account = Account.find(account_id)
|
||||||
target_domain = domain(target_account_uri)
|
target_domain = domain(target_account_uri)
|
||||||
target_account = stoplight_wrap_request(target_domain) { ResolveAccountService.new.call(target_account_uri, { check_delivery_availability: true }) }
|
target_account = stoplight_wrapper(target_domain).run { ResolveAccountService.new.call(target_account_uri, { check_delivery_availability: true }) }
|
||||||
options.symbolize_keys!
|
options.symbolize_keys!
|
||||||
|
|
||||||
return if target_account.nil?
|
return if target_account.nil?
|
||||||
|
@ -43,16 +43,15 @@ class Import::RelationshipWorker
|
||||||
TagManager.instance.local_domain?(domain) ? nil : TagManager.instance.normalize_domain(domain)
|
TagManager.instance.local_domain?(domain) ? nil : TagManager.instance.normalize_domain(domain)
|
||||||
end
|
end
|
||||||
|
|
||||||
def stoplight_wrap_request(domain, &block)
|
def stoplight_wrapper(domain)
|
||||||
if domain.present?
|
if domain.present?
|
||||||
Stoplight("source:#{domain}", &block)
|
Stoplight("source:#{domain}")
|
||||||
.with_fallback { nil }
|
.with_fallback { nil }
|
||||||
.with_threshold(1)
|
.with_threshold(1)
|
||||||
.with_cool_off_time(5.minutes.seconds)
|
.with_cool_off_time(5.minutes.seconds)
|
||||||
.with_error_handler { |error, handle| error.is_a?(HTTP::Error) || error.is_a?(OpenSSL::SSL::SSLError) ? handle.call(error) : raise(error) }
|
.with_error_handler { |error, handle| error.is_a?(HTTP::Error) || error.is_a?(OpenSSL::SSL::SSLError) ? handle.call(error) : raise(error) }
|
||||||
.run
|
|
||||||
else
|
else
|
||||||
yield
|
Stoplight('domain-blank')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,6 +3,6 @@
|
||||||
require 'stoplight'
|
require 'stoplight'
|
||||||
|
|
||||||
Rails.application.reloader.to_prepare do
|
Rails.application.reloader.to_prepare do
|
||||||
Stoplight::Light.default_data_store = Stoplight::DataStore::Redis.new(RedisConfiguration.new.connection)
|
Stoplight.default_data_store = Stoplight::DataStore::Redis.new(RedisConfiguration.new.connection)
|
||||||
Stoplight::Light.default_notifiers = [Stoplight::Notifier::Logger.new(Rails.logger)]
|
Stoplight.default_notifiers = [Stoplight::Notifier::Logger.new(Rails.logger)]
|
||||||
end
|
end
|
||||||
|
|
|
@ -84,13 +84,11 @@ module Paperclip
|
||||||
# Don't go through Stoplight if we don't have anything object-storage-oriented to do
|
# Don't go through Stoplight if we don't have anything object-storage-oriented to do
|
||||||
return super if @queued_for_delete.empty? && @queued_for_write.empty? && !dirty?
|
return super if @queued_for_delete.empty? && @queued_for_write.empty? && !dirty?
|
||||||
|
|
||||||
Stoplight('object-storage') { super }.with_threshold(STOPLIGHT_THRESHOLD).with_cool_off_time(STOPLIGHT_COOLDOWN).with_error_handler do |error, handle|
|
Stoplight('object-storage')
|
||||||
if error.is_a?(Seahorse::Client::NetworkingError)
|
.with_threshold(STOPLIGHT_THRESHOLD)
|
||||||
handle.call(error)
|
.with_cool_off_time(STOPLIGHT_COOLDOWN)
|
||||||
else
|
.with_error_handler { |error, handle| error.is_a?(Seahorse::Client::NetworkingError) ? handle.call(error) : raise(error) }
|
||||||
raise error
|
.run { super }
|
||||||
end
|
|
||||||
end.run
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,13 +22,15 @@ describe 'Public' do
|
||||||
get '/api/v1/timelines/public', headers: headers, params: params
|
get '/api/v1/timelines/public', headers: headers, params: params
|
||||||
end
|
end
|
||||||
|
|
||||||
let!(:private_status) { Fabricate(:status, visibility: :private) } # rubocop:disable RSpec/LetSetup
|
|
||||||
let!(:local_status) { Fabricate(:status, account: Fabricate.build(:account, domain: nil)) }
|
let!(:local_status) { Fabricate(:status, account: Fabricate.build(:account, domain: nil)) }
|
||||||
let!(:remote_status) { Fabricate(:status, account: Fabricate.build(:account, domain: 'example.com')) }
|
let!(:remote_status) { Fabricate(:status, account: Fabricate.build(:account, domain: 'example.com')) }
|
||||||
let!(:media_status) { Fabricate(:status, media_attachments: [Fabricate.build(:media_attachment)]) }
|
let!(:media_status) { Fabricate(:status, media_attachments: [Fabricate.build(:media_attachment)]) }
|
||||||
|
|
||||||
let(:params) { {} }
|
let(:params) { {} }
|
||||||
|
|
||||||
|
before do
|
||||||
|
Fabricate(:status, visibility: :private)
|
||||||
|
end
|
||||||
|
|
||||||
context 'when the instance allows public preview' do
|
context 'when the instance allows public preview' do
|
||||||
let(:expected_statuses) { [local_status, remote_status, media_status] }
|
let(:expected_statuses) { [local_status, remote_status, media_status] }
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ describe 'Instances' do
|
||||||
expect(body_as_json)
|
expect(body_as_json)
|
||||||
.to be_present
|
.to be_present
|
||||||
.and include(title: 'Mastodon Glitch Edition')
|
.and include(title: 'Mastodon Glitch Edition')
|
||||||
|
.and include_configuration_limits
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -31,7 +32,26 @@ describe 'Instances' do
|
||||||
expect(body_as_json)
|
expect(body_as_json)
|
||||||
.to be_present
|
.to be_present
|
||||||
.and include(title: 'Mastodon Glitch Edition')
|
.and include(title: 'Mastodon Glitch Edition')
|
||||||
|
.and include_configuration_limits
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def include_configuration_limits
|
||||||
|
include(
|
||||||
|
configuration: include(
|
||||||
|
accounts: include(
|
||||||
|
max_featured_tags: FeaturedTag::LIMIT,
|
||||||
|
max_pinned_statuses: StatusPinValidator::PIN_LIMIT
|
||||||
|
),
|
||||||
|
statuses: include(
|
||||||
|
max_characters: StatusLengthValidator::MAX_CHARS,
|
||||||
|
max_media_attachments: 4 # TODO, move to constant somewhere
|
||||||
|
),
|
||||||
|
polls: include(
|
||||||
|
max_options: PollValidator::MAX_OPTIONS
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,11 +10,22 @@ describe REST::InstanceSerializer do
|
||||||
it 'returns recent usage data' do
|
it 'returns recent usage data' do
|
||||||
expect(serialization['usage']).to eq({ 'users' => { 'active_month' => 0 } })
|
expect(serialization['usage']).to eq({ 'users' => { 'active_month' => 0 } })
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'configuration' do
|
||||||
it 'returns the VAPID public key' do
|
it 'returns the VAPID public key' do
|
||||||
expect(serialization['configuration']['vapid']).to eq({
|
expect(serialization['configuration']['vapid']).to eq({
|
||||||
'public_key' => Rails.configuration.x.vapid_public_key,
|
'public_key' => Rails.configuration.x.vapid_public_key,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'returns the max pinned statuses limit' do
|
||||||
|
expect(serialization.deep_symbolize_keys)
|
||||||
|
.to include(
|
||||||
|
configuration: include(
|
||||||
|
accounts: include(max_pinned_statuses: StatusPinValidator::PIN_LIMIT)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue