mirror of
https://github.com/mastodon/mastodon
synced 2024-12-22 10:38:14 +09:00
6b2be5dbfb
* Guarantee Subscription service first account has proper URL details Subscription Service potentially could break if the first user suspended themselves, creating a situation where the urls that populate throughout subscription service's PuSH request would cause the remote API to throw 503 errors. Guaranteeing that the first account picked is not suspended prevents this problem. * Fix style issue
58 lines
1.6 KiB
Ruby
58 lines
1.6 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class SubscribeService < BaseService
|
|
def call(account)
|
|
return if account.hub_url.blank?
|
|
|
|
@account = account
|
|
@account.secret = SecureRandom.hex
|
|
@response = build_request.perform
|
|
|
|
if response_failed_permanently?
|
|
# We're not allowed to subscribe. Fail and move on.
|
|
@account.secret = ''
|
|
@account.save!
|
|
elsif response_successful?
|
|
# The subscription will be confirmed asynchronously.
|
|
@account.save!
|
|
else
|
|
# The response was either a 429 rate limit, or a 5xx error.
|
|
# We need to retry at a later time. Fail loudly!
|
|
raise Mastodon::UnexpectedResponseError, @response
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def build_request
|
|
request = Request.new(:post, @account.hub_url, form: subscription_params)
|
|
request.on_behalf_of(some_local_account) if some_local_account
|
|
request
|
|
end
|
|
|
|
def subscription_params
|
|
{
|
|
'hub.topic': @account.remote_url,
|
|
'hub.mode': 'subscribe',
|
|
'hub.callback': api_subscription_url(@account.id),
|
|
'hub.verify': 'async',
|
|
'hub.secret': @account.secret,
|
|
'hub.lease_seconds': 7.days.seconds,
|
|
}
|
|
end
|
|
|
|
def some_local_account
|
|
@some_local_account ||= Account.local.where(suspended: false).first
|
|
end
|
|
|
|
# Any response in the 3xx or 4xx range, except for 429 (rate limit)
|
|
def response_failed_permanently?
|
|
(@response.status.redirect? || @response.status.client_error?) && !@response.status.too_many_requests?
|
|
end
|
|
|
|
# Any response in the 2xx range
|
|
def response_successful?
|
|
@response.status.success?
|
|
end
|
|
end
|