WebFingerPlugin.php 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. <?php
  2. /*
  3. * GNU Social - a federating social network
  4. * Copyright (C) 2013, Free Software Foundation, Inc.
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. /**
  20. * Implements WebFinger for GNU Social, as well as support for the
  21. * '.well-known/host-meta' resource.
  22. *
  23. * Depends on: LRDD plugin
  24. *
  25. * @package GNUsocial
  26. * @author Mikael Nordfeldth <mmn@hethane.se>
  27. */
  28. if (!defined('GNUSOCIAL')) { exit(1); }
  29. class WebFingerPlugin extends Plugin
  30. {
  31. const OAUTH_ACCESS_TOKEN_REL = 'http://apinamespace.org/oauth/access_token';
  32. const OAUTH_REQUEST_TOKEN_REL = 'http://apinamespace.org/oauth/request_token';
  33. const OAUTH_AUTHORIZE_REL = 'http://apinamespace.org/oauth/authorize';
  34. public $http_alias = false;
  35. public function initialize()
  36. {
  37. common_config_set('webfinger', 'http_alias', $this->http_alias);
  38. }
  39. public function onRouterInitialized($m)
  40. {
  41. $m->connect('.well-known/host-meta', array('action' => 'hostmeta'));
  42. $m->connect('.well-known/host-meta.:format',
  43. array('action' => 'hostmeta',
  44. 'format' => '(xml|json)'));
  45. // the resource GET parameter can be anywhere, so don't mention it here
  46. $m->connect('.well-known/webfinger', array('action' => 'webfinger'));
  47. $m->connect('.well-known/webfinger.:format',
  48. array('action' => 'webfinger',
  49. 'format' => '(xml|json)'));
  50. $m->connect('main/ownerxrd', array('action' => 'ownerxrd'));
  51. return true;
  52. }
  53. public function onLoginAction($action, &$login)
  54. {
  55. switch ($action) {
  56. case 'hostmeta':
  57. case 'webfinger':
  58. $login = true;
  59. return false;
  60. }
  61. return true;
  62. }
  63. public function onStartGetProfileAcctUri(Profile $profile, &$acct)
  64. {
  65. $wfr = new WebFingerResource_Profile($profile);
  66. try {
  67. $acct = $wfr->reconstructAcct();
  68. } catch (Exception $e) {
  69. return true;
  70. }
  71. return false;
  72. }
  73. public function onEndGetWebFingerResource($resource, WebFingerResource &$target=null, array $args=array())
  74. {
  75. $profile = null;
  76. if (Discovery::isAcct($resource)) {
  77. $parts = explode('@', substr(urldecode($resource), 5)); // 5 is strlen of 'acct:'
  78. if (count($parts) == 2) {
  79. list($nick, $domain) = $parts;
  80. if ($domain === common_config('site', 'server')) {
  81. $nick = common_canonical_nickname($nick);
  82. $user = User::getKV('nickname', $nick);
  83. if (!($user instanceof User)) {
  84. throw new NoSuchUserException(array('nickname'=>$nick));
  85. }
  86. $profile = $user->getProfile();
  87. } else {
  88. throw new Exception(_('Remote profiles not supported via WebFinger yet.'));
  89. }
  90. }
  91. } else {
  92. try {
  93. $user = User::getByUri($resource);
  94. $profile = $user->getProfile();
  95. } catch (NoResultException $e) {
  96. if (common_config('fix', 'fancyurls')) {
  97. try {
  98. try { // if it's a /index.php/ url
  99. // common_fake_local_fancy_url can throw an exception
  100. $alt_url = common_fake_local_fancy_url($resource);
  101. } catch (Exception $e) { // let's try to create a fake local /index.php/ url
  102. // this too if it can't do anything about the URL
  103. $alt_url = common_fake_local_nonfancy_url($resource);
  104. }
  105. // and this will throw a NoResultException if not found
  106. $user = User::getByUri($alt_url);
  107. $profile = $user->getProfile();
  108. } catch (Exception $e) {
  109. // apparently we didn't get any matches with that, so continue...
  110. }
  111. }
  112. }
  113. }
  114. // if we still haven't found a match...
  115. if (!$profile instanceof Profile) {
  116. // if our rewrite hack didn't work, try to get something by profile URL
  117. $profile = Profile::getKV('profileurl', $resource);
  118. }
  119. if ($profile instanceof Profile) {
  120. $target = new WebFingerResource_Profile($profile);
  121. return false; // We got our target, stop handler execution
  122. }
  123. $notice = Notice::getKV('uri', $resource);
  124. if ($notice instanceof Notice) {
  125. $target = new WebFingerResource_Notice($notice);
  126. return false;
  127. }
  128. return true;
  129. }
  130. public function onStartHostMetaLinks(array &$links)
  131. {
  132. foreach (Discovery::supportedMimeTypes() as $type) {
  133. $links[] = new XML_XRD_Element_Link(Discovery::LRDD_REL,
  134. common_local_url('webfinger') . '?resource={uri}',
  135. $type,
  136. true); // isTemplate
  137. }
  138. // OAuth connections
  139. $links[] = new XML_XRD_Element_link(self::OAUTH_ACCESS_TOKEN_REL, common_local_url('ApiOAuthAccessToken'));
  140. $links[] = new XML_XRD_Element_link(self::OAUTH_REQUEST_TOKEN_REL, common_local_url('ApiOAuthRequestToken'));
  141. $links[] = new XML_XRD_Element_link(self::OAUTH_AUTHORIZE_REL, common_local_url('ApiOAuthAuthorize'));
  142. }
  143. /**
  144. * Add a link header for LRDD Discovery
  145. */
  146. public function onStartShowHTML($action)
  147. {
  148. if ($action instanceof ShowstreamAction) {
  149. $resource = $action->getTarget()->getUri();
  150. $url = common_local_url('webfinger') . '?resource='.urlencode($resource);
  151. foreach (array(Discovery::JRD_MIMETYPE, Discovery::XRD_MIMETYPE) as $type) {
  152. header('Link: <'.$url.'>; rel="'. Discovery::LRDD_REL.'"; type="'.$type.'"', false);
  153. }
  154. }
  155. }
  156. public function onPluginVersion(array &$versions)
  157. {
  158. $versions[] = array('name' => 'WebFinger',
  159. 'version' => GNUSOCIAL_VERSION,
  160. 'author' => 'Mikael Nordfeldth',
  161. 'homepage' => 'http://www.gnu.org/software/social/',
  162. // TRANS: Plugin description.
  163. 'rawdescription' => _m('Adds WebFinger lookup to GNU Social'));
  164. return true;
  165. }
  166. }