You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

58 lines
1.6 KiB

  1. # frozen_string_literal: true
  2. class SubscribeService < BaseService
  3. def call(account)
  4. return if account.hub_url.blank?
  5. @account = account
  6. @account.secret = SecureRandom.hex
  7. @response = build_request.perform
  8. if response_failed_permanently?
  9. # We're not allowed to subscribe. Fail and move on.
  10. @account.secret = ''
  11. @account.save!
  12. elsif response_successful?
  13. # The subscription will be confirmed asynchronously.
  14. @account.save!
  15. else
  16. # The response was either a 429 rate limit, or a 5xx error.
  17. # We need to retry at a later time. Fail loudly!
  18. raise Mastodon::UnexpectedResponseError, @response
  19. end
  20. @response.connection&.close
  21. end
  22. private
  23. def build_request
  24. request = Request.new(:post, @account.hub_url, form: subscription_params)
  25. request.on_behalf_of(some_local_account) if some_local_account
  26. request
  27. end
  28. def subscription_params
  29. {
  30. 'hub.topic': @account.remote_url,
  31. 'hub.mode': 'subscribe',
  32. 'hub.callback': api_subscription_url(@account.id),
  33. 'hub.verify': 'async',
  34. 'hub.secret': @account.secret,
  35. 'hub.lease_seconds': 7.days.seconds,
  36. }
  37. end
  38. def some_local_account
  39. @some_local_account ||= Account.local.where(suspended: false).first
  40. end
  41. # Any response in the 3xx or 4xx range, except for 429 (rate limit)
  42. def response_failed_permanently?
  43. (@response.status.redirect? || @response.status.client_error?) && !@response.status.too_many_requests?
  44. end
  45. # Any response in the 2xx range
  46. def response_successful?
  47. @response.status.success?
  48. end
  49. end