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.

57 lines
1.6 KiB

  1. # frozen_string_literal: true
  2. class SubscribeService < BaseService
  3. def call(account)
  4. return unless account.ostatus?
  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 "Subscription attempt failed for #{@account.acct} (#{@account.hub_url}): HTTP #{@response.code}"
  19. end
  20. end
  21. private
  22. def build_request
  23. request = Request.new(:post, @account.hub_url, form: subscription_params)
  24. request.on_behalf_of(some_local_account) if some_local_account
  25. request
  26. end
  27. def subscription_params
  28. {
  29. 'hub.topic': @account.remote_url,
  30. 'hub.mode': 'subscribe',
  31. 'hub.callback': api_subscription_url(@account.id),
  32. 'hub.verify': 'async',
  33. 'hub.secret': @account.secret,
  34. 'hub.lease_seconds': 7.days.seconds,
  35. }
  36. end
  37. def some_local_account
  38. @some_local_account ||= Account.local.first
  39. end
  40. # Any response in the 3xx or 4xx range, except for 429 (rate limit)
  41. def response_failed_permanently?
  42. (@response.status.redirect? || @response.status.client_error?) && !@response.status.too_many_requests?
  43. end
  44. # Any response in the 2xx range
  45. def response_successful?
  46. @response.status.success?
  47. end
  48. end