delivery_worker.rb 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. # frozen_string_literal: true
  2. class Pubsubhubbub::DeliveryWorker
  3. include Sidekiq::Worker
  4. include RoutingHelper
  5. sidekiq_options queue: 'push', retry: 3, dead: false
  6. sidekiq_retry_in do |count|
  7. 5 * (count + 1)
  8. end
  9. attr_reader :subscription, :payload
  10. def perform(subscription_id, payload)
  11. @subscription = Subscription.find(subscription_id)
  12. @payload = payload
  13. process_delivery unless blocked_domain?
  14. rescue => e
  15. raise e.class, "Delivery failed for #{subscription&.callback_url}: #{e.message}"
  16. end
  17. private
  18. def process_delivery
  19. payload_delivery
  20. raise Mastodon::UnexpectedResponseError, payload_delivery unless response_successful?
  21. subscription.touch(:last_successful_delivery_at)
  22. end
  23. def payload_delivery
  24. @_payload_delivery ||= callback_post_payload
  25. end
  26. def callback_post_payload
  27. request = Request.new(:post, subscription.callback_url, body: payload)
  28. request.add_headers(headers)
  29. request.perform
  30. end
  31. def blocked_domain?
  32. DomainBlock.blocked?(host)
  33. end
  34. def host
  35. Addressable::URI.parse(subscription.callback_url).normalized_host
  36. end
  37. def headers
  38. {
  39. 'Content-Type' => 'application/atom+xml',
  40. 'Link' => link_header,
  41. }.merge(signature_headers.to_h)
  42. end
  43. def link_header
  44. LinkHeader.new([hub_link_header, self_link_header]).to_s
  45. end
  46. def hub_link_header
  47. [api_push_url, [%w(rel hub)]]
  48. end
  49. def self_link_header
  50. [account_url(subscription.account, format: :atom), [%w(rel self)]]
  51. end
  52. def signature_headers
  53. { 'X-Hub-Signature' => payload_signature } if subscription.secret?
  54. end
  55. def payload_signature
  56. "sha1=#{hmac_payload_digest}"
  57. end
  58. def hmac_payload_digest
  59. OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), subscription.secret, payload)
  60. end
  61. def response_successful?
  62. payload_delivery.code > 199 && payload_delivery.code < 300
  63. end
  64. end