aboutsummaryrefslogtreecommitdiffhomepage
path: root/application/api/ApiMiddleware.php
diff options
context:
space:
mode:
Diffstat (limited to 'application/api/ApiMiddleware.php')
-rw-r--r--application/api/ApiMiddleware.php132
1 files changed, 132 insertions, 0 deletions
diff --git a/application/api/ApiMiddleware.php b/application/api/ApiMiddleware.php
new file mode 100644
index 00000000..162e88e0
--- /dev/null
+++ b/application/api/ApiMiddleware.php
@@ -0,0 +1,132 @@
1<?php
2
3namespace Shaarli\Api;
4
5use Shaarli\Api\Exceptions\ApiException;
6use Shaarli\Api\Exceptions\ApiAuthorizationException;
7use Slim\Container;
8use Slim\Http\Request;
9use Slim\Http\Response;
10
11/**
12 * Class ApiMiddleware
13 *
14 * This will be called before accessing any API Controller.
15 * Its role is to make sure that the API is enabled, configured, and to validate the JWT token.
16 *
17 * If the request is validated, the controller is called, otherwise a JSON error response is returned.
18 *
19 * @package Api
20 */
21class ApiMiddleware
22{
23 /**
24 * @var int JWT token validity in seconds (9 min).
25 */
26 public static $TOKEN_DURATION = 540;
27
28 /**
29 * @var Container: contains conf, plugins, etc.
30 */
31 protected $container;
32
33 /**
34 * @var \ConfigManager instance.
35 */
36 protected $conf;
37
38 /**
39 * ApiMiddleware constructor.
40 *
41 * @param Container $container instance.
42 */
43 public function __construct($container)
44 {
45 $this->container = $container;
46 $this->conf = $this->container->get('conf');
47 $this->setLinkDb($this->conf);
48 }
49
50 /**
51 * Middleware execution:
52 * - check the API request
53 * - execute the controller
54 * - return the response
55 *
56 * @param Request $request Slim request
57 * @param Response $response Slim response
58 * @param callable $next Next action
59 *
60 * @return Response response.
61 */
62 public function __invoke($request, $response, $next)
63 {
64 try {
65 $this->checkRequest($request);
66 $response = $next($request, $response);
67 } catch(ApiException $e) {
68 $e->setResponse($response);
69 $e->setDebug($this->conf->get('dev.debug', false));
70 $response = $e->getApiResponse();
71 }
72
73 return $response;
74 }
75
76 /**
77 * Check the request validity (HTTP method, request value, etc.),
78 * that the API is enabled, and the JWT token validity.
79 *
80 * @param Request $request Slim request
81 *
82 * @throws ApiAuthorizationException The API is disabled or the token is invalid.
83 */
84 protected function checkRequest($request)
85 {
86 if (! $this->conf->get('api.enabled', true)) {
87 throw new ApiAuthorizationException('API is disabled');
88 }
89 $this->checkToken($request);
90 }
91
92 /**
93 * Check that the JWT token is set and valid.
94 * The API secret setting must be set.
95 *
96 * @param Request $request Slim request
97 *
98 * @throws ApiAuthorizationException The token couldn't be validated.
99 */
100 protected function checkToken($request) {
101 $jwt = $request->getHeaderLine('jwt');
102 if (empty($jwt)) {
103 throw new ApiAuthorizationException('JWT token not provided');
104 }
105
106 if (empty($this->conf->get('api.secret'))) {
107 throw new ApiAuthorizationException('Token secret must be set in Shaarli\'s administration');
108 }
109
110 ApiUtils::validateJwtToken($jwt, $this->conf->get('api.secret'));
111 }
112
113 /**
114 * Instantiate a new LinkDB including private links,
115 * and load in the Slim container.
116 *
117 * FIXME! LinkDB could use a refactoring to avoid this trick.
118 *
119 * @param \ConfigManager $conf instance.
120 */
121 protected function setLinkDb($conf)
122 {
123 $linkDb = new \LinkDB(
124 $conf->get('resource.datastore'),
125 true,
126 $conf->get('privacy.hide_public_links'),
127 $conf->get('redirector.url'),
128 $conf->get('redirector.encode_url')
129 );
130 $this->container['db'] = $linkDb;
131 }
132}