闭社主体 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.

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