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