]> git.immae.eu Git - github/shaarli/Shaarli.git/blame - application/api/ApiMiddleware.php
Merge pull request #1525 from ArthurHoaro/feature/rest-api-bookmark-dates
[github/shaarli/Shaarli.git] / application / api / ApiMiddleware.php
CommitLineData
18e67967 1<?php
18e67967
A
2namespace Shaarli\Api;
3
18e67967 4use Shaarli\Api\Exceptions\ApiAuthorizationException;
dea72c71 5use Shaarli\Api\Exceptions\ApiException;
255b2264 6use Shaarli\Bookmark\BookmarkFileService;
813849e5 7use Shaarli\Config\ConfigManager;
18e67967
A
8use Slim\Container;
9use Slim\Http\Request;
10use Slim\Http\Response;
11
12/**
13 * Class ApiMiddleware
14 *
15 * This will be called before accessing any API Controller.
16 * Its role is to make sure that the API is enabled, configured, and to validate the JWT token.
17 *
18 * If the request is validated, the controller is called, otherwise a JSON error response is returned.
19 *
20 * @package Api
21 */
22class ApiMiddleware
23{
24 /**
25 * @var int JWT token validity in seconds (9 min).
26 */
27 public static $TOKEN_DURATION = 540;
28
29 /**
30 * @var Container: contains conf, plugins, etc.
31 */
32 protected $container;
33
34 /**
813849e5 35 * @var ConfigManager instance.
18e67967
A
36 */
37 protected $conf;
38
39 /**
40 * ApiMiddleware constructor.
41 *
42 * @param Container $container instance.
43 */
44 public function __construct($container)
45 {
46 $this->container = $container;
47 $this->conf = $this->container->get('conf');
48 $this->setLinkDb($this->conf);
49 }
50
51 /**
52 * Middleware execution:
53 * - check the API request
54 * - execute the controller
55 * - return the response
56 *
57 * @param Request $request Slim request
58 * @param Response $response Slim response
59 * @param callable $next Next action
60 *
61 * @return Response response.
62 */
63 public function __invoke($request, $response, $next)
64 {
65 try {
66 $this->checkRequest($request);
67 $response = $next($request, $response);
f211e417 68 } catch (ApiException $e) {
18e67967
A
69 $e->setResponse($response);
70 $e->setDebug($this->conf->get('dev.debug', false));
71 $response = $e->getApiResponse();
72 }
73
255b2264
A
74 return $response
75 ->withHeader('Access-Control-Allow-Origin', '*')
76 ->withHeader(
77 'Access-Control-Allow-Headers',
78 'X-Requested-With, Content-Type, Accept, Origin, Authorization'
79 )
80 ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
81 ;
18e67967
A
82 }
83
84 /**
85 * Check the request validity (HTTP method, request value, etc.),
86 * that the API is enabled, and the JWT token validity.
87 *
88 * @param Request $request Slim request
89 *
90 * @throws ApiAuthorizationException The API is disabled or the token is invalid.
91 */
92 protected function checkRequest($request)
93 {
94 if (! $this->conf->get('api.enabled', true)) {
95 throw new ApiAuthorizationException('API is disabled');
96 }
97 $this->checkToken($request);
98 }
99
100 /**
101 * Check that the JWT token is set and valid.
102 * The API secret setting must be set.
103 *
104 * @param Request $request Slim request
105 *
106 * @throws ApiAuthorizationException The token couldn't be validated.
107 */
f211e417
V
108 protected function checkToken($request)
109 {
255b2264
A
110 if (!$request->hasHeader('Authorization')
111 && !isset($this->container->environment['REDIRECT_HTTP_AUTHORIZATION'])
112 ) {
18e67967
A
113 throw new ApiAuthorizationException('JWT token not provided');
114 }
25cb7555 115
18e67967
A
116 if (empty($this->conf->get('api.secret'))) {
117 throw new ApiAuthorizationException('Token secret must be set in Shaarli\'s administration');
118 }
119
25cb7555
CS
120 if (isset($this->container->environment['REDIRECT_HTTP_AUTHORIZATION'])) {
121 $authorization = $this->container->environment['REDIRECT_HTTP_AUTHORIZATION'];
122 } else {
676571da 123 $authorization = $request->getHeaderLine('Authorization');
25cb7555 124 }
63ef5497
V
125
126 if (! preg_match('/^Bearer (.*)/i', $authorization, $matches)) {
127 throw new ApiAuthorizationException('Invalid JWT header');
128 }
129
130 ApiUtils::validateJwtToken($matches[1], $this->conf->get('api.secret'));
18e67967
A
131 }
132
133 /**
255b2264 134 * Instantiate a new LinkDB including private bookmarks,
18e67967
A
135 * and load in the Slim container.
136 *
137 * FIXME! LinkDB could use a refactoring to avoid this trick.
138 *
813849e5 139 * @param ConfigManager $conf instance.
18e67967
A
140 */
141 protected function setLinkDb($conf)
142 {
255b2264
A
143 $linkDb = new BookmarkFileService(
144 $conf,
145 $this->container->get('history'),
146 true
18e67967
A
147 );
148 $this->container['db'] = $linkDb;
149 }
150}