diff --git a/plugins/OStatus/actions/feedsubsettings.php b/plugins/OStatus/actions/feedsubsettings.php index af8bf4d25e..6933c9bf21 100644 --- a/plugins/OStatus/actions/feedsubsettings.php +++ b/plugins/OStatus/actions/feedsubsettings.php @@ -197,6 +197,9 @@ class FeedSubSettingsAction extends ConnectSettingsAction if ($this->validateFeed()) { $this->preview = true; $this->profile = Ostatus_profile::ensureProfile($this->munger); + if (!$this->profile) { + throw new ServerException("Feed profile was not saved properly."); + } // If not already in use, subscribe to updates via the hub if ($this->profile->sub_start) { @@ -212,13 +215,10 @@ class FeedSubSettingsAction extends ConnectSettingsAction // And subscribe the current user to the local profile $user = common_current_user(); - $profile = $this->profile->getLocalProfile(); - if (!$profile) { - throw new ServerException("Feed profile was not saved properly."); - } if ($this->profile->isGroup()) { - if ($user->isMember($profile)) { + $group = $this->profile->localGroup(); + if ($user->isMember($group)) { $this->showForm(_m('Already a member!')); } elseif (Group_member::join($this->profile->group_id, $user->id)) { $this->showForm(_m('Joined remote group!')); @@ -226,9 +226,10 @@ class FeedSubSettingsAction extends ConnectSettingsAction $this->showForm(_m('Remote group join failed!')); } } else { - if ($user->isSubscribed($profile)) { + $local = $this->profile->localProfile(); + if ($user->isSubscribed($local)) { $this->showForm(_m('Already subscribed!')); - } elseif ($user->subscribeTo($profile)) { + } elseif ($user->subscribeTo($local)) { $this->showForm(_m('Feed subscribed!')); } else { $this->showForm(_m('Feed subscription failed!')); diff --git a/plugins/OStatus/actions/pushcallback.php b/plugins/OStatus/actions/pushcallback.php index a446593ff9..2601a377a0 100644 --- a/plugins/OStatus/actions/pushcallback.php +++ b/plugins/OStatus/actions/pushcallback.php @@ -84,27 +84,24 @@ class PushCallbackAction extends Action throw new ServerException("Bogus hub callback: unknown feed", 404); } - # Can't currently set the token in our sub api - #if ($feedinfo->verify_token !== $verify_token) { - # common_log(LOG_WARNING, __METHOD__ . ": bogus hub callback with bad token \"$verify_token\" for feed $topic"); - # throw new ServerError("Bogus hub callback: bad token", 404); - #} - + if ($profile->verify_token !== $verify_token) { + common_log(LOG_WARNING, __METHOD__ . ": bogus hub callback with bad token \"$verify_token\" for feed $topic"); + throw new ServerError("Bogus hub callback: bad token", 404); + } + + if ($mode != $profile->sub_state) { + common_log(LOG_WARNING, __METHOD__ . ": bogus hub callback with bad mode \"$mode\" for feed $topic in state \"{$profile->sub_state}\""); + throw new ServerException("Bogus hub callback: mode doesn't match subscription state.", 404); + } + // OK! if ($mode == 'subscribe') { common_log(LOG_INFO, __METHOD__ . ': sub confirmed'); - $profile->sub_start = common_sql_date(time()); - if ($lease_seconds > 0) { - $profile->sub_end = common_sql_date(time() + $lease_seconds); - } else { - $profile->sub_end = null; - } - $profile->update(); + $profile->confirmSubscribe($lease_seconds); } else { common_log(LOG_INFO, __METHOD__ . ": unsub confirmed; deleting sub record for $topic"); - $profile->delete(); + $profile->confirmUnsubscribe(); } - print $challenge; } } diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 748ecce18f..f7bbcd0286 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -182,9 +182,24 @@ class Ostatus_profile extends Memcached_DataObject * Fetch the StatusNet-side profile for this feed * @return Profile */ - public function getLocalProfile() + public function localProfile() { - return Profile::staticGet('id', $this->profile_id); + if ($this->profile_id) { + return Profile::staticGet('id', $this->profile_id); + } + return null; + } + + /** + * Fetch the StatusNet-side profile for this feed + * @return Profile + */ + public function localGroup() + { + if ($this->group_id) { + return User_group::staticGet('id', $this->group_id); + } + return null; } /** @@ -194,73 +209,96 @@ class Ostatus_profile extends Memcached_DataObject */ public static function ensureProfile($munger) { - $entity = $munger->ostatusProfile(); + $profile = $munger->ostatusProfile(); - $current = self::staticGet('feeduri', $entity->feeduri); + $current = self::staticGet('feeduri', $profile->feeduri); if ($current) { // @fixme we should probably update info as necessary return $current; } - $entity->query('BEGIN'); + $profile->query('BEGIN'); // Awful hack! Awful hack! - $entity->verify = common_good_rand(16); - $entity->secret = common_good_rand(32); + $profile->verify = common_good_rand(16); + $profile->secret = common_good_rand(32); try { - $profile = $munger->profile(); + $local = $munger->profile(); + + if ($entity->isGroup()) { + $group = new User_group(); + $group->nickname = $local->nickname . '@remote'; // @fixme + $group->fullname = $local->fullname; + $group->homepage = $local->homepage; + $group->location = $local->location; + $group->created = $local->created; + $group->insert(); + if (empty($result)) { + throw new FeedDBException($group); + } + $profile->group_id = $group->id; + } else { + $result = $local->insert(); + if (empty($result)) { + throw new FeedDBException($local); + } + $profile->profile_id = $local->id; + } + + $profile->created = sql_common_date(); + $profile->lastupdate = sql_common_date(); $result = $profile->insert(); if (empty($result)) { throw new FeedDBException($profile); } - $avatar = $munger->getAvatar(); - if ($avatar) { - // @fixme this should be better encapsulated - // ripped from oauthstore.php (for old OMB client) - $temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar'); - copy($avatar, $temp_filename); - $imagefile = new ImageFile($profile->id, $temp_filename); - $filename = Avatar::filename($profile->id, - image_type_to_extension($imagefile->type), - null, - common_timestamp()); - rename($temp_filename, Avatar::path($filename)); - $profile->setOriginal($filename); - } - - $entity->profile_id = $profile->id; - if ($entity->isGroup()) { - $group = new User_group(); - $group->nickname = $profile->nickname . '@remote'; // @fixme - $group->fullname = $profile->fullname; - $group->homepage = $profile->homepage; - $group->location = $profile->location; - $group->created = $profile->created; - $group->insert(); - - if ($avatar) { - $group->setOriginal($filename); - } - - $entity->group_id = $group->id; - } - - $result = $entity->insert(); - if (empty($result)) { - throw new FeedDBException($entity); - } - $entity->query('COMMIT'); } catch (FeedDBException $e) { common_log_db_error($e->obj, 'INSERT', __FILE__); $entity->query('ROLLBACK'); return false; } + + $avatar = $munger->getAvatar(); + if ($avatar) { + try { + $this->updateAvatar($avatar); + } catch (Exception $e) { + common_log(LOG_ERR, "Exception setting OStatus avatar: " . + $e->getMessage()); + } + } + return $entity; } + /** + * Download and update given avatar image + * @param string $url + * @throws Exception in various failure cases + */ + public function updateAvatar($url) + { + // @fixme this should be better encapsulated + // ripped from oauthstore.php (for old OMB client) + $temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar'); + copy($url, $temp_filename); + $imagefile = new ImageFile($profile->id, $temp_filename); + $filename = Avatar::filename($profile->id, + image_type_to_extension($imagefile->type), + null, + common_timestamp()); + rename($temp_filename, Avatar::path($filename)); + if ($this->isGroup()) { + $group = $this->localGroup(); + $group->setOriginal($filename); + } else { + $profile = $this->localProfile(); + $profile->setOriginal($filename); + } + } + /** * Damn dirty hack! */ @@ -318,6 +356,46 @@ class Ostatus_profile extends Memcached_DataObject } } + /** + * Save PuSH subscription confirmation. + * Sets approximate lease start and end times and finalizes state. + * + * @param int $lease_seconds provided hub.lease_seconds parameter, if given + */ + public function confirmSubscribe($lease_seconds=0) + { + $original = clone($this); + + $this->sub_state = 'active'; + $this->sub_start = common_sql_date(time()); + if ($lease_seconds > 0) { + $this->sub_end = common_sql_date(time() + $lease_seconds); + } else { + $this->sub_end = null; + } + $this->lastupdate = common_sql_date(); + + return $this->update($original); + } + + /** + * Save PuSH unsubscription confirmation. + * Wipes active PuSH sub info and resets state. + */ + public function confirmUnsubscribe() + { + $original = clone($this); + + $this->verify_token = null; + $this->secret = null; + $this->sub_state = null; + $this->sub_start = null; + $this->sub_end = null; + $this->lastupdate = common_sql_date(); + + return $this->update($original); + } + /** * Send an unsubscription request to the hub for this feed. * The hub will later send us a confirmation POST to /main/push/callback.