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

90 lines
2.0 KiB

  1. # frozen_string_literal: true
  2. class Pubsubhubbub::ConfirmationWorker
  3. include Sidekiq::Worker
  4. include RoutingHelper
  5. sidekiq_options queue: 'push', retry: false
  6. attr_reader :subscription, :mode, :secret, :lease_seconds
  7. def perform(subscription_id, mode, secret = nil, lease_seconds = nil)
  8. @subscription = Subscription.find(subscription_id)
  9. @mode = mode
  10. @secret = secret
  11. @lease_seconds = lease_seconds
  12. process_confirmation
  13. end
  14. private
  15. def process_confirmation
  16. prepare_subscription
  17. confirm_callback
  18. logger.debug "Confirming PuSH subscription for #{subscription.callback_url} with challenge #{challenge}: #{callback_response_body}"
  19. update_subscription
  20. end
  21. def update_subscription
  22. if successful_subscribe?
  23. subscription.save!
  24. elsif successful_unsubscribe?
  25. subscription.destroy!
  26. end
  27. end
  28. def successful_subscribe?
  29. subscribing? && response_matches_challenge?
  30. end
  31. def successful_unsubscribe?
  32. (unsubscribing? && response_matches_challenge?) || !subscription.confirmed?
  33. end
  34. def response_matches_challenge?
  35. callback_response_body == challenge
  36. end
  37. def subscribing?
  38. mode == 'subscribe'
  39. end
  40. def unsubscribing?
  41. mode == 'unsubscribe'
  42. end
  43. def confirm_callback
  44. @_confirm_callback ||= callback_get_with_params
  45. end
  46. def callback_get_with_params
  47. HTTP.headers(user_agent: 'Mastodon/PubSubHubbub')
  48. .timeout(:per_operation, write: 20, connect: 20, read: 50)
  49. .get(subscription.callback_url, params: callback_params)
  50. end
  51. def callback_response_body
  52. confirm_callback.body.to_s
  53. end
  54. def callback_params
  55. {
  56. 'hub.topic' => account_url(subscription.account, format: :atom),
  57. 'hub.mode' => mode,
  58. 'hub.challenge' => challenge,
  59. 'hub.lease_seconds' => subscription.lease_seconds,
  60. }
  61. end
  62. def prepare_subscription
  63. subscription.secret = secret
  64. subscription.lease_seconds = lease_seconds
  65. subscription.confirmed = true
  66. end
  67. def challenge
  68. @_challenge ||= SecureRandom.hex
  69. end
  70. end