@@ -41,9 +41,3 @@ MESSENGER_TRANSPORT_DSN_HIGH=doctrine://default?queue_name=high | |||
MESSENGER_TRANSPORT_DSN_LOW=doctrine://default?queue_name=low | |||
# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages | |||
###< symfony/messenger ### | |||
###> trikoder/oauth2-bundle ### | |||
# Fallback OAuth2 encryption key | |||
# Please override this with a secure value: https://oauth2.thephpleague.com/installation/#string-password | |||
OAUTH2_ENCRYPTION_KEY=6cfc355e274dc909f82730c8741eb1e0 | |||
###< trikoder/oauth2-bundle ### |
@@ -21,7 +21,4 @@ return [ | |||
SymfonyCasts\Bundle\ResetPassword\SymfonyCastsResetPasswordBundle::class => ['all' => true], | |||
Knp\Bundle\TimeBundle\KnpTimeBundle::class => ['all' => true], | |||
Fidry\PsyshBundle\PsyshBundle::class => ['all' => true], | |||
Trikoder\Bundle\OAuth2Bundle\TrikoderOAuth2Bundle::class => ['all' => true], | |||
Ajgarlag\Bundle\PsrHttpMessageBundle\AjgarlagPsrHttpMessageBundle::class => ['all' => true], | |||
SymfonyBundles\JsonRequestBundle\JsonRequestBundle::class => ['all' => true], | |||
]; |
@@ -31,9 +31,7 @@ security: | |||
pattern: ^/api/ | |||
security: true | |||
stateless: true | |||
guard: | |||
authenticators: | |||
- Trikoder\Bundle\OAuth2Bundle\Security\Guard\Authenticator\OAuth2Authenticator | |||
main: | |||
entry_point: App\Security\Authenticator | |||
guard: | |||
@@ -1,32 +0,0 @@ | |||
trikoder_oauth2: | |||
authorization_server: | |||
private_key: '%kernel.project_dir%/var/oauth/private.key' | |||
private_key_passphrase: null # Passphrase of the private key, if any | |||
encryption_key: '%env(string:OAUTH2_ENCRYPTION_KEY)%' # (Optional) Change this | |||
grant_types: | |||
authorization_code: | |||
enable: true | |||
client_credentials: | |||
enable: true | |||
implicit: | |||
enable: true | |||
password: | |||
enable: true | |||
refresh_token: | |||
enable: true | |||
resource_server: | |||
public_key: '%kernel.project_dir%/var/oauth/public.key' | |||
persistence: | |||
doctrine: null | |||
# Scopes that you wish to utilize in your application. | |||
# This should be a simple array of strings. | |||
scopes: | |||
- read | |||
- write | |||
- follow |
@@ -1,7 +0,0 @@ | |||
oauth2_authorization_code: | |||
controller: Trikoder\Bundle\OAuth2Bundle\Controller\AuthorizationController::indexAction | |||
path: '/oauth/authorize' | |||
oauth2_token: | |||
controller: Trikoder\Bundle\OAuth2Bundle\Controller\TokenController::indexAction | |||
path: '/oauth/token' |
@@ -0,0 +1,85 @@ | |||
<?php | |||
declare(strict_types = 1); | |||
// {{{ License | |||
// This file is part of GNU social - https://www.gnu.org/software/social | |||
// | |||
// GNU social 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. | |||
// | |||
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>. | |||
// }}} | |||
/** | |||
* ActivityPub implementation for GNU social | |||
* | |||
* @package OAuth2 | |||
* @category API | |||
* | |||
* @author Diogo Peralta Cordeiro <@diogo.site> | |||
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org | |||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later | |||
*/ | |||
namespace Plugin\IndieAuth\Controller; | |||
use App\Core\Controller; | |||
use App\Core\DB\DB; | |||
use App\Core\Log; | |||
use App\Util\Common; | |||
use Plugin\IndieAuth\Entity\OAuth2Client; | |||
use Symfony\Component\HttpFoundation\JsonResponse; | |||
/** | |||
* App Management Endpoint | |||
* | |||
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org | |||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later | |||
*/ | |||
class Apps extends Controller | |||
{ | |||
public function onPost(): JsonResponse | |||
{ | |||
Log::debug('OAuth2 Apps: Received a POST request.'); | |||
Log::debug('OAuth2 Apps: Request content: ', [$body = $this->request->getContent()]); | |||
$args = json_decode($body, true); | |||
$identifier = hash('md5', random_bytes(16)); | |||
// Random string Length should be between 43 and 128 | |||
$secret = Common::base64url_encode(hash('sha256', random_bytes(57))); | |||
DB::persist($app = OAuth2Client::create([ | |||
'identifier' => $identifier, | |||
'secret' => $secret, | |||
'redirect_uris' => $args['redirect_uris'], | |||
'grants' => 'client_credentials authorization_code', | |||
'scopes' => $args['scopes'], | |||
'active' => true, | |||
'allow_plain_text_pkce' => false, | |||
'client_name' => $args['client_name'], | |||
'website' => $args['website'], | |||
])); | |||
Log::debug('OAuth2 Apps: Created App: ', [$app]); | |||
DB::flush(); | |||
// Success | |||
return new JsonResponse([ | |||
'name' => $app->getClientName(), | |||
'website' => $app->getWebsite(), | |||
'redirect_uri' => $app->getRedirectUris()[0], | |||
'client_id' => $app->getIdentifier(), | |||
'client_secret' => $app->getSecret(), | |||
], status: 200, headers: ['content_type' => 'application/json; charset=utf-8']); | |||
} | |||
} |
@@ -0,0 +1,70 @@ | |||
<?php | |||
declare(strict_types = 1); | |||
// {{{ License | |||
// This file is part of GNU social - https://www.gnu.org/software/social | |||
// | |||
// GNU social 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. | |||
// | |||
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>. | |||
// }}} | |||
/** | |||
* ActivityPub implementation for GNU social | |||
* | |||
* @package OAuth2 | |||
* @category API | |||
* | |||
* @author Diogo Peralta Cordeiro <@diogo.site> | |||
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org | |||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later | |||
*/ | |||
namespace Plugin\IndieAuth\Controller; | |||
use App\Core\Controller; | |||
use Nyholm\Psr7\Factory\Psr17Factory; | |||
use Plugin\IndieAuth\IndieAuth; | |||
use Psr\Http\Message\ResponseInterface; | |||
use Psr\Http\Message\ServerRequestInterface; | |||
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory; | |||
use Symfony\Component\HttpFoundation\RequestStack; | |||
/** | |||
* App Management Endpoint | |||
* | |||
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org | |||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later | |||
*/ | |||
class OAuth2 extends Controller | |||
{ | |||
private ServerRequestInterface $psrRequest; | |||
public function __construct(RequestStack $requestStack) | |||
{ | |||
parent::__construct($requestStack); | |||
$psr17Factory = new Psr17Factory(); | |||
$psrHttpFactory = new PsrHttpFactory($psr17Factory, $psr17Factory, $psr17Factory, $psr17Factory); | |||
$this->psrRequest = $psrHttpFactory->createRequest($this->request); | |||
} | |||
public function handleAuthorizationEndpointRequest(): ResponseInterface | |||
{ | |||
return IndieAuth::$server->handleAuthorizationEndpointRequest($this->psrRequest); | |||
} | |||
public function handleTokenEndpointRequest(): ResponseInterface | |||
{ | |||
return IndieAuth::$server->handleTokenEndpointRequest($this->psrRequest); | |||
} | |||
} |
@@ -0,0 +1,225 @@ | |||
<?php | |||
declare(strict_types = 1); | |||
// {{{ License | |||
// This file is part of GNU social - https://www.gnu.org/software/social | |||
// | |||
// GNU social 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. | |||
// | |||
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>. | |||
// }}} | |||
/** | |||
* ActivityPub implementation for GNU social | |||
* | |||
* @package GNUsocial | |||
* @category OAuth2 | |||
* | |||
* @author Diogo Peralta Cordeiro <@diogo.site> | |||
* @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org | |||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later | |||
*/ | |||
namespace Plugin\IndieAuth\Entity; | |||
use App\Core\Entity; | |||
use DateTimeInterface; | |||
/** | |||
* OAuth application registration record | |||
* | |||
* @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org | |||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later | |||
*/ | |||
class OAuth2Client extends Entity | |||
{ | |||
// {{{ Autocode | |||
// @codeCoverageIgnoreStart | |||
private string $identifier; | |||
private ?string $secret; | |||
private string $redirect_uris = ''; | |||
private string $grants = ''; | |||
private string $scopes = ''; | |||
private bool $active = true; | |||
private bool $allow_plain_text_pkce = false; | |||
private ?string $client_name = null; | |||
private ?string $website = null; | |||
private DateTimeInterface $created; | |||
private DateTimeInterface $modified; | |||
public function __toString(): string | |||
{ | |||
return $this->getIdentifier(); | |||
} | |||
public function getIdentifier(): string | |||
{ | |||
return $this->identifier; | |||
} | |||
public function getSecret(): ?string | |||
{ | |||
return $this->secret; | |||
} | |||
public function setSecret(?string $secret): self | |||
{ | |||
$this->secret = $secret; | |||
return $this; | |||
} | |||
public function getRedirectUris(): array | |||
{ | |||
return explode(' ', $this->redirect_uris); | |||
} | |||
public function setRedirectUris(string ...$redirect_uris): self | |||
{ | |||
$this->redirect_uris = implode(' ', $redirect_uris); | |||
return $this; | |||
} | |||
public function getGrants(): array | |||
{ | |||
return explode(' ', $this->grants); | |||
} | |||
public function setGrants(string ...$grants): self | |||
{ | |||
$this->grants = implode(' ', $grants); | |||
return $this; | |||
} | |||
public function getScopes(): array | |||
{ | |||
return explode(' ', $this->scopes); | |||
} | |||
public function setScopes(string ...$scopes): self | |||
{ | |||
$this->scopes = implode(' ', $scopes); | |||
return $this; | |||
} | |||
public function isActive(): bool | |||
{ | |||
return $this->active; | |||
} | |||
public function setActive(bool $active): self | |||
{ | |||
$this->active = $active; | |||
return $this; | |||
} | |||
public function isConfidential(): bool | |||
{ | |||
return !empty($this->secret); | |||
} | |||
public function isPlainTextPkceAllowed(): bool | |||
{ | |||
return $this->allow_plain_text_pkce; | |||
} | |||
public function setAllowPlainTextPkce(bool $allow_plain_text_pkce): self | |||
{ | |||
$this->allow_plain_text_pkce = $allow_plain_text_pkce; | |||
return $this; | |||
} | |||
public function setIdentifier(string $identifier): self | |||
{ | |||
$this->identifier = $identifier; | |||
return $this; | |||
} | |||
public function getClientName(): string | |||
{ | |||
return $this->client_name; | |||
} | |||
public function setClientName(string $client_name): self | |||
{ | |||
$this->client_name = $client_name; | |||
return $this; | |||
} | |||
public function getWebsite(): ?string | |||
{ | |||
return $this->website; | |||
} | |||
public function setWebsite(?string $website): self | |||
{ | |||
$this->website = $website; | |||
return $this; | |||
} | |||
public function setCreated(DateTimeInterface $created): self | |||
{ | |||
$this->created = $created; | |||
return $this; | |||
} | |||
public function getCreated(): DateTimeInterface | |||
{ | |||
return $this->created; | |||
} | |||
public function setModified(DateTimeInterface $modified): self | |||
{ | |||
$this->modified = $modified; | |||
return $this; | |||
} | |||
public function getModified(): DateTimeInterface | |||
{ | |||
return $this->modified; | |||
} | |||
// @codeCoverageIgnoreEnd | |||
// }}} Autocode | |||
/** | |||
* Return table definition for Schema setup and Entity usage. | |||
* | |||
* @return array array of column definitions | |||
*/ | |||
public static function schemaDef(): array | |||
{ | |||
return [ | |||
'name' => 'oauth2_client', | |||
'fields' => [ | |||
'identifier' => ['type' => 'varchar', 'length' => 32, 'not null' => true, 'description' => 'foreign key to oauth2_client->identifier'], | |||
'secret' => ['type' => 'varchar', 'length' => 128, 'not null' => false, 'description' => 'foreign key to oauth2_client->identifier'], | |||
'client_name' => ['type' => 'varchar', 'length' => 191, 'not null' => false, 'description' => 'name of the application'], | |||
'redirect_uris' => ['type' => 'text', 'not null' => false, 'description' => 'application homepage - used for source link'], | |||
'grants' => ['type' => 'text', 'not null' => true, 'default' => '', 'description' => 'application homepage - used for source link'], | |||
'scopes' => ['type' => 'text', 'not null' => true, 'default' => '', 'description' => 'application homepage - used for source link'], | |||
'active' => ['type' => 'bool', 'not null' => true, 'description' => 'was this note generated by a local actor'], | |||
'allow_plain_text_pkce' => ['type' => 'bool', 'not null' => true, 'default' => false, 'description' => 'was this note generated by a local actor'], | |||
'website' => ['type' => 'text', 'not null' => false, 'description' => 'application homepage - used for source link'], | |||
'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'], | |||
'modified' => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'], | |||
], | |||
'primary key' => ['identifier'], | |||
]; | |||
} | |||
} |
@@ -30,21 +30,19 @@ declare(strict_types = 1); | |||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later | |||
*/ | |||
namespace Plugin\OAuth2; | |||
namespace Plugin\IndieAuth; | |||
use App\Core\Event; | |||
use App\Core\Log; | |||
use App\Core\Modules\Plugin; | |||
use App\Core\Router\RouteLoader; | |||
use App\Core\Router\Router; | |||
use App\Util\Common; | |||
use App\Util\Exception\NoLoggedInUser; | |||
use Nyholm\Psr7\Response; | |||
use Plugin\OAuth2\Controller\Apps; | |||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | |||
use Trikoder\Bundle\OAuth2Bundle\Event\AuthorizationRequestResolveEvent; | |||
use Trikoder\Bundle\OAuth2Bundle\Event\UserResolveEvent; | |||
use Trikoder\Bundle\OAuth2Bundle\Model\Grant; | |||
use Trikoder\Bundle\OAuth2Bundle\OAuth2Events; | |||
use Plugin\IndieAuth\Controller\Apps; | |||
use Plugin\IndieAuth\Controller\OAuth2; | |||
use Psr\Http\Message\ServerRequestInterface; | |||
use Taproot\IndieAuth\Server; | |||
use XML_XRD_Element_Link; | |||
/** | |||
@@ -53,12 +51,39 @@ use XML_XRD_Element_Link; | |||
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org | |||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later | |||
*/ | |||
class OAuth2 extends Plugin implements EventSubscriberInterface | |||
class IndieAuth extends Plugin | |||
{ | |||
public const OAUTH_ACCESS_TOKEN_REL = 'http://apinamespace.org/oauth/access_token'; | |||
public const OAUTH_REQUEST_TOKEN_REL = 'http://apinamespace.org/oauth/request_token'; | |||
public const OAUTH_AUTHORIZE_REL = 'http://apinamespace.org/oauth/authorize'; | |||
public static Server $server; | |||
public function onInitializePlugin() | |||
{ | |||
self::$server = new Server([ | |||
'secret' => 'YOUR_APP_INDIEAUTH_SECRET$config["secret"] must be a string with a minimum length of 64 characters.yeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', | |||
'logger' => Log::getLogger(), | |||
'requirePKCE' => false, | |||
// A path to store token data, or an object implementing TokenStorageInterface. | |||
'tokenStorage' => '/../data/auth_tokens/', | |||
// An authentication callback function, which either returns data about the current user, | |||
// or redirects to/implements an authentication flow. | |||
'authenticationHandler' => function (ServerRequestInterface $request, string $authenticationRedirect, ?string $normalizedMeUrl) { | |||
// If the request is authenticated, return an array with a `me` key containing the | |||
// canonical URL of the currently logged-in user. | |||
if ($actor = Common::actor()) { | |||
return ['me' => $actor->getUri(Router::ABSOLUTE_URL)]; | |||
} | |||
// Otherwise, redirect the user to a login page, ensuring that they will be redirected | |||
// back to the IndieAuth flow with query parameters intact once logged in. | |||
return new Response(302, ['Location' => Router::url('security_login') . '?returnUrl=' . urlencode($authenticationRedirect)]); | |||
}, | |||
]); | |||
} | |||
public function version(): string | |||
{ | |||
return '3.0.0'; | |||
@@ -78,6 +103,19 @@ class OAuth2 extends Plugin implements EventSubscriberInterface | |||
Apps::class, | |||
['http-methods' => ['POST']], | |||
); | |||
$r->connect( | |||
'oauth2_authorization_code', | |||
'/oauth/authorize', | |||
[OAuth2::class, 'handleAuthorizationEndpointRequest'], | |||
); | |||
$r->connect( | |||
'oauth2_token', | |||
'/oauth/token', | |||
[OAuth2::class, 'handleTokenEndpointRequest'], | |||
); | |||
return Event::next; | |||
} | |||
@@ -88,40 +126,4 @@ class OAuth2 extends Plugin implements EventSubscriberInterface | |||
$links[] = new XML_XRD_Element_link(self::OAUTH_ACCESS_TOKEN_REL, Router::url('oauth2_token', type: Router::ABSOLUTE_URL)); | |||
return Event::next; | |||
} | |||
public function userResolve(UserResolveEvent $event): void | |||
{ | |||
$user = Common::user(); | |||
if (\is_null($user)) { | |||
return; | |||
} | |||
$event->setUser($user); | |||
} | |||
public function authorizeRequestResolve(AuthorizationRequestResolveEvent $event): void | |||
{ | |||
$request = Common::getRequest(); | |||
try { | |||
$user = Common::ensureLoggedIn(); | |||
$event->setUser($user); | |||
$event->resolveAuthorization(AuthorizationRequestResolveEvent::AUTHORIZATION_APPROVED); | |||
$event->getClient()->setGrants(new Grant('client_credentials'), new Grant('authorization_code')); | |||
} catch (NoLoggedInUser) { | |||
$event->setResponse(new Response(302, [ | |||
'Location' => Router::url('security_login', [ | |||
'returnUrl' => $request->getUri(), | |||
]), | |||
])); | |||
} | |||
} | |||
public static function getSubscribedEvents(): array | |||
{ | |||
return [ | |||
OAuth2Events::USER_RESOLVE => 'userResolve', | |||
OAuth2Events::AUTHORIZATION_REQUEST_RESOLVE => 'authorizeRequestResolve', | |||
]; | |||
} | |||
} |
@@ -0,0 +1,7 @@ | |||
{ | |||
"require": { | |||
"nyholm/psr7": "^1.4", | |||
"symfony/psr-http-message-bridge": "^2.1", | |||
"taproot/indieauth": "^0.1.0" | |||
} | |||
} |
@@ -1,106 +0,0 @@ | |||
<?php | |||
declare(strict_types = 1); | |||
// {{{ License | |||
// This file is part of GNU social - https://www.gnu.org/software/social | |||
// | |||
// GNU social 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. | |||
// | |||
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>. | |||
// }}} | |||
/** | |||
* ActivityPub implementation for GNU social | |||
* | |||
* @package OAuth2 | |||
* @category API | |||
* | |||
* @author Diogo Peralta Cordeiro <@diogo.site> | |||
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org | |||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later | |||
*/ | |||
namespace Plugin\OAuth2\Controller; | |||
use App\Core\Controller; | |||
use App\Core\DB\DB; | |||
use App\Core\Log; | |||
use App\Util\Common; | |||
use Plugin\OAuth2\Entity\OAuth2ClientMeta; | |||
use Symfony\Component\HttpFoundation\JsonResponse; | |||
use Trikoder\Bundle\OAuth2Bundle\Model\Client; | |||
use Trikoder\Bundle\OAuth2Bundle\Model\Grant; | |||
use Trikoder\Bundle\OAuth2Bundle\Model\RedirectUri; | |||
use Trikoder\Bundle\OAuth2Bundle\Model\Scope; | |||
/** | |||
* App Management Endpoint | |||
* | |||
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org | |||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later | |||
*/ | |||
class Apps extends Controller | |||
{ | |||
public function onPost(): JsonResponse | |||
{ | |||
Log::debug('OAuth2 Apps: Received a POST request.'); | |||
Log::debug('OAuth2 Apps: Request content: ', [$body = $this->request->getContent()]); | |||
$args = json_decode($body, true); | |||
$identifier = hash('md5', random_bytes(16)); // Random string Length should be between 43 and 128 | |||
$secret = Common::base64url_encode(hash('sha256', random_bytes(57))); | |||
$client = new Client($identifier, $secret); | |||
$client->setActive(true); | |||
$client->setAllowPlainTextPkce(false); | |||
$redirectUris = array_map( | |||
static fn (string $redirectUri): RedirectUri => new RedirectUri($redirectUri), | |||
explode(' ', $args['redirect_uris']), | |||
); | |||
$client->setRedirectUris(...$redirectUris); | |||
$client->setGrants(new Grant('client_credentials')); | |||
$scopes = array_map( | |||
static fn (string $scope): Scope => new Scope($scope), | |||
explode(' ', $args['scopes']), | |||
); | |||
$client->setScopes(...$scopes); | |||
DB::persist($client); | |||
DB::persist($additional_meta = OAuth2ClientMeta::create([ | |||
'identifier' => $client->getIdentifier(), | |||
'client_name' => $args['client_name'], | |||
'website' => $args['website'], | |||
])); | |||
Log::debug('OAuth2 Apps: Created App: ', [$client, $additional_meta]); | |||
$app_meta = [ | |||
'id' => (string) $additional_meta->getId(), | |||
'name' => $additional_meta->getClientName(), | |||
'website' => $additional_meta->getWebsite(), | |||
'redirect_uri' => (string) $client->getRedirectUris()[0], | |||
'client_id' => $client->getIdentifier(), | |||
'client_secret' => $client->getSecret(), | |||
]; | |||
Log::debug('OAuth2 Apps: Create App Meta: ', [$app_meta]); | |||
DB::flush(); | |||
// Success | |||
return new JsonResponse($app_meta, status: 200, headers: ['content_type' => 'application/json; charset=utf-8']); | |||
} | |||
} |
@@ -1,144 +0,0 @@ | |||
<?php | |||
declare(strict_types = 1); | |||
// {{{ License | |||
// This file is part of GNU social - https://www.gnu.org/software/social | |||
// | |||
// GNU social 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. | |||
// | |||
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>. | |||
// }}} | |||
/** | |||
* ActivityPub implementation for GNU social | |||
* | |||
* @package GNUsocial | |||
* @category OAuth2 | |||
* | |||
* @author Diogo Peralta Cordeiro <@diogo.site> | |||
* @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org | |||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later | |||
*/ | |||
namespace Plugin\OAuth2\Entity; | |||
use App\Core\Entity; | |||
use DateTimeInterface; | |||
/** | |||
* OAuth application registration record | |||
* | |||
* @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org | |||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later | |||
*/ | |||
class OAuth2ClientMeta extends Entity | |||
{ | |||
// {{{ Autocode | |||
// @codeCoverageIgnoreStart | |||
private int $id; | |||
private string $identifier; | |||
private string $client_name; | |||
private ?string $website = null; | |||
private DateTimeInterface $created; | |||
private DateTimeInterface $modified; | |||
public function getId(): int | |||
{ | |||
return $this->id; | |||
} | |||
public function setId(int $id): self | |||
{ | |||
$this->id = $id; | |||
return $this; | |||
} | |||
public function getIdentifier(): string | |||
{ | |||
return $this->identifier; | |||
} | |||
public function setIdentifier(string $identifier): self | |||
{ | |||
$this->identifier = $identifier; | |||
return $this; | |||
} | |||
public function getClientName(): string | |||
{ | |||
return $this->client_name; | |||
} | |||
public function setClientName(string $client_name): self | |||
{ | |||
$this->client_name = $client_name; | |||
return $this; | |||
} | |||
public function getWebsite(): ?string | |||
{ | |||
return $this->website; | |||
} | |||
public function setWebsite(?string $website): self | |||
{ | |||
$this->website = $website; | |||
return $this; | |||
} | |||
public function setCreated(DateTimeInterface $created): self | |||
{ | |||
$this->created = $created; | |||
return $this; | |||
} | |||
public function getCreated(): DateTimeInterface | |||
{ | |||
return $this->created; | |||
} | |||
public function setModified(DateTimeInterface $modified): self | |||
{ | |||
$this->modified = $modified; | |||
return $this; | |||
} | |||
public function getModified(): DateTimeInterface | |||
{ | |||
return $this->modified; | |||
} | |||
// @codeCoverageIgnoreEnd | |||
// }}} Autocode | |||
/** | |||
* Return table definition for Schema setup and Entity usage. | |||
* | |||
* @return array array of column definitions | |||
*/ | |||
public static function schemaDef(): array | |||
{ | |||
return [ | |||
'name' => 'oauth2_client_meta', | |||
'fields' => [ | |||
'id' => ['type' => 'serial', 'not null' => true, 'description' => 'unique identifier'], | |||
'identifier' => ['type' => 'varchar', 'length' => 32, 'description' => 'foreign key to oauth2_client->identifier'], | |||
'client_name' => ['type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'name of the application'], | |||
'website' => ['type' => 'text', 'not null' => false, 'description' => 'application homepage - used for source link'], | |||
'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'], | |||
'modified' => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'], | |||
], | |||
'primary key' => ['id'], | |||
]; | |||
} | |||
} |
@@ -1,7 +0,0 @@ | |||
{ | |||
"require": { | |||
"nyholm/psr7": "*", | |||
"symfony-bundles/json-request-bundle": "^4.1", | |||
"trikoder/oauth2-bundle": "v3.x-dev" | |||
} | |||
} |
@@ -58,6 +58,11 @@ abstract class Log | |||
self::$logger = $l; | |||
} | |||
public static function getLogger(): LoggerInterface | |||
{ | |||
return self::$logger; | |||
} | |||
/** | |||
* Log a critical error when a really unexpected exception occured. This indicates a bug in the software | |||
* | |||
@@ -1,10 +1,10 @@ | |||
{ | |||
"ajgarlag/psr-http-message-bundle": { | |||
"version": "1.2.1" | |||
}, | |||
"alchemy/binary-driver": { | |||
"version": "v5.2.0" | |||
}, | |||
"barnabywalters/mf-cleaner": { | |||
"version": "v0.1.4" | |||
}, | |||
"behat/gherkin": { | |||
"version": "v4.9.0" | |||
}, | |||
@@ -68,8 +68,8 @@ | |||
"composer/xdebug-handler": { | |||
"version": "1.4.6" | |||
}, | |||
"defuse/php-encryption": { | |||
"version": "v2.3.1" | |||
"dflydev/fig-cookies": { | |||
"version": "v3.0.0" | |||
}, | |||
"doctrine/annotations": { | |||
"version": "1.0", | |||
@@ -208,6 +208,15 @@ | |||
"guzzlehttp/psr7": { | |||
"version": "2.1.0" | |||
}, | |||
"indieauth/client": { | |||
"version": "1.1.5" | |||
}, | |||
"indieweb/link-rel-parser": { | |||
"version": "0.1.3" | |||
}, | |||
"indieweb/representative-h-card": { | |||
"version": "0.1.2" | |||
}, | |||
"jchook/phpunit-assert-throws": { | |||
"version": "v1.0.3" | |||
}, | |||
@@ -229,18 +238,6 @@ | |||
"landrok/activitypub": { | |||
"version": "0.5.6" | |||
}, | |||
"lcobucci/clock": { | |||
"version": "2.1.0" | |||
}, | |||
"lcobucci/jwt": { | |||
"version": "4.1.5" | |||
}, | |||
"league/event": { | |||
"version": "2.2.0" | |||
}, | |||
"league/oauth2-server": { | |||
"version": "8.3.3" | |||
}, | |||
"league/uri-parser": { | |||
"version": "1.4.1" | |||
}, | |||
@@ -301,6 +298,9 @@ | |||
"oscarotero/html-parser": { | |||
"version": "v0.1.6" | |||
}, | |||
"p3k/http": { | |||
"version": "0.1.12" | |||
}, | |||
"paragonie/constant_time_encoding": { | |||
"version": "v2.4.0" | |||
}, | |||
@@ -390,6 +390,12 @@ | |||
"psr/http-message": { | |||
"version": "1.0.1" | |||
}, | |||
"psr/http-server-handler": { | |||
"version": "1.0.1" | |||
}, | |||
"psr/http-server-middleware": { | |||
"version": "1.0.1" | |||
}, | |||
"psr/link": { | |||
"version": "1.1.1" | |||
}, | |||
@@ -468,9 +474,6 @@ | |||
"someonewithpc/redis-polyfill": { | |||
"version": "dev-master" | |||
}, | |||
"symfony-bundles/json-request-bundle": { | |||
"version": "4.1.1" | |||
}, | |||
"symfony/amqp-messenger": { | |||
"version": "v5.4.0" | |||
}, | |||
@@ -868,6 +871,9 @@ | |||
"symfonycasts/verify-email-bundle": { | |||
"version": "v1.3.0" | |||
}, | |||
"taproot/indieauth": { | |||
"version": "v0.1.0" | |||
}, | |||
"tgalopin/html-sanitizer": { | |||
"version": "1.4.0" | |||
}, | |||
@@ -886,19 +892,6 @@ | |||
"theseer/tokenizer": { | |||
"version": "1.2.0" | |||
}, | |||
"trikoder/oauth2-bundle": { | |||
"version": "3.2", | |||
"recipe": { | |||
"repo": "github.com/symfony/recipes-contrib", | |||
"branch": "master", | |||
"version": "3.0", | |||
"ref": "43774de114904e86d18de0cea92f368d8e3c7499" | |||
}, | |||
"files": [ | |||
"config/packages/trikoder_oauth2.yaml", | |||
"config/routes/trikoder_oauth2.yaml" | |||
] | |||
}, | |||
"twig/extra-bundle": { | |||
"version": "v3.3.0" | |||
}, | |||
@@ -923,6 +916,9 @@ | |||
"webmozart/assert": { | |||
"version": "1.10.0" | |||
}, | |||
"webmozart/path-util": { | |||
"version": "2.3.0" | |||
}, | |||
"wikimedia/composer-merge-plugin": { | |||
"version": "v2.0.1" | |||
}, | |||