Implemented WebFinger and replaced our XRD with PEAR XML_XRD
New plugins: * LRDD LRDD implements client-side RFC6415 and RFC7033 resource descriptor discovery procedures. I.e. LRDD, host-meta and WebFinger stuff. OStatus and OpenID now depend on the LRDD plugin (XML_XRD). * WebFinger This plugin implements the server-side of RFC6415 and RFC7033. Note: WebFinger technically doesn't handle XRD, but we serve both that and JRD (JSON Resource Descriptor), depending on Accept header and one ugly hack to check for old StatusNet installations. WebFinger depends on LRDD. We might make this even prettier by using Net_WebFinger, but it is not currently RFC7033 compliant (no /.well-known/webfinger resource GETs). Disabling the WebFinger plugin would effectively render your site non- federated (which might be desired on a private site). Disabling the LRDD plugin would make your site unable to do modern web URI lookups (making life just a little bit harder).
This commit is contained in:
29
plugins/WebFinger/EVENTS.txt
Normal file
29
plugins/WebFinger/EVENTS.txt
Normal file
@@ -0,0 +1,29 @@
|
||||
StartHostMetaLinks: Start /.well-known/host-meta links
|
||||
- &links: array containing the links elements to be written
|
||||
|
||||
EndHostMetaLinks: End /.well-known/host-meta links
|
||||
- &links: array containing the links elements to be written
|
||||
|
||||
StartWebFingerReconstruction:
|
||||
- $profile: Profile object for which we want a WebFinger ID
|
||||
- &$acct: String reference where reconstructed ID is stored
|
||||
|
||||
EndWebFingerReconstruction:
|
||||
- $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
|
||||
- $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
|
||||
- $xrd: XML_XRD object being shown
|
||||
- $target: Profile being shown
|
97
plugins/WebFinger/WebFingerPlugin.php
Normal file
97
plugins/WebFinger/WebFingerPlugin.php
Normal file
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
/*
|
||||
* GNU Social - a federating social network
|
||||
* Copyright (C) 2013, Free Software Foundation, Inc.
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements WebFinger for GNU Social, as well as support for the
|
||||
* '.well-known/host-meta' resource.
|
||||
*
|
||||
* Depends on: LRDD plugin
|
||||
*
|
||||
* @package GNUSocial
|
||||
* @author Mikael Nordfeldth <mmn@hethane.se>
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class WebFingerPlugin extends Plugin
|
||||
{
|
||||
public function onRouterInitialized($m)
|
||||
{
|
||||
$m->connect('.well-known/host-meta', array('action' => 'hostmeta'));
|
||||
$m->connect('.well-known/host-meta.:format',
|
||||
array('action' => 'hostmeta',
|
||||
'format' => '(xml|json)'));
|
||||
// the resource GET parameter can be anywhere, so don't mention it here
|
||||
$m->connect('.well-known/webfinger', array('action' => 'webfinger'));
|
||||
$m->connect('.well-known/webfinger.:format',
|
||||
array('action' => 'webfinger',
|
||||
'format' => '(xml|json)'));
|
||||
$m->connect('main/ownerxrd', array('action' => 'ownerxrd'));
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onLoginAction($action, &$login)
|
||||
{
|
||||
switch ($action) {
|
||||
case 'hostmeta':
|
||||
case 'webfinger':
|
||||
$login = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onStartHostMetaLinks(array &$links)
|
||||
{
|
||||
foreach (Discovery::supportedMimeTypes() as $type) {
|
||||
$links[] = new XML_XRD_Element_Link(Discovery::LRDD_REL,
|
||||
common_local_url('webfinger') . '?resource={uri}',
|
||||
$type,
|
||||
true); // isTemplate
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a link header for LRDD Discovery
|
||||
*/
|
||||
public function onStartShowHTML($action)
|
||||
{
|
||||
if ($action instanceof ShowstreamAction) {
|
||||
$acct = 'acct:'. $action->profile->nickname .'@'. common_config('site', 'server');
|
||||
$url = common_local_url('webfinger') . '?resource='.$acct;
|
||||
|
||||
foreach (array(Discovery::JRD_MIMETYPE, Discovery::XRD_MIMETYPE) as $type) {
|
||||
header('Link: <'.$url.'>; rel="'. Discovery::LRDD_REL.'"; type="'.$type.'"');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function onPluginVersion(&$versions)
|
||||
{
|
||||
$versions[] = array('name' => 'WebFinger',
|
||||
'version' => STATUSNET_VERSION,
|
||||
'author' => 'Mikael Nordfeldth',
|
||||
'homepage' => 'http://www.gnu.org/software/social/',
|
||||
// TRANS: Plugin description.
|
||||
'rawdescription' => _m('Adds WebFinger lookup to GNU Social'));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
41
plugins/WebFinger/actions/hostmeta.php
Normal file
41
plugins/WebFinger/actions/hostmeta.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/*
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2010, StatusNet, Inc.
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @category Action
|
||||
* @package StatusNet
|
||||
* @author James Walker <james@status.net>
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Mikael Nordfeldth <mmn@hethane.se>
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
// @todo XXX: Add documentation.
|
||||
class HostMetaAction extends XrdAction
|
||||
{
|
||||
protected $defaultformat = 'xml';
|
||||
|
||||
protected function setXRD()
|
||||
{
|
||||
if(Event::handle('StartHostMetaLinks', array(&$this->xrd->links))) {
|
||||
Event::handle('EndHostMetaLinks', array(&$this->xrd->links));
|
||||
}
|
||||
}
|
||||
}
|
59
plugins/WebFinger/actions/ownerxrd.php
Normal file
59
plugins/WebFinger/actions/ownerxrd.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
/*
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2010, StatusNet, Inc.
|
||||
*
|
||||
* 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 WebFingerPlugin
|
||||
* @author James Walker <james@status.net>
|
||||
* @author Mikael Nordfeldth <mmn@hethane.se>
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class OwnerxrdAction extends WebfingerAction
|
||||
{
|
||||
protected $defaultformat = 'xml';
|
||||
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
$user = User::siteOwner();
|
||||
|
||||
$nick = common_canonical_nickname($user->nickname);
|
||||
$args['resource'] = 'acct:' . $nick . '@' . common_config('site', 'server');
|
||||
|
||||
// We have now set $args['resource'] to the configured value, since
|
||||
// only this local site configuration knows who the owner is!
|
||||
parent::prepare($args);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function setXRD()
|
||||
{
|
||||
parent::setXRD();
|
||||
|
||||
// Check to see if a $config['webfinger']['owner'] has been set
|
||||
// and then make sure 'subject' is set to that primary identity.
|
||||
if ($owner = common_config('webfinger', 'owner')) {
|
||||
$this->xrd->aliases[] = $this->xrd->subject;
|
||||
$this->xrd->subject = Discovery::normalize($owner);
|
||||
} else {
|
||||
$this->xrd->subject = $this->resource;
|
||||
}
|
||||
}
|
||||
}
|
122
plugins/WebFinger/actions/webfinger.php
Normal file
122
plugins/WebFinger/actions/webfinger.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
/*
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2010, StatusNet, Inc.
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* @package WebFingerPlugin
|
||||
* @author James Walker <james@status.net>
|
||||
* @author Mikael Nordfeldth <mmn@hethane.se>
|
||||
*/
|
||||
class WebfingerAction extends XrdAction
|
||||
{
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function setXRD()
|
||||
{
|
||||
if (empty($this->target)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
100
plugins/WebFinger/lib/webfinger.php
Normal file
100
plugins/WebFinger/lib/webfinger.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
55
plugins/WebFinger/lib/webfingerreconstructionexception.php
Normal file
55
plugins/WebFinger/lib/webfingerreconstructionexception.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Class for an exception when a WebFinger acct: URI can not be constructed
|
||||
* using the data we have in a Profile.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category Exception
|
||||
* @package StatusNet
|
||||
* @author Mikael Nordfeldth <mmn@hethane.se>
|
||||
* @copyright 2013 Free Software Foundation, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Class for an exception when a WebFinger acct: URI can not be constructed
|
||||
* using the data we have in a Profile.
|
||||
*
|
||||
* @category Exception
|
||||
* @package StatusNet
|
||||
* @author Mikael Nordfeldth <mmn@hethane.se>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class WebFingerReconstructionException extends ServerException
|
||||
{
|
||||
public $target = null;
|
||||
|
||||
public function __construct(Profile $target)
|
||||
{
|
||||
$this->target = $target;
|
||||
|
||||
// We could log an entry here with the search parameters
|
||||
parent::__construct(_('WebFinger URI generation failed.'));
|
||||
}
|
||||
}
|
150
plugins/WebFinger/lib/xrdaction.php
Normal file
150
plugins/WebFinger/lib/xrdaction.php
Normal file
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
/*
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2010, StatusNet, Inc.
|
||||
*
|
||||
* 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 WebFingerPlugin
|
||||
* @author James Walker <james@status.net>
|
||||
* @author Mikael Nordfeldth <mmn@hethane.se>
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
abstract class XrdAction extends Action
|
||||
{
|
||||
// json or xml for now, this may still be overriden because of
|
||||
// our back-compatibility with StatusNet <=1.1.1
|
||||
protected $defaultformat = null;
|
||||
|
||||
protected $resource = null;
|
||||
protected $target = null;
|
||||
protected $xrd = null;
|
||||
|
||||
public function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configures $this->xrd which will later be printed. Must be
|
||||
* implemented by child classes.
|
||||
*/
|
||||
abstract protected function setXRD();
|
||||
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
if (!isset($args['format'])) {
|
||||
$args['format'] = $this->defaultformat;
|
||||
}
|
||||
|
||||
parent::prepare($args);
|
||||
|
||||
$this->xrd = new XML_XRD();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$this->setXRD();
|
||||
|
||||
if (common_config('discovery', 'cors')) {
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
}
|
||||
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
public function mimeType()
|
||||
{
|
||||
try {
|
||||
return $this->checkAccept();
|
||||
} catch (Exception $e) {
|
||||
$supported = Discovery::supportedMimeTypes();
|
||||
$docformat = $this->arg('format');
|
||||
|
||||
if (!empty($docformat) && isset($supported[$docformat])) {
|
||||
return $supported[$docformat];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* "A WebFinger resource MUST return a JRD as the representation
|
||||
* for the resource if the client requests no other supported
|
||||
* format explicitly via the HTTP "Accept" header. [...]
|
||||
* The WebFinger resource MUST silently ignore any requested
|
||||
* representations that it does not understand and support."
|
||||
* -- RFC 7033 (WebFinger)
|
||||
* http://tools.ietf.org/html/rfc7033
|
||||
*/
|
||||
return Discovery::JRD_MIMETYPE;
|
||||
}
|
||||
|
||||
public function showPage()
|
||||
{
|
||||
$mimeType = $this->mimeType();
|
||||
header("Content-type: {$mimeType}");
|
||||
|
||||
switch ($mimeType) {
|
||||
case Discovery::XRD_MIMETYPE:
|
||||
print $this->xrd->toXML();
|
||||
break;
|
||||
case Discovery::JRD_MIMETYPE:
|
||||
case Discovery::JRD_MIMETYPE_OLD:
|
||||
print $this->xrd->to('json');
|
||||
break;
|
||||
default:
|
||||
throw new Exception(_('No supported MIME type in Accept header.'));
|
||||
}
|
||||
}
|
||||
|
||||
protected function checkAccept()
|
||||
{
|
||||
$type = null;
|
||||
$httpaccept = isset($_SERVER['HTTP_ACCEPT'])
|
||||
? $_SERVER['HTTP_ACCEPT'] : null;
|
||||
$useragent = isset($_SERVER['HTTP_USER_AGENT'])
|
||||
? $_SERVER['HTTP_USER_AGENT'] : null;
|
||||
|
||||
if ($httpaccept !== null && $httpaccept != '*/*') {
|
||||
$can_serve = implode(',', Discovery::supportedMimeTypes());
|
||||
$type = common_negotiate_type(common_accept_to_prefs($httpaccept),
|
||||
common_accept_to_prefs($can_serve));
|
||||
} else {
|
||||
/*
|
||||
* HACK: for StatusNet to work against us, we must always serve an
|
||||
* XRD to at least versions <1.1.1 (at time of writing) since they
|
||||
* don't send Accept headers (in their 'Discovery::fetchXrd' calls)
|
||||
*/
|
||||
$matches = array();
|
||||
preg_match('/(StatusNet)\/(\d+\.\d+(\.\d+)?)/', $useragent, $browser);
|
||||
if (count($browser)>2 && $browser[1] === 'StatusNet'
|
||||
&& version_compare($browser[2], '1.1.1') < 1) {
|
||||
return Discovery::XRD_MIMETYPE;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($type)) {
|
||||
throw new Exception(_('No specified MIME type in Accept header.'));
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user