From 1a698cf9eeaca5a910c6ff2ff55985449334179a Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Mon, 23 Mar 2015 08:21:57 +0000 Subject: [PATCH] support unsubscribing --- controllers/push.php | 64 +++++++++++++++++++++++++++----------------- lib/PushTask.php | 38 +++++++++++++++----------- lib/db_helpers.php | 11 ++++++++ 3 files changed, 74 insertions(+), 39 deletions(-) diff --git a/controllers/push.php b/controllers/push.php index d00d08f..32ff264 100644 --- a/controllers/push.php +++ b/controllers/push.php @@ -24,8 +24,9 @@ $app->get('/callback-fail', function() use($app) { $app->post('/', function() use($app) { $params = $app->request()->params(); - switch(k($params, 'hub_mode')) { + switch($mode=k($params, 'hub_mode')) { case 'subscribe': + case 'unsubscribe': // Sanity check the request params $topic = k($params, 'hub_topic'); @@ -39,32 +40,48 @@ $app->post('/', function() use($app) { push_error($app, 'Callback URL was invalid'); } - // If we've already seen the topic, assume it's valid and don't check it again - if(!db\feed_from_url($topic)) { - $topic_head = request\get_head($topic); - if($topic_head && !request\response_is($topic_head['status'], 2)) { - push_error($app, "The topic URL returned a " . $topic_head['status'] . " status code"); - } else { - push_error($app, 'We tried to verify the topic URL exists but it didn\'t respond to a HEAD request.'); + if($mode == 'subscribe') { + // If we've already seen the topic, assume it's valid and don't check it again + if(!db\feed_from_url($topic)) { + $topic_head = request\get_head($topic); + if($topic_head && !request\response_is($topic_head['status'], 2)) { + push_error($app, "The topic URL returned a " . $topic_head['status'] . " status code"); + } else { + push_error($app, 'We tried to verify the topic URL exists but it didn\'t respond to a HEAD request.'); + } } - } - // Find or create the feed given the topic URL - $feed = db\find_or_create('feeds', ['feed_url'=>$topic], [ - 'hash' => db\random_hash(), - ], true); + // Find or create the feed given the topic URL + $feed = db\find_or_create('feeds', ['feed_url'=>$topic], [ + 'hash' => db\random_hash(), + ], true); + + // Find or create the subscription for this callback URL and feed + $subscription = db\find_or_create('subscriptions', ['feed_id'=>$feed->id, 'callback_url'=>$callback], [ + 'hash' => db\random_hash() + ], true); + // Always set a new requested date and challenge + $subscription->date_requested = db\now(); + $subscription->challenge = db\random_hash(); + $subscription->save(); + + // Queue the worker to validate the subscription + DeferredTask::queue('PushTask', 'verify_subscription', [$subscription->id, 'subscribe']); + + } else { + $feed = db\feed_from_url($topic); + if(!$feed) { + push_error($app, 'The topic was not found, so there is no subscription active'); + } - // Find or create the subscription for this callback URL and feed - $subscription = db\find_or_create('subscriptions', ['feed_id'=>$feed->id, 'callback_url'=>$callback], [ - 'hash' => db\random_hash() - ], true); - // Always set a new requested date and challenge - $subscription->date_requested = db\now(); - $subscription->challenge = db\random_hash(); - $subscription->save(); + $subscription = db\find('subscriptions', ['feed_id'=>$feed->id, 'callback_url'=>$callback]); + if(!$subscription) { + push_error($app, 'There was no subscription found for this callback URL and topic'); + } - // Queue the worker to validate the subscription - DeferredTask::queue('PushTask', 'verify_subscription', $subscription->id); + // Queue the worker to validate the subscription + DeferredTask::queue('PushTask', 'verify_subscription', [$subscription->id, 'unsubscribe']); + } $app->response()->status(202); echo "The subscription request is being validated. Check the status here:\n"; @@ -72,7 +89,6 @@ $app->post('/', function() use($app) { break; - case 'unsubscribe': break; } diff --git a/lib/PushTask.php b/lib/PushTask.php index 05c138a..74afa31 100644 --- a/lib/PushTask.php +++ b/lib/PushTask.php @@ -3,32 +3,32 @@ use BarnabyWalters\Mf2; class PushTask { - public static function verify_subscription($subscription_id) { + public static function verify_subscription($subscription_id, $mode) { $subscription = db\get_by_id('subscriptions', $subscription_id); if($subscription) { $feed = db\get_by_id('feeds', $subscription->feed_id); - $url = parse_url($subscription->callback_url); - // Choose the expiration for the subscription $lease_seconds = 86400*3; $exp_ts = time() + $lease_seconds; $exp_date = date('Y-m-d H:i:s', $exp_ts); $push_params = [ - 'hub.mode' => 'subscribe', + 'hub.mode' => ($mode == 'subscribe' ? 'subscribe' : 'unsubscribe'), 'hub.topic' => $feed->feed_url, - 'hub.challenge' => $subscription->challenge, - 'hub.lease_seconds' => $lease_seconds + 'hub.challenge' => $subscription->challenge ]; + if($mode == 'subscribe') { + $push_params['hub.lease_seconds'] = $lease_seconds; + } + $url = parse_url($subscription->callback_url); if($q=k($url, 'query')) { parse_str($q, $existing_params); $push_params = array_merge($push_params, $existing_params); } $url['query'] = http_build_query($push_params); - $url = build_url($url); $response = request\get_url($url, true); @@ -37,22 +37,30 @@ class PushTask { if(request\response_is($response['status'], 2) && $response['body'] == $subscription->challenge) { // The subscriber replied with a 2xx status code and confirmed the challenge string. - // The subscription is confirmed and active. - $subscription->date_confirmed = db\now(); - $subscription->lease_seconds = $lease_seconds; - $subscription->date_expires = $exp_date; - db\set_updated($subscription); - $subscription->active = 1; + + if($mode == 'subscribe') { + // The subscription is confirmed and active. + $subscription->date_confirmed = db\now(); + $subscription->lease_seconds = $lease_seconds; + $subscription->date_expires = $exp_date; + $subscription->active = 1; + echo "Subscriber verified the request and is now subscribed\n"; + } else { + $subscription->date_unsubscribed = db\now(); + $subscription->active = 0; + echo "Subscriber verified the request and is now unsubscribed\n"; + } } else { - // The subscriber did not confirm the subscription, so reject it + // The subscriber did not confirm the subscription, so reject the request + echo "Subscriber did not echo the challenge\n"; } + db\set_updated($subscription); $subscription->save(); print_r($response); - } } diff --git a/lib/db_helpers.php b/lib/db_helpers.php index c72ba70..cb60daa 100644 --- a/lib/db_helpers.php +++ b/lib/db_helpers.php @@ -41,6 +41,17 @@ function find_or_create($table, $where, $defaults, $autosave=false) { return $item; } +function find($table, $where) { + $item = ORM::for_table($table); + + // Where is an associative array of key/val combos + foreach($where as $c=>$v) { + $item = $item->where($c, $v); + } + + return $item->find_one(); +} + function feed_from_url($url) { return ORM::for_table('feeds')->where('feed_url', $url)->find_one(); }