IndieAuth.php 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. <?php
  2. declare(strict_types = 1);
  3. // {{{ License
  4. // This file is part of GNU social - https://www.gnu.org/software/social
  5. //
  6. // GNU social 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. // GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
  18. // }}}
  19. /**
  20. * ActivityPub implementation for GNU social
  21. *
  22. * @package GNUsocial
  23. * @category API
  24. *
  25. * @author Diogo Peralta Cordeiro <@diogo.site>
  26. * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
  27. * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
  28. */
  29. namespace Plugin\IndieAuth;
  30. use App\Core\Event;
  31. use App\Core\Log;
  32. use App\Core\Modules\Plugin;
  33. use App\Core\Router\RouteLoader;
  34. use App\Core\Router\Router;
  35. use App\Util\Common;
  36. use Nyholm\Psr7\Response;
  37. use Plugin\IndieAuth\Controller\Apps;
  38. use Plugin\IndieAuth\Controller\OAuth2;
  39. use Psr\Http\Message\ServerRequestInterface;
  40. use Taproot\IndieAuth\Server;
  41. use XML_XRD_Element_Link;
  42. /**
  43. * Adds OAuth2 support to GNU social when enabled
  44. *
  45. * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
  46. * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
  47. */
  48. class IndieAuth extends Plugin
  49. {
  50. public const OAUTH_ACCESS_TOKEN_REL = 'http://apinamespace.org/oauth/access_token';
  51. public const OAUTH_REQUEST_TOKEN_REL = 'http://apinamespace.org/oauth/request_token';
  52. public const OAUTH_AUTHORIZE_REL = 'http://apinamespace.org/oauth/authorize';
  53. public static Server $server;
  54. public function onInitializePlugin()
  55. {
  56. self::$server = new Server([
  57. 'secret' => 'YOUR_APP_INDIEAUTH_SECRET$config["secret"] must be a string with a minimum length of 64 characters.yeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
  58. 'logger' => Log::getLogger(),
  59. 'requirePKCE' => false,
  60. // A path to store token data, or an object implementing TokenStorageInterface.
  61. 'tokenStorage' => '/../data/auth_tokens/',
  62. // An authentication callback function, which either returns data about the current user,
  63. // or redirects to/implements an authentication flow.
  64. 'authenticationHandler' => function (ServerRequestInterface $request, string $authenticationRedirect, ?string $normalizedMeUrl) {
  65. // If the request is authenticated, return an array with a `me` key containing the
  66. // canonical URL of the currently logged-in user.
  67. if ($actor = Common::actor()) {
  68. return ['me' => $actor->getUri(Router::ABSOLUTE_URL)];
  69. }
  70. // Otherwise, redirect the user to a login page, ensuring that they will be redirected
  71. // back to the IndieAuth flow with query parameters intact once logged in.
  72. return new Response(302, ['Location' => Router::url('security_login') . '?returnUrl=' . urlencode($authenticationRedirect)]);
  73. },
  74. ]);
  75. }
  76. public function version(): string
  77. {
  78. return '3.0.0';
  79. }
  80. /**
  81. * This code executes when GNU social creates the page routing, and we hook
  82. * on this event to add our Inbox and Outbox handler for ActivityPub.
  83. *
  84. * @param RouteLoader $r the router that was initialized
  85. */
  86. public function onAddRoute(RouteLoader $r): bool
  87. {
  88. $r->connect(
  89. 'oauth2_apps',
  90. '/api/v1/apps',
  91. Apps::class,
  92. ['http-methods' => ['POST']],
  93. );
  94. $r->connect(
  95. 'oauth2_authorization_code',
  96. '/oauth/authorize',
  97. [OAuth2::class, 'handleAuthorizationEndpointRequest'],
  98. );
  99. $r->connect(
  100. 'oauth2_token',
  101. '/oauth/token',
  102. [OAuth2::class, 'handleTokenEndpointRequest'],
  103. );
  104. return Event::next;
  105. }
  106. public function onEndHostMetaLinks(array &$links): bool
  107. {
  108. $links[] = new XML_XRD_Element_link(self::OAUTH_REQUEST_TOKEN_REL, Router::url('oauth2_apps', type: Router::ABSOLUTE_URL));
  109. $links[] = new XML_XRD_Element_link(self::OAUTH_AUTHORIZE_REL, Router::url('oauth2_authorize', type: Router::ABSOLUTE_URL));
  110. $links[] = new XML_XRD_Element_link(self::OAUTH_ACCESS_TOKEN_REL, Router::url('oauth2_token', type: Router::ABSOLUTE_URL));
  111. return Event::next;
  112. }
  113. }