/** * Sign and post the given Atom entry as a Salmon message. * * Side effects: may generate a keypair on-demand for the given user, * which can be very slow on some systems (like those without php5-gmp). * * @param string $endpoint_uri * @param string $xml string representation of payload * @param Profile $user profile whose keys we sign with (must be a local user) * @return boolean success */ public static function post($endpoint_uri, $xml, Profile $actor, Profile $target = null) { if (empty($endpoint_uri)) { common_debug('No endpoint URI for Salmon post to ' . $actor->getUri()); return false; } try { $magic_env = MagicEnvelope::signAsUser($xml, $actor->getUser()); } catch (Exception $e) { common_log(LOG_ERR, "Salmon unable to sign: " . $e->getMessage()); return false; } // $target is so far only used in Diaspora, so it can be null if (Event::handle('SalmonSlap', array($endpoint_uri, $magic_env, $target))) { return false; //throw new ServerException('Could not distribute salmon slap as no plugin completed the event.'); } return true; }
/** * Get the Salmon keypair from a URI, uses XRD Discovery etc. Reasonably * you'll only get the public key ;) * * The string will (hopefully) be formatted as described in Magicsig specification: * https://salmon-protocol.googlecode.com/svn/trunk/draft-panzer-magicsig-01.html#anchor13 * * @return string formatted as Magicsig keypair */ public function discoverKeyPair(Profile $profile) { $signer_uri = $profile->getUri(); if (empty($signer_uri)) { throw new ServerException(sprintf('Profile missing URI (id==%d)', $profile->id)); } $disco = new Discovery(); // Throws exception on lookup problems $xrd = $disco->lookup($signer_uri); $link = $xrd->get(Magicsig::PUBLICKEYREL); if (is_null($link)) { // TRANS: Exception. throw new Exception(_m('Unable to locate signer public key.')); } // We have a public key element, let's hope it has proper key data. $keypair = false; $parts = explode(',', $link->href); if (count($parts) == 2) { $keypair = $parts[1]; } else { // Backwards compatibility check for separator bug in 0.9.0 $parts = explode(';', $link->href); if (count($parts) == 2) { $keypair = $parts[1]; } } if ($keypair === false) { // For debugging clarity. Keypair did not pass count()-check above. // TRANS: Exception when public key was not properly formatted. throw new Exception(_m('Incorrectly formatted public key element.')); } return $keypair; }
function onEndUnsubscribe(Profile $profile, Profile $other) { // Only do this if config is enabled if (!$this->StopFollowUser) { return true; } if (!$profile->isLocal()) { return true; } // TRANS: Text for "stopped following" item in activity plugin. // TRANS: %1$s is a profile URL, %2$s is a profile name, // TRANS: %3$s is a profile URL, %4$s is a profile name. $rendered = sprintf(_m('<a href="%1$s">%2$s</a> stopped following <a href="%3$s">%4$s</a>.'), $profile->getUrl(), $profile->getBestName(), $other->getUrl(), $other->getBestName()); // TRANS: Text for "stopped following" item in activity plugin. // TRANS: %1$s is a profile name, %2$s is a profile URL, // TRANS: %3$s is a profile name, %4$s is a profile URL. $content = sprintf(_m('%1$s (%2$s) stopped following %3$s (%4$s).'), $profile->getBestName(), $profile->getUrl(), $other->getBestName(), $other->getUrl()); $uri = TagURI::mint('stop-following:%d:%d:%s', $profile->id, $other->id, common_date_iso8601(common_sql_now())); $notice = Notice::saveNew($profile->id, $content, ActivityPlugin::SOURCE, array('rendered' => $rendered, 'urls' => array(), 'replies' => array($other->getUri()), 'uri' => $uri, 'verb' => ActivityVerb::UNFOLLOW, 'object_type' => ActivityObject::PERSON)); return true; }
/** * Get the Salmon keypair from a URI, uses XRD Discovery etc. Reasonably * you'll only get the public key ;) * * The string will (hopefully) be formatted as described in Magicsig specification: * https://salmon-protocol.googlecode.com/svn/trunk/draft-panzer-magicsig-01.html#anchor13 * * @return string formatted as Magicsig keypair */ public function discoverKeyPair(Profile $profile) { $signer_uri = $profile->getUri(); if (empty($signer_uri)) { throw new ServerException(sprintf('Profile missing URI (id==%d)', $profile->getID())); } $disco = new Discovery(); // Throws exception on lookup problems try { $xrd = $disco->lookup($signer_uri); } catch (Exception $e) { // Diaspora seems to require us to request the acct: uri $xrd = $disco->lookup($profile->getAcctUri()); } common_debug('Will try to find magic-public-key from XRD of profile id==' . $profile->getID()); $pubkey = null; if (Event::handle('MagicsigPublicKeyFromXRD', array($xrd, &$pubkey))) { $link = $xrd->get(Magicsig::PUBLICKEYREL); if (is_null($link)) { // TRANS: Exception. throw new Exception(_m('Unable to locate signer public key.')); } $pubkey = $link->href; } if (empty($pubkey)) { throw new ServerException('Empty Magicsig public key. A bug?'); } // We have a public key element, let's hope it has proper key data. $keypair = false; $parts = explode(',', $pubkey); if (count($parts) == 2) { $keypair = $parts[1]; } else { // Backwards compatibility check for separator bug in 0.9.0 $parts = explode(';', $pubkey); if (count($parts) == 2) { $keypair = $parts[1]; } } if ($keypair === false) { // For debugging clarity. Keypair did not pass count()-check above. // TRANS: Exception when public key was not properly formatted. throw new Exception(_m('Incorrectly formatted public key element.')); } return $keypair; }
static function fromProfile(Profile $profile) { $object = new ActivityObject(); if (Event::handle('StartActivityObjectFromProfile', array($profile, &$object))) { $object->type = ActivityObject::PERSON; $object->id = $profile->getUri(); $object->title = $profile->getBestName(); $object->link = $profile->profileurl; $orig = $profile->getOriginalAvatar(); if (!empty($orig)) { $object->avatarLinks[] = AvatarLink::fromAvatar($orig); } $sizes = array(AVATAR_PROFILE_SIZE, AVATAR_STREAM_SIZE, AVATAR_MINI_SIZE); foreach ($sizes as $size) { $alink = null; $avatar = $profile->getAvatar($size); if (!empty($avatar)) { $alink = AvatarLink::fromAvatar($avatar); } else { $alink = new AvatarLink(); $alink->type = 'image/png'; $alink->height = $size; $alink->width = $size; $alink->url = Avatar::defaultImage($size); if ($size == AVATAR_PROFILE_SIZE) { // Hack for Twitter import: we don't have a 96x96 image, // but we do have a 73x73 image. For now, fake it with that. $avatar = $profile->getAvatar(73); if ($avatar) { $alink = AvatarLink::fromAvatar($avatar); $alink->height = $size; $alink->width = $size; } } } $object->avatarLinks[] = $alink; } if (isset($profile->lat) && isset($profile->lon)) { $object->geopoint = (double) $profile->lat . ' ' . (double) $profile->lon; } $object->poco = PoCo::fromProfile($profile); Event::handle('EndActivityObjectFromProfile', array($profile, &$object)); } return $object; }
static function fromProfile(Profile $profile) { $object = new ActivityObject(); $object->type = ActivityObject::PERSON; $object->id = $profile->getUri(); $object->title = $profile->getBestName(); $object->link = $profile->profileurl; $orig = $profile->getOriginalAvatar(); if (!empty($orig)) { $object->avatarLinks[] = AvatarLink::fromAvatar($orig); } $sizes = array(AVATAR_PROFILE_SIZE, AVATAR_STREAM_SIZE, AVATAR_MINI_SIZE); foreach ($sizes as $size) { $alink = null; $avatar = $profile->getAvatar($size); if (!empty($avatar)) { $alink = AvatarLink::fromAvatar($avatar); } else { $alink = new AvatarLink(); $alink->type = 'image/png'; $alink->height = $size; $alink->width = $size; $alink->url = Avatar::defaultImage($size); } $object->avatarLinks[] = $alink; } if (isset($profile->lat) && isset($profile->lon)) { $object->geopoint = (double) $profile->lat . ' ' . (double) $profile->lon; } $object->poco = PoCo::fromProfile($profile); return $object; }
static function checkAuthorship(Activity $activity, Profile $profile) { if (Event::handle('CheckActivityAuthorship', array($activity, &$profile))) { // if (empty($activity->actor)), then we generated this Activity ourselves and can trust $profile $actor_uri = $profile->getUri(); if (!in_array($actor_uri, array($activity->actor->id, $activity->actor->link))) { // A mismatch between our locally stored URI and the supplied author? // Probably not more than a blog feed or something (with multiple authors or so) // but log it for future inspection. common_log(LOG_WARNING, "Got an actor '{$activity->actor->title}' ({$activity->actor->id}) on single-user feed for " . $actor_uri); } elseif (empty($activity->actor->id)) { // Plain <author> without ActivityStreams actor info. // We'll just ignore this info for now and save the update under the feed's identity. } } if (!$profile instanceof Profile) { throw new ServerException('Could not get an author Profile for activity'); } return $profile; }