闭社主体 forked from https://github.com/tootsuite/mastodon
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.

83 lines
1.8 KiB

  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. request = Request.new(:post, subscription.callback_url, body: payload)
  26. request.add_headers(headers)
  27. request.perform
  28. end
  29. def blocked_domain?
  30. DomainBlock.blocked?(host)
  31. end
  32. def host
  33. Addressable::URI.parse(subscription.callback_url).normalized_host
  34. end
  35. def headers
  36. {
  37. 'Content-Type' => 'application/atom+xml',
  38. 'Link' => link_header,
  39. }.merge(signature_headers.to_h)
  40. end
  41. def link_header
  42. LinkHeader.new([hub_link_header, self_link_header]).to_s
  43. end
  44. def hub_link_header
  45. [api_push_url, [%w(rel hub)]]
  46. end
  47. def self_link_header
  48. [account_url(subscription.account, format: :atom), [%w(rel self)]]
  49. end
  50. def signature_headers
  51. { 'X-Hub-Signature' => payload_signature } if subscription.secret?
  52. end
  53. def payload_signature
  54. "sha1=#{hmac_payload_digest}"
  55. end
  56. def hmac_payload_digest
  57. OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), subscription.secret, payload)
  58. end
  59. def response_successful?
  60. payload_delivery.code > 199 && payload_delivery.code < 300
  61. end
  62. end