WebFingerEndpoint::getResource()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 6
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * The MIT License (MIT)
7
 *
8
 * Copyright (c) 2014-2019 Spomky-Labs
9
 *
10
 * This software may be modified and distributed under the terms
11
 * of the MIT license.  See the LICENSE file for details.
12
 */
13
14
namespace OAuth2Framework\Component\WebFingerEndpoint;
15
16
use Assert\Assertion;
17
use OAuth2Framework\Component\WebFingerEndpoint\IdentifierResolver\Identifier;
18
use OAuth2Framework\Component\WebFingerEndpoint\IdentifierResolver\IdentifierResolverManager;
19
use Psr\Http\Message\ResponseFactoryInterface;
20
use Psr\Http\Message\ResponseInterface;
21
use Psr\Http\Message\ServerRequestInterface;
22
use Psr\Http\Server\MiddlewareInterface;
23
use Psr\Http\Server\RequestHandlerInterface;
24
use function Safe\json_encode;
25
use function Safe\sprintf;
26
27
final class WebFingerEndpoint implements MiddlewareInterface
28
{
29
    /**
30
     * @var ResponseFactoryInterface
31
     */
32
    private $responseFactory;
33
34
    /**
35
     * @var IdentifierResolverManager
36
     */
37
    private $identifierResolverManager;
38
39
    /**
40
     * @var ResourceRepository
41
     */
42
    private $resourceRepository;
43
44
    public function __construct(ResponseFactoryInterface $responseFactory, ResourceRepository $resourceRepository, IdentifierResolverManager $identifierResolverManager)
45
    {
46
        $this->resourceRepository = $resourceRepository;
47
        $this->responseFactory = $responseFactory;
48
        $this->identifierResolverManager = $identifierResolverManager;
49
    }
50
51
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
52
    {
53
        try {
54
            $resource = $this->getResource($request);
55
            $identifier = $this->getIdentifier($resource);
56
            $resourceDescriptor = $this->resourceRepository->find($resource, $identifier);
57
            Assertion::notNull($resourceDescriptor, sprintf('The resource identified with "%s" does not exist or is not supported by this server.', $resource));
58
59
            $filteredResourceDescriptor = $this->filterLinks($request, $resourceDescriptor);
60
            $response = $this->responseFactory->createResponse(200);
61
            $headers = [
62
                'Content-Type' => 'application/jrd+json; charset=UTF-8',
63
            ];
64
            $response->getBody()->write(json_encode($filteredResourceDescriptor, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
65
        } catch (\InvalidArgumentException $e) {
66
            $response = $this->responseFactory->createResponse(400);
67
            $headers = [
68
                'Content-Type' => 'application/json; charset=UTF-8',
69
            ];
70
            $response->getBody()->write(json_encode(['error' => 'invalid_request', 'error_description' => $e->getMessage()], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
71
        }
72
        foreach ($headers as $k => $v) {
73
            $response = $response->withHeader($k, $v);
74
        }
75
76
        return $response;
77
    }
78
79
    private function getIdentifier(string $resource): Identifier
80
    {
81
        try {
82
            return $this->identifierResolverManager->resolve($resource);
83
        } catch (\Throwable $e) {
84
            throw new \InvalidArgumentException(sprintf('The resource identified with "%s" does not exist or is not supported by this server.', $resource), 400, $e);
85
        }
86
    }
87
88
    private function getResource(ServerRequestInterface $request): string
89
    {
90
        $query_params = $request->getQueryParams() ?? [];
91
        Assertion::keyExists($query_params, 'resource', 'The parameter "resource" is mandatory.');
92
93
        return $query_params['resource'];
94
    }
95
96
    private function filterLinks(ServerRequestInterface $request, ResourceDescriptor $resourceDescriptor): array
97
    {
98
        $data = $resourceDescriptor->jsonSerialize();
99
100
        $rels = $this->getRels($request);
101
        if (!\array_key_exists('links', $data) || 0 === \count($rels) || 0 === \count($data['links'])) {
102
            return $data;
103
        }
104
105
        $data['links'] = array_filter($data['links'], static function (Link $link) use ($rels): bool {
106
            if (\in_array($link->getRel(), $rels, true)) {
107
                return true;
108
            }
109
110
            return false;
111
        });
112
113
        if (0 === \count($data['links'])) {
114
            unset($data['links']);
115
        }
116
117
        return $data;
118
    }
119
120
    /**
121
     * @return string[]
122
     */
123
    private function getRels(ServerRequestInterface $request): array
124
    {
125
        $queryParams = $request->getQueryParams();
126
        if (!\array_key_exists('rel', $queryParams)) {
127
            return [];
128
        }
129
130
        switch (true) {
131
            case \is_string($queryParams['rel']):
132
                return [$queryParams['rel']];
133
            case \is_array($queryParams['rel']):
134
                return $queryParams['rel'];
135
            default:
136
                return [];
137
        }
138
    }
139
}
140