WebFingerResource introduced, instead of strict Profile object
This is the beginning of getting notice URI info via WebFinger *XrdActionLinks is renamed *WebFingerProfileLinks, check EVENTS.txt in WebFinger plugin for new events.
This commit is contained in:
parent
d632df320a
commit
e868ebfe77
@ -216,6 +216,12 @@ class Notice extends Managed_DataObject
|
||||
return $this->uri;
|
||||
}
|
||||
|
||||
public function getUrl()
|
||||
{
|
||||
// The risk is we start having empty urls and non-http uris...
|
||||
return $this->url ?: $this->uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract #hashtags from this notice's content and save them to the database.
|
||||
*/
|
||||
|
@ -1314,7 +1314,7 @@ class OStatusPlugin extends Plugin
|
||||
return true;
|
||||
}
|
||||
|
||||
function onEndXrdActionLinks(XML_XRD $xrd, Profile $target)
|
||||
function onEndWebFingerProfileLinks(XML_XRD $xrd, Profile $target)
|
||||
{
|
||||
$xrd->links[] = new XML_XRD_Element_Link(Discovery::UPDATESFROM,
|
||||
common_local_url('ApiTimelineUser',
|
||||
|
@ -26,7 +26,7 @@ class DiscoveryHints {
|
||||
|
||||
foreach ($xrd->links as $link) {
|
||||
switch ($link->rel) {
|
||||
case WebFinger::PROFILEPAGE:
|
||||
case WebFingerResource::PROFILEPAGE:
|
||||
$hints['profileurl'] = $link->href;
|
||||
break;
|
||||
case Salmon::NS_MENTIONS:
|
||||
|
@ -773,7 +773,7 @@ class OpenIDPlugin extends Plugin
|
||||
* @return boolean hook value (always true)
|
||||
*/
|
||||
|
||||
function onEndXrdActionLinks(XML_XRD $xrd, Profile $target)
|
||||
function onEndWebFingerProfileLinks(XML_XRD $xrd, Profile $target)
|
||||
{
|
||||
$xrd->links[] = new XML_XRD_Element_Link(
|
||||
'http://specs.openid.net/auth/2.0/provider',
|
||||
|
@ -4,26 +4,28 @@ StartHostMetaLinks: Start /.well-known/host-meta links
|
||||
EndHostMetaLinks: End /.well-known/host-meta links
|
||||
- &links: array containing the links elements to be written
|
||||
|
||||
StartWebFingerReconstruction:
|
||||
StartGetWebFingerResource: Get a WebFingerResource extended object by resource string
|
||||
- $resource String that contains the requested URI
|
||||
- &$target WebFingerResource extended object goes here
|
||||
- $args Array which may contains arguments such as 'rel' filtering values
|
||||
|
||||
EndGetWebFingerResource: Last attempts getting a WebFingerResource object
|
||||
- $resource String that contains the requested URI
|
||||
- &$target WebFingerResource extended object goes here
|
||||
- $args Array which may contains arguments such as 'rel' filtering values
|
||||
|
||||
StartWebFingerReconstruction: Generate an acct: uri from a Profile object
|
||||
- $profile: Profile object for which we want a WebFinger ID
|
||||
- &$acct: String reference where reconstructed ID is stored
|
||||
|
||||
EndWebFingerReconstruction:
|
||||
EndWebFingerReconstruction: Last attempts to generate an acct: uri from a Profile object
|
||||
- $profile: Profile object for which we want a WebFinger ID
|
||||
- &$acct: String reference where reconstructed ID is stored
|
||||
|
||||
StartXrdActionAliases: About to set aliases for the XRD for a user
|
||||
StartWebFingerProfileLinks: About to set links for the resource descriptor of a profile
|
||||
- $xrd: XML_XRD object being shown
|
||||
- $target: Profile being shown
|
||||
|
||||
EndXrdActionAliases: Done with aliases for the XRD for a user
|
||||
- $xrd: XML_XRD object being shown
|
||||
- $target: Profile being shown
|
||||
|
||||
StartXrdActionLinks: About to set links for the XRD for a profile
|
||||
- $xrd: XML_XRD object being shown
|
||||
- $target: Profile being shown
|
||||
|
||||
EndXrdActionLinks: Done with links for the XRD for a profile
|
||||
EndWebFingerProfileLinks: Done with links for the resource descriptor of a profile
|
||||
- $xrd: XML_XRD object being shown
|
||||
- $target: Profile being shown
|
||||
|
@ -58,6 +58,48 @@ class WebFingerPlugin extends Plugin
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onEndGetWebFingerResource($resource, WebFingerResource &$target=null, array $args=array())
|
||||
{
|
||||
$profile = null;
|
||||
if (Discovery::isAcct($resource)) {
|
||||
$parts = explode('@', substr(urldecode($resource), 5)); // 5 is strlen of 'acct:'
|
||||
if (count($parts) == 2) {
|
||||
list($nick, $domain) = $parts;
|
||||
if ($domain === common_config('site', 'server')) {
|
||||
$nick = common_canonical_nickname($nick);
|
||||
$user = User::getKV('nickname', $nick);
|
||||
if (!($user instanceof User)) {
|
||||
throw new NoSuchUserException(array('nickname'=>$nick));
|
||||
}
|
||||
$profile = $user->getProfile();
|
||||
} else {
|
||||
throw new Exception(_('Remote profiles not supported via WebFinger yet.'));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$user = User::getKV('uri', $resource);
|
||||
if ($user instanceof User) {
|
||||
$profile = $user->getProfile();
|
||||
} else {
|
||||
// try and get it by profile url
|
||||
$profile = Profile::getKV('profileurl', $resource);
|
||||
}
|
||||
}
|
||||
|
||||
if ($profile instanceof Profile) {
|
||||
$target = new WebFingerResource_Profile($profile);
|
||||
return false; // We got our target, stop handler execution
|
||||
}
|
||||
|
||||
$notice = Notice::getKV('uri', $resource);
|
||||
if ($notice instanceof Notice) {
|
||||
$target = new WebFingerResource_Notice($notice);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onStartHostMetaLinks(array &$links)
|
||||
{
|
||||
foreach (Discovery::supportedMimeTypes() as $type) {
|
||||
|
@ -26,6 +26,9 @@ if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
*/
|
||||
class WebfingerAction extends XrdAction
|
||||
{
|
||||
protected $resource = null; // string with the resource URI
|
||||
protected $target = null; // object of the WebFingerResource class
|
||||
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
@ -33,34 +36,8 @@ class WebfingerAction extends XrdAction
|
||||
// throws exception if resource is empty
|
||||
$this->resource = Discovery::normalize($this->trimmed('resource'));
|
||||
|
||||
if (Discovery::isAcct($this->resource)) {
|
||||
$parts = explode('@', substr(urldecode($this->resource), 5));
|
||||
if (count($parts) == 2) {
|
||||
list($nick, $domain) = $parts;
|
||||
if ($domain === common_config('site', 'server')) {
|
||||
$nick = common_canonical_nickname($nick);
|
||||
$user = User::getKV('nickname', $nick);
|
||||
if (!($user instanceof User)) {
|
||||
throw new NoSuchUserException(array('nickname'=>$nick));
|
||||
}
|
||||
$this->target = $user->getProfile();
|
||||
} else {
|
||||
throw new Exception(_('Remote profiles not supported via WebFinger yet.'));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$user = User::getKV('uri', $this->resource);
|
||||
if ($user instanceof User) {
|
||||
$this->target = $user->getProfile();
|
||||
} else {
|
||||
// try and get it by profile url
|
||||
$this->target = Profile::getKV('profileurl', $this->resource);
|
||||
}
|
||||
}
|
||||
|
||||
if (!($this->target instanceof Profile)) {
|
||||
// TRANS: Client error displayed when user not found for an action.
|
||||
$this->clientError(_('No such user: ') . var_export($this->resource,true), 404);
|
||||
if (Event::handle('StartGetWebFingerResource', array($this->resource, &$this->target, $this->args))) {
|
||||
Event::handle('EndGetWebFingerResource', array($this->resource, &$this->target, $this->args));
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -68,55 +45,18 @@ class WebfingerAction extends XrdAction
|
||||
|
||||
protected function setXRD()
|
||||
{
|
||||
if (empty($this->target)) {
|
||||
if (!($this->target instanceof WebFingerResource)) {
|
||||
throw new Exception(_('Target not set for resource descriptor'));
|
||||
}
|
||||
|
||||
// $this->target set in a _child_ class prepare()
|
||||
$nick = $this->target->nickname;
|
||||
|
||||
$this->xrd->subject = $this->resource;
|
||||
|
||||
if (Event::handle('StartXrdActionAliases', array($this->xrd, $this->target))) {
|
||||
$uris = WebFinger::getIdentities($this->target);
|
||||
foreach ($uris as $uri) {
|
||||
if ($uri != $this->xrd->subject && !in_array($uri, $this->xrd->aliases)) {
|
||||
$this->xrd->aliases[] = $uri;
|
||||
foreach ($this->target->getAliases() as $alias) {
|
||||
if ($alias != $this->xrd->subject && !in_array($alias, $this->xrd->aliases)) {
|
||||
$this->xrd->aliases[] = $alias;
|
||||
}
|
||||
}
|
||||
Event::handle('EndXrdActionAliases', array($this->xrd, $this->target));
|
||||
}
|
||||
|
||||
if (Event::handle('StartXrdActionLinks', array($this->xrd, $this->target))) {
|
||||
|
||||
$this->xrd->links[] = new XML_XRD_Element_Link(WebFinger::PROFILEPAGE,
|
||||
$this->target->getUrl(), 'text/html');
|
||||
|
||||
// XFN
|
||||
$this->xrd->links[] = new XML_XRD_Element_Link('http://gmpg.org/xfn/11',
|
||||
$this->target->getUrl(), 'text/html');
|
||||
// FOAF
|
||||
$this->xrd->links[] = new XML_XRD_Element_Link('describedby',
|
||||
common_local_url('foaf', array('nickname' => $nick)),
|
||||
'application/rdf+xml');
|
||||
|
||||
$link = new XML_XRD_Element_Link('http://apinamespace.org/atom',
|
||||
common_local_url('ApiAtomService', array('id' => $nick)),
|
||||
'application/atomsvc+xml');
|
||||
// XML_XRD must implement changing properties first $link['http://apinamespace.org/atom/username'] = $nick;
|
||||
$this->xrd->links[] = clone $link;
|
||||
|
||||
if (common_config('site', 'fancy')) {
|
||||
$apiRoot = common_path('api/', true);
|
||||
} else {
|
||||
$apiRoot = common_path('index.php/api/', true);
|
||||
}
|
||||
|
||||
$link = new XML_XRD_Element_Link('http://apinamespace.org/twitter', $apiRoot);
|
||||
// XML_XRD must implement changing properties first $link['http://apinamespace.org/twitter/username'] = $nick;
|
||||
$this->xrd->links[] = clone $link;
|
||||
|
||||
Event::handle('EndXrdActionLinks', array($this->xrd, $this->target));
|
||||
}
|
||||
$this->target->updateXRD($this->xrd);
|
||||
}
|
||||
}
|
||||
|
@ -1,100 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2010, StatusNet, Inc.
|
||||
*
|
||||
* WebFinger functions
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @package GNUsocial
|
||||
* @author Mikael Nordfeldth
|
||||
* @copyright 2013 Free Software Foundation, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class WebFinger
|
||||
{
|
||||
const PROFILEPAGE = 'http://webfinger.net/rel/profile-page';
|
||||
|
||||
/*
|
||||
* Reconstructs a WebFinger ID from data we know about the profile.
|
||||
*
|
||||
* @param Profile $profile The profile we want a WebFinger ID for
|
||||
*
|
||||
* @return string $acct acct:user@example.com URI
|
||||
*/
|
||||
public static function reconstruct(Profile $profile)
|
||||
{
|
||||
$acct = null;
|
||||
|
||||
if (Event::handle('StartWebFingerReconstruction', array($profile, &$acct))) {
|
||||
// TODO: getUri may not always give us the correct host on remote users?
|
||||
$host = parse_url($profile->getUri(), PHP_URL_HOST);
|
||||
if (empty($profile->nickname) || empty($host)) {
|
||||
throw new WebFingerReconstructionException($profile);
|
||||
}
|
||||
$acct = sprintf('acct:%s@%s', $profile->nickname, $host);
|
||||
|
||||
Event::handle('EndWebFingerReconstruction', array($profile, &$acct));
|
||||
}
|
||||
|
||||
return $acct;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets all URI aliases for a Profile
|
||||
*
|
||||
* @param Profile $profile The profile we want aliases for
|
||||
*
|
||||
* @return array $aliases All the Profile's alternative URLs
|
||||
*/
|
||||
public static function getAliases(Profile $profile)
|
||||
{
|
||||
$aliases = array();
|
||||
$aliases[] = $profile->getUri();
|
||||
try {
|
||||
$aliases[] = $profile->getUrl();
|
||||
} catch (InvalidUrlException $e) {
|
||||
common_debug('Profile id='.$profile->id.' has invalid profileurl: ' .
|
||||
var_export($profile->profileurl, true));
|
||||
}
|
||||
return $aliases;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets all identities for a Profile, includes WebFinger acct: if
|
||||
* available, as well as alias URLs.
|
||||
*
|
||||
* @param Profile $profile The profile we want aliases for
|
||||
*
|
||||
* @return array $uris WebFinger acct: URI and alias URLs
|
||||
*/
|
||||
public static function getIdentities(Profile $profile)
|
||||
{
|
||||
$uris = array();
|
||||
try {
|
||||
$uris[] = self::reconstruct($profile);
|
||||
} catch (WebFingerReconstructionException $e) {
|
||||
common_debug('WebFinger reconstruction for Profile failed, ' .
|
||||
' (id='.$profile->id.')');
|
||||
}
|
||||
$uris = array_merge($uris, self::getAliases($profile));
|
||||
|
||||
return $uris;
|
||||
}
|
||||
}
|
54
plugins/WebFinger/lib/webfingerresource.php
Normal file
54
plugins/WebFinger/lib/webfingerresource.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* WebFinger resource parent class
|
||||
*
|
||||
* @package GNUsocial
|
||||
* @author Mikael Nordfeldth
|
||||
* @copyright 2013 Free Software Foundation, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
abstract class WebFingerResource
|
||||
{
|
||||
const PROFILEPAGE = 'http://webfinger.net/rel/profile-page';
|
||||
|
||||
protected $identities = array();
|
||||
|
||||
protected $object = null;
|
||||
protected $type = null;
|
||||
|
||||
public function __construct(Managed_DataObject $object)
|
||||
{
|
||||
$this->object = $object;
|
||||
}
|
||||
|
||||
public function getObject()
|
||||
{
|
||||
if ($this->object === null) {
|
||||
throw new ServerException('Object is not set');
|
||||
}
|
||||
return $this->object;
|
||||
}
|
||||
|
||||
public function getAliases()
|
||||
{
|
||||
$aliases = array();
|
||||
|
||||
// Add the URI as an identity, this is _not_ necessarily an HTTP url
|
||||
$aliases[] = $this->object->getUri();
|
||||
|
||||
try {
|
||||
$aliases[] = $this->object->getUrl();
|
||||
} catch (InvalidUrlException $e) {
|
||||
// getUrl failed because no valid URL could be returned, just ignore it
|
||||
}
|
||||
|
||||
return $aliases;
|
||||
}
|
||||
|
||||
public function updateXRD(XML_XRD $xrd) {
|
||||
$xrd->links[] = new XML_XRD_Element_Link(WebFingerResource::PROFILEPAGE,
|
||||
$this->object->getUrl(), 'text/html');
|
||||
}
|
||||
}
|
27
plugins/WebFinger/lib/webfingerresource/notice.php
Normal file
27
plugins/WebFinger/lib/webfingerresource/notice.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* WebFinger resource for Notice objects
|
||||
*
|
||||
* @package GNUsocial
|
||||
* @author Mikael Nordfeldth
|
||||
* @copyright 2013 Free Software Foundation, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class WebFingerResource_Notice extends WebFingerResource
|
||||
{
|
||||
public function __construct(Notice $object)
|
||||
{
|
||||
// The type argument above verifies that it's our class
|
||||
parent::__construct($object);
|
||||
}
|
||||
|
||||
public function updateXRD(XML_XRD $xrd)
|
||||
{
|
||||
parent::updateXRD($xrd);
|
||||
|
||||
// TODO: Add atom and json representation links here
|
||||
// TODO: Add Salmon/callback links and stuff here
|
||||
}
|
||||
}
|
87
plugins/WebFinger/lib/webfingerresource/profile.php
Normal file
87
plugins/WebFinger/lib/webfingerresource/profile.php
Normal file
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
/**
|
||||
* WebFinger resource for Profile objects
|
||||
*
|
||||
* @package GNUsocial
|
||||
* @author Mikael Nordfeldth
|
||||
* @copyright 2013 Free Software Foundation, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class WebFingerResource_Profile extends WebFingerResource
|
||||
{
|
||||
public function __construct(Profile $object)
|
||||
{
|
||||
// The type argument above verifies that it's our class
|
||||
parent::__construct($object);
|
||||
}
|
||||
|
||||
public function getAliases()
|
||||
{
|
||||
$aliases = array();
|
||||
|
||||
try {
|
||||
// Try to create an acct: URI if we're dealing with a profile
|
||||
$aliases[] = $this->reconstructAcct();
|
||||
} catch (WebFingerReconstructionException $e) {
|
||||
common_debug("WebFinger reconstruction for Profile failed (id={$this->object->id})");
|
||||
}
|
||||
|
||||
return array_merge($aliases, parent::getAliases());
|
||||
}
|
||||
|
||||
protected function reconstructAcct()
|
||||
{
|
||||
$acct = null;
|
||||
|
||||
if (Event::handle('StartWebFingerReconstruction', array($this->object, &$acct))) {
|
||||
// TODO: getUri may not always give us the correct host on remote users?
|
||||
$host = parse_url($this->object->getUri(), PHP_URL_HOST);
|
||||
if (empty($this->object->nickname) || empty($host)) {
|
||||
throw new WebFingerReconstructionException($this->object);
|
||||
}
|
||||
$acct = sprintf('acct:%s@%s', $this->object->nickname, $host);
|
||||
|
||||
Event::handle('EndWebFingerReconstruction', array($this->object, &$acct));
|
||||
}
|
||||
|
||||
return $acct;
|
||||
}
|
||||
|
||||
public function updateXRD(XML_XRD $xrd)
|
||||
{
|
||||
if (Event::handle('StartWebFingerProfileLinks', array($xrd, $this->object))) {
|
||||
|
||||
parent::updateXRD($xrd);
|
||||
|
||||
// XFN
|
||||
$xrd->links[] = new XML_XRD_Element_Link('http://gmpg.org/xfn/11',
|
||||
$this->object->getUrl(), 'text/html');
|
||||
// FOAF
|
||||
$xrd->links[] = new XML_XRD_Element_Link('describedby',
|
||||
common_local_url('foaf',
|
||||
array('nickname' => $this->object->nickname)),
|
||||
'application/rdf+xml');
|
||||
|
||||
$link = new XML_XRD_Element_Link('http://apinamespace.org/atom',
|
||||
common_local_url('ApiAtomService',
|
||||
array('id' => $this->object->nickname)),
|
||||
'application/atomsvc+xml');
|
||||
// XML_XRD must implement changing properties first $link['http://apinamespace.org/atom/username'] = $this->object->nickname;
|
||||
$xrd->links[] = clone $link;
|
||||
|
||||
if (common_config('site', 'fancy')) {
|
||||
$apiRoot = common_path('api/', true);
|
||||
} else {
|
||||
$apiRoot = common_path('index.php/api/', true);
|
||||
}
|
||||
|
||||
$link = new XML_XRD_Element_Link('http://apinamespace.org/twitter', $apiRoot);
|
||||
// XML_XRD must implement changing properties first $link['http://apinamespace.org/twitter/username'] = $this->object->nickname;
|
||||
$xrd->links[] = clone $link;
|
||||
|
||||
Event::handle('EndWebFingerProfileLinks', array($xrd, $this->object));
|
||||
}
|
||||
}
|
||||
}
|
@ -31,8 +31,6 @@ abstract class XrdAction extends Action
|
||||
// our back-compatibility with StatusNet <=1.1.1
|
||||
protected $defaultformat = null;
|
||||
|
||||
protected $resource = null;
|
||||
protected $target = null;
|
||||
protected $xrd = null;
|
||||
|
||||
public function isReadOnly($args)
|
||||
|
Loading…
Reference in New Issue
Block a user