FetchRemotePlugin.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. <?php
  2. /*
  3. * GNU social - a federating social network
  4. * Copyright (C) 2013-2014, 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. * Uses WebFinger to implement remote notice retrieval for GNU social.
  21. *
  22. * Depends on: WebFinger plugin
  23. *
  24. * @package GNUsocial
  25. * @author Mikael Nordfeldth <mmn@hethane.se>
  26. */
  27. if (!defined('GNUSOCIAL')) { exit(1); }
  28. class FetchRemotePlugin extends Plugin
  29. {
  30. static function fetchNoticeFromUrl($url)
  31. {
  32. if (!common_valid_http_url($url)) {
  33. throw new InvalidUrlException($url);
  34. }
  35. $host = parse_url($url, PHP_URL_HOST);
  36. // TODO: try to fetch directly, either by requesting Atom or
  37. // Link headers/<head> elements with rel=alternate and compare
  38. // the remote domain name with the notice URL's.
  39. if (!$stored instanceof Notice) {
  40. common_log(LOG_INFO, 'Could not fetch remote notice from URL: '._ve($url));
  41. throw new ServerException('Could not fetch remote notice.');
  42. }
  43. return $stored;
  44. }
  45. public function onFetchRemoteNoticeWithSource($uri, Profile $source, &$stored)
  46. {
  47. if (common_valid_http_url($uri) && !Event::handle('FetchRemoteNoticeFromUrl', array($url, &$stored))) {
  48. // Woopi, we got it straight from a URL-formatted URI!
  49. return false;
  50. }
  51. // Let's assume we can only do this over HTTPS and a proper
  52. // WebFinger (RFC7033) endpoint on /.well-known/webfinger
  53. try {
  54. $source_url = parse_url($source->getUrl());
  55. } catch (InvalidUrlException $e) {
  56. return true;
  57. }
  58. if ($source_url['scheme'] !== 'https') {
  59. common_debug('Will not try to fetch remote notice from non-HTTPS capable profile source');
  60. return true;
  61. }
  62. try {
  63. $port = isset($source_url['port']) ? ":{$source_url['port']}" : '';
  64. $rfc7033 = "https://{$source_url['host']}{$port}/.well-known/webfinger";
  65. $params = ['resource' => $uri];
  66. common_debug(__METHOD__ . ": getting json data about notice from: {$rfc7033}?resource=$uri");
  67. $json = HTTPClient::quickGetJson($rfc7033, $params);
  68. } catch (Exception $e) {
  69. // NOPE NOPE NOPE NOPE
  70. // couldn't get remote data about this notice's URI
  71. // FIXME: try later?
  72. return true;
  73. }
  74. if (!isset($json->aliases)) {
  75. // FIXME: malformed json for our current use, but maybe we could find rel="alternate" type="text/html"?
  76. return true;
  77. }
  78. common_debug(__METHOD__ . ": Found these aliases: "._ve($json->aliases));
  79. foreach ($json->aliases as $alias) {
  80. try {
  81. $stored = self::fetchNoticeFromUrl($url);
  82. if ($stored instanceof Notice) {
  83. // we're done here! all good, let's get back to business
  84. return false;
  85. }
  86. } catch (InvalidUrlException $e) {
  87. /// mmmmye, aliases might not always be HTTP(S) URLs.
  88. } catch (Exception $e) {
  89. // oh well, try the next one and see if it works better.
  90. common_debug(__METHOD__ . ": {$e->getMessage()}");
  91. }
  92. }
  93. // Nothing found, return true to continue processing the event
  94. return true;
  95. }
  96. public function onPluginVersion(array &$versions)
  97. {
  98. $versions[] = array('name' => 'FetchRemote',
  99. 'version' => GNUSOCIAL_VERSION,
  100. 'author' => 'Mikael Nordfeldth',
  101. 'homepage' => 'http://www.gnu.org/software/social/',
  102. // TRANS: Plugin description.
  103. 'rawdescription' => _m('Retrieves remote notices (and serves local) via WebFinger'));
  104. return true;
  105. }
  106. }