delivery_worker.rb 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  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. end
  15. private
  16. def process_delivery
  17. payload_delivery
  18. raise "Delivery failed for #{subscription.callback_url}: HTTP #{payload_delivery.code}" unless response_successful?
  19. subscription.touch(:last_successful_delivery_at)
  20. end
  21. def payload_delivery
  22. @_payload_delivery ||= callback_post_payload
  23. end
  24. def callback_post_payload
  25. HTTP.timeout(:per_operation, write: 50, connect: 20, read: 50)
  26. .headers(headers)
  27. .post(subscription.callback_url, body: payload)
  28. end
  29. def blocked_domain?
  30. DomainBlock.blocked?(host)
  31. end
  32. def host
  33. Addressable::URI.parse(subscription.callback_url).normalize.host
  34. end
  35. def headers
  36. {
  37. 'User-Agent' => 'Mastodon/PubSubHubbub',
  38. 'Content-Type' => 'application/atom+xml',
  39. 'Link' => link_headers,
  40. }.merge(signature_headers.to_h)
  41. end
  42. def link_headers
  43. LinkHeader.new([hub_link_header, self_link_header]).to_s
  44. end
  45. def hub_link_header
  46. [api_push_url, [%w(rel hub)]]
  47. end
  48. def self_link_header
  49. [account_url(subscription.account, format: :atom), [%w(rel self)]]
  50. end
  51. def signature_headers
  52. { 'X-Hub-Signature' => payload_signature } if subscription.secret?
  53. end
  54. def payload_signature
  55. "sha1=#{hmac_payload_digest}"
  56. end
  57. def hmac_payload_digest
  58. OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), subscription.secret, payload)
  59. end
  60. def response_successful?
  61. payload_delivery.code > 199 && payload_delivery.code < 300
  62. end
  63. end