From 273fe3cf5b216f1365d9db3f61a76413e95f1353 Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Fri, 20 Mar 2015 09:51:23 -0700 Subject: [PATCH] push subscriptions --- composer.json | 1 + composer.lock | 12 ++++---- controllers/push.php | 73 +++++++++++++++++++++++++------------------- lib/DeferredTask.php | 6 ++-- lib/PushTask.php | 57 ++++++++++++++++++++++++++++++++++ lib/db_helpers.php | 7 +++++ scripts/run.php | 31 +++++++++++++++++++ 7 files changed, 147 insertions(+), 40 deletions(-) create mode 100644 lib/PushTask.php create mode 100644 scripts/run.php diff --git a/composer.json b/composer.json index a0aa5e7..48c1474 100644 --- a/composer.json +++ b/composer.json @@ -18,6 +18,7 @@ "lib/db_helpers.php", "lib/mf2_feed_parser.php", "lib/DeferredTask.php", + "lib/PushTask.php", "lib/request.php" ] } diff --git a/composer.lock b/composer.lock index 1a9a168..345000d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "e97be02376b6b07beab7c771b815ca64", + "hash": "56d03ce1ea73dfa3bd0f68bf4a987844", "packages": [ { "name": "barnabywalters/mf-cleaner", @@ -48,16 +48,16 @@ }, { "name": "indieauth/client", - "version": "0.1.8", + "version": "0.1.9", "source": { "type": "git", "url": "https://github.com/indieweb/indieauth-client-php.git", - "reference": "f979f8ee0fc6daaa6a393e7afdac894000d09544" + "reference": "6f9303cb79de7f650018cb8a317798bd4bfc2fb9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/indieweb/indieauth-client-php/zipball/f979f8ee0fc6daaa6a393e7afdac894000d09544", - "reference": "f979f8ee0fc6daaa6a393e7afdac894000d09544", + "url": "https://api.github.com/repos/indieweb/indieauth-client-php/zipball/6f9303cb79de7f650018cb8a317798bd4bfc2fb9", + "reference": "6f9303cb79de7f650018cb8a317798bd4bfc2fb9", "shasum": "" }, "require": { @@ -83,7 +83,7 @@ } ], "description": "IndieAuth Client Library", - "time": "2014-10-06 07:37:10" + "time": "2015-03-18 20:00:10" }, { "name": "indieweb/link-rel-parser", diff --git a/controllers/push.php b/controllers/push.php index 3ef80b4..d00d08f 100644 --- a/controllers/push.php +++ b/controllers/push.php @@ -6,6 +6,21 @@ function push_error(&$app, $msg) { die(); } +/////////////////////////////////////////////////////////////// +// These are just test routes +$app->get('/callback-success', function() use($app) { + $params = $app->request()->params(); + $app->response()->status(200); + echo $params['hub_challenge']; +}); + +$app->get('/callback-fail', function() use($app) { + $params = $app->request()->params(); + $app->response()->status(404); +}); +/////////////////////////////////////////////////////////////// + + $app->post('/', function() use($app) { $params = $app->request()->params(); @@ -24,41 +39,37 @@ $app->post('/', function() use($app) { push_error($app, 'Callback URL was invalid'); } - // Make a HEAD request to the topic URL to check if it exists - $topic_head = request\get_head($topic); - if($topic_head) { - if(request\response_is($topic_head['status'], 2)) { - $app->response()->status(202); - - // Find or create the feed given the topic URL - $feed = db\find_or_create('feeds', ['feed_url'=>$topic], [ - 'hash' => db\random_hash(), - ], true); - - print_r($feed); - - // 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(), - ]); - $subscription->date_requested = db\now(); - $subscription->challenge = db\random_hash(); - $subscription->save(); - - - - - - echo "The subscription request is being validated. Check the status here:\n"; - echo Config::$base_url . '/subscription/' . $subscription->hash . "\n"; + // 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 { - $app->response()->status(400); - echo "The topic URL returned a " . $topic_head['status'] . " status code\n"; + push_error($app, 'We tried to verify the topic URL exists but it didn\'t respond to a HEAD request.'); } - } else { - push_error($app, 'There was a problem trying to verify the topic URL'); } + // 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); + + $app->response()->status(202); + echo "The subscription request is being validated. Check the status here:\n"; + echo Config::$base_url . '/subscription/' . $subscription->hash . "\n"; + break; case 'unsubscribe': diff --git a/lib/DeferredTask.php b/lib/DeferredTask.php index a188ebf..aaa300e 100644 --- a/lib/DeferredTask.php +++ b/lib/DeferredTask.php @@ -5,7 +5,7 @@ class DeferredTask { public static function run() { global $pcntl_continue; - $tube = 'monocle-worker'; + $tube = 'switchboard-worker'; echo "PID " . posix_getpid() . " watching tube: " . $tube . "\n"; bs()->watch($tube)->ignore('default'); @@ -29,7 +29,7 @@ class DeferredTask { } public static function run_once() { - $tube = 'monocle-worker'; + $tube = 'switchboard-worker'; echo "PID " . posix_getpid() . " watching tube: " . $tube . "\n"; bs()->watch($tube)->ignore('default'); @@ -44,7 +44,7 @@ class DeferredTask { if(!is_array($args)) $args = array($args); - bs()->putInTube('monocle-worker', + bs()->putInTube('switchboard-worker', json_encode(array('class'=>$class, 'method'=>$method, 'args'=>$args)), 1024, // priority $delay, // delay diff --git a/lib/PushTask.php b/lib/PushTask.php new file mode 100644 index 0000000..d422730 --- /dev/null +++ b/lib/PushTask.php @@ -0,0 +1,57 @@ +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.topic' => $feed->feed_url, + 'hub.challenge' => $subscription->challenge, + 'hub.lease_seconds' => $lease_seconds + ]; + + 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); + + 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; + $subscription->save(); + + } else { + // The subscriber did not confirm the subscription, so reject it + + } + + print_r($response); + + } + + } + +} diff --git a/lib/db_helpers.php b/lib/db_helpers.php index 6797cd9..6af6631 100644 --- a/lib/db_helpers.php +++ b/lib/db_helpers.php @@ -41,3 +41,10 @@ function find_or_create($table, $where, $defaults, $autosave=false) { return $item; } +function feed_from_url($url) { + return ORM::for_table('feeds')->where('feed_url', $url)->find_one(); +} + +function get_by_id($table, $id) { + return ORM::for_table($table)->where('id', $id)->find_one(); +} diff --git a/scripts/run.php b/scripts/run.php new file mode 100644 index 0000000..5d30182 --- /dev/null +++ b/scripts/run.php @@ -0,0 +1,31 @@ +