# frozen_string_literal: true class Pubsubhubbub::ConfirmationWorker include Sidekiq::Worker include RoutingHelper sidekiq_options queue: 'push', retry: false attr_reader :subscription, :mode, :secret, :lease_seconds def perform(subscription_id, mode, secret = nil, lease_seconds = nil) @subscription = Subscription.find(subscription_id) @mode = mode @secret = secret @lease_seconds = lease_seconds process_confirmation end private def process_confirmation prepare_subscription confirm_callback logger.debug "Confirming PuSH subscription for #{subscription.callback_url} with challenge #{challenge}: #{callback_response_body}" update_subscription end def update_subscription if successful_subscribe? subscription.save! elsif successful_unsubscribe? subscription.destroy! end end def successful_subscribe? subscribing? && response_matches_challenge? end def successful_unsubscribe? (unsubscribing? && response_matches_challenge?) || !subscription.confirmed? end def response_matches_challenge? callback_response_body == challenge end def subscribing? mode == 'subscribe' end def unsubscribing? mode == 'unsubscribe' end def confirm_callback @_confirm_callback ||= callback_get_with_params end def callback_get_with_params HTTP.headers(user_agent: 'Mastodon/PubSubHubbub') .timeout(:per_operation, write: 20, connect: 20, read: 50) .get(subscription.callback_url, params: callback_params) end def callback_response_body confirm_callback.body.to_s end def callback_params { 'hub.topic' => account_url(subscription.account, format: :atom), 'hub.mode' => mode, 'hub.challenge' => challenge, 'hub.lease_seconds' => subscription.lease_seconds, } end def prepare_subscription subscription.secret = secret subscription.lease_seconds = lease_seconds subscription.confirmed = true end def challenge @_challenge ||= SecureRandom.hex end end