Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
100.00% |
1 / 1 |
|
100.00% |
4 / 4 |
CRAP | |
100.00% |
27 / 27 |
DefaultAuthorizationForm | |
100.00% |
1 / 1 |
|
100.00% |
4 / 4 |
6 | |
100.00% |
27 / 27 |
__construct | |
100.00% |
1 / 1 |
1 | |
100.00% |
4 / 4 |
|||
showForm | |
100.00% |
1 / 1 |
3 | |
100.00% |
18 / 18 |
|||
transformAuthorizationCode | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
setLogger | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
1 | <?php declare(strict_types=1); |
2 | |
3 | namespace Taproot\IndieAuth\Callback; |
4 | |
5 | use BarnabyWalters\Mf2 as M; |
6 | use Psr\Http\Message\ServerRequestInterface; |
7 | use Nyholm\Psr7\Response; |
8 | use Psr\Http\Message\ResponseInterface; |
9 | use Psr\Log\LoggerAwareInterface; |
10 | use Psr\Log\LoggerInterface; |
11 | use Psr\Log\NullLogger; |
12 | |
13 | use function Taproot\IndieAuth\renderTemplate; |
14 | |
15 | /** |
16 | * Default Authorization Form |
17 | * |
18 | * This implementation of `AuthorizationFormInterface` is used by `Server` if the user doesn’t |
19 | * provide one of their own. It presents the user with a simple consent screen, showing any |
20 | * available details about the client app, and allowing the user to grant any requested scopes. |
21 | * |
22 | * When the form is submitted, any granted scopes are then added to the authorization code data. |
23 | * |
24 | * You can customise the authorization template used by passing a path to your own template to |
25 | * the constructor. Refer to the default template `/templates/default_authorization_page.html.php` |
26 | * as a starting point. |
27 | * |
28 | * If you want to add additional form controls (e.g. configurable token lifetimes), as well as |
29 | * making a new template, you’ll need to make a subclass which overrides `transformAuthorizationCode()` |
30 | * to additionally handle your new form data. |
31 | * |
32 | * For any more involved customisation (for example using a templating library of your choice), it |
33 | * may make sense to create your own implementation of `AuthorizationFormInterface`. |
34 | */ |
35 | class DefaultAuthorizationForm implements AuthorizationFormInterface, LoggerAwareInterface { |
36 | /** @var string $csrfKey */ |
37 | public $csrfKey; |
38 | |
39 | /** @var string $formTemplatePath */ |
40 | public $formTemplatePath; |
41 | |
42 | /** @var LoggerInterface $logger */ |
43 | public $logger; |
44 | |
45 | /** |
46 | * Constructor |
47 | * |
48 | * @param string|null $formTemplatePath The path to a custom template. Uses the default if null. |
49 | * @param string|null $csrfKey The key used to retrieve a CSRF token from the request attributes, and as its form data name. Uses the default defined in Server if null. Only change this if you’re using a custom CSRF middleware. |
50 | * @param LoggerInterface|null $logger A logger. |
51 | */ |
52 | public function __construct(?string $formTemplatePath=null, ?string $csrfKey=null, ?LoggerInterface $logger=null) { |
53 | $this->formTemplatePath = $formTemplatePath ?? __DIR__ . '/../../templates/default_authorization_page.html.php'; |
54 | $this->csrfKey = $csrfKey ?? \Taproot\IndieAuth\Server::DEFAULT_CSRF_KEY; |
55 | $this->logger = $logger ?? new NullLogger; |
56 | } |
57 | |
58 | public function showForm(ServerRequestInterface $request, array $authenticationResult, string $formAction, ?array $clientHApp): ResponseInterface { |
59 | // Show an authorization page. List all requested scopes, as this default |
60 | // function has now way of knowing which scopes are supported by the consumer. |
61 | $scopes = []; |
62 | foreach(explode(' ', $request->getQueryParams()['scope'] ?? '') as $s) { |
63 | $scopes[$s] = null; // Ideally there would be a description of the scope here, we don’t have one though. |
64 | } |
65 | |
66 | if (is_null($clientHApp)) { |
67 | $clientHApp = [ |
68 | 'type' => ['h-app'], |
69 | 'properties' => [] |
70 | ]; |
71 | } |
72 | |
73 | $hApp = [ |
74 | 'name' => M\getProp($clientHApp, 'name'), |
75 | 'url' => M\getProp($clientHApp, 'url'), |
76 | 'photo' => M\getProp($clientHApp, 'photo') |
77 | ]; |
78 | |
79 | return new Response(200, ['content-type' => 'text/html'], renderTemplate($this->formTemplatePath, [ |
80 | 'scopes' => $scopes, |
81 | 'user' => $authenticationResult, |
82 | 'formAction' => $formAction, |
83 | 'request' => $request, |
84 | 'clientHApp' => $hApp, |
85 | 'clientId' => $request->getQueryParams()['client_id'], |
86 | 'clientRedirectUri' => $request->getQueryParams()['redirect_uri'], |
87 | 'csrfFormElement' => '<input type="hidden" name="' . htmlentities($this->csrfKey) . '" value="' . htmlentities($request->getAttribute($this->csrfKey)) . '" />' |
88 | ])); |
89 | } |
90 | |
91 | public function transformAuthorizationCode(ServerRequestInterface $request, array $code): array { |
92 | // Add any granted scopes from the form to the code. |
93 | $grantedScopes = $request->getParsedBody()['taproot_indieauth_server_scope'] ?? []; |
94 | |
95 | // This default implementation naievely accepts any scopes it receives from the form. |
96 | // You may wish to perform some sort of validation. |
97 | $code['scope'] = join(' ', $grantedScopes); |
98 | |
99 | // You may wish to additionally make any other necessary changes to the the code based on |
100 | // the form submission, e.g. if the user set a custom token lifetime, or wanted extra data |
101 | // stored on the token to affect how it behaves. |
102 | return $code; |
103 | } |
104 | |
105 | public function setLogger(LoggerInterface $logger) { |
106 | $this->logger = $logger; |
107 | } |
108 | } |