diff options
Diffstat (limited to 'application/api')
-rw-r--r-- | application/api/ApiMiddleware.php | 21 | ||||
-rw-r--r-- | application/api/ApiUtils.php | 17 | ||||
-rw-r--r-- | application/api/controllers/ApiController.php | 3 | ||||
-rw-r--r-- | application/api/controllers/Links.php | 23 |
4 files changed, 46 insertions, 18 deletions
diff --git a/application/api/ApiMiddleware.php b/application/api/ApiMiddleware.php index 4745ac94..adc8b266 100644 --- a/application/api/ApiMiddleware.php +++ b/application/api/ApiMiddleware.php | |||
@@ -1,6 +1,7 @@ | |||
1 | <?php | 1 | <?php |
2 | namespace Shaarli\Api; | 2 | namespace Shaarli\Api; |
3 | 3 | ||
4 | use malkusch\lock\mutex\FlockMutex; | ||
4 | use Shaarli\Api\Exceptions\ApiAuthorizationException; | 5 | use Shaarli\Api\Exceptions\ApiAuthorizationException; |
5 | use Shaarli\Api\Exceptions\ApiException; | 6 | use Shaarli\Api\Exceptions\ApiException; |
6 | use Shaarli\Bookmark\BookmarkFileService; | 7 | use Shaarli\Bookmark\BookmarkFileService; |
@@ -71,7 +72,14 @@ class ApiMiddleware | |||
71 | $response = $e->getApiResponse(); | 72 | $response = $e->getApiResponse(); |
72 | } | 73 | } |
73 | 74 | ||
74 | return $response; | 75 | return $response |
76 | ->withHeader('Access-Control-Allow-Origin', '*') | ||
77 | ->withHeader( | ||
78 | 'Access-Control-Allow-Headers', | ||
79 | 'X-Requested-With, Content-Type, Accept, Origin, Authorization' | ||
80 | ) | ||
81 | ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS') | ||
82 | ; | ||
75 | } | 83 | } |
76 | 84 | ||
77 | /** | 85 | /** |
@@ -100,7 +108,9 @@ class ApiMiddleware | |||
100 | */ | 108 | */ |
101 | protected function checkToken($request) | 109 | protected function checkToken($request) |
102 | { | 110 | { |
103 | if (! $request->hasHeader('Authorization')) { | 111 | if (!$request->hasHeader('Authorization') |
112 | && !isset($this->container->environment['REDIRECT_HTTP_AUTHORIZATION']) | ||
113 | ) { | ||
104 | throw new ApiAuthorizationException('JWT token not provided'); | 114 | throw new ApiAuthorizationException('JWT token not provided'); |
105 | } | 115 | } |
106 | 116 | ||
@@ -108,7 +118,11 @@ class ApiMiddleware | |||
108 | throw new ApiAuthorizationException('Token secret must be set in Shaarli\'s administration'); | 118 | throw new ApiAuthorizationException('Token secret must be set in Shaarli\'s administration'); |
109 | } | 119 | } |
110 | 120 | ||
111 | $authorization = $request->getHeaderLine('Authorization'); | 121 | if (isset($this->container->environment['REDIRECT_HTTP_AUTHORIZATION'])) { |
122 | $authorization = $this->container->environment['REDIRECT_HTTP_AUTHORIZATION']; | ||
123 | } else { | ||
124 | $authorization = $request->getHeaderLine('Authorization'); | ||
125 | } | ||
112 | 126 | ||
113 | if (! preg_match('/^Bearer (.*)/i', $authorization, $matches)) { | 127 | if (! preg_match('/^Bearer (.*)/i', $authorization, $matches)) { |
114 | throw new ApiAuthorizationException('Invalid JWT header'); | 128 | throw new ApiAuthorizationException('Invalid JWT header'); |
@@ -130,6 +144,7 @@ class ApiMiddleware | |||
130 | $linkDb = new BookmarkFileService( | 144 | $linkDb = new BookmarkFileService( |
131 | $conf, | 145 | $conf, |
132 | $this->container->get('history'), | 146 | $this->container->get('history'), |
147 | new FlockMutex(fopen(SHAARLI_MUTEX_FILE, 'r'), 2), | ||
133 | true | 148 | true |
134 | ); | 149 | ); |
135 | $this->container['db'] = $linkDb; | 150 | $this->container['db'] = $linkDb; |
diff --git a/application/api/ApiUtils.php b/application/api/ApiUtils.php index 5156a5f7..eb1ca9bc 100644 --- a/application/api/ApiUtils.php +++ b/application/api/ApiUtils.php | |||
@@ -67,7 +67,7 @@ class ApiUtils | |||
67 | if (! $bookmark->isNote()) { | 67 | if (! $bookmark->isNote()) { |
68 | $out['url'] = $bookmark->getUrl(); | 68 | $out['url'] = $bookmark->getUrl(); |
69 | } else { | 69 | } else { |
70 | $out['url'] = $indexUrl . $bookmark->getUrl(); | 70 | $out['url'] = rtrim($indexUrl, '/') . '/' . ltrim($bookmark->getUrl(), '/'); |
71 | } | 71 | } |
72 | $out['shorturl'] = $bookmark->getShortUrl(); | 72 | $out['shorturl'] = $bookmark->getShortUrl(); |
73 | $out['title'] = $bookmark->getTitle(); | 73 | $out['title'] = $bookmark->getTitle(); |
@@ -89,12 +89,12 @@ class ApiUtils | |||
89 | * If no URL is provided, it will generate a local note URL. | 89 | * If no URL is provided, it will generate a local note URL. |
90 | * If no title is provided, it will use the URL as title. | 90 | * If no title is provided, it will use the URL as title. |
91 | * | 91 | * |
92 | * @param array $input Request Link. | 92 | * @param array|null $input Request Link. |
93 | * @param bool $defaultPrivate Request Link. | 93 | * @param bool $defaultPrivate Setting defined if a bookmark is private by default. |
94 | * | 94 | * |
95 | * @return Bookmark instance. | 95 | * @return Bookmark instance. |
96 | */ | 96 | */ |
97 | public static function buildLinkFromRequest($input, $defaultPrivate) | 97 | public static function buildBookmarkFromRequest(?array $input, bool $defaultPrivate): Bookmark |
98 | { | 98 | { |
99 | $bookmark = new Bookmark(); | 99 | $bookmark = new Bookmark(); |
100 | $url = ! empty($input['url']) ? cleanup_url($input['url']) : ''; | 100 | $url = ! empty($input['url']) ? cleanup_url($input['url']) : ''; |
@@ -110,6 +110,15 @@ class ApiUtils | |||
110 | $bookmark->setTags(! empty($input['tags']) ? $input['tags'] : []); | 110 | $bookmark->setTags(! empty($input['tags']) ? $input['tags'] : []); |
111 | $bookmark->setPrivate($private); | 111 | $bookmark->setPrivate($private); |
112 | 112 | ||
113 | $created = \DateTime::createFromFormat(\DateTime::ATOM, $input['created'] ?? ''); | ||
114 | if ($created instanceof \DateTimeInterface) { | ||
115 | $bookmark->setCreated($created); | ||
116 | } | ||
117 | $updated = \DateTime::createFromFormat(\DateTime::ATOM, $input['updated'] ?? ''); | ||
118 | if ($updated instanceof \DateTimeInterface) { | ||
119 | $bookmark->setUpdated($updated); | ||
120 | } | ||
121 | |||
113 | return $bookmark; | 122 | return $bookmark; |
114 | } | 123 | } |
115 | 124 | ||
diff --git a/application/api/controllers/ApiController.php b/application/api/controllers/ApiController.php index c4b3d0c3..88a845eb 100644 --- a/application/api/controllers/ApiController.php +++ b/application/api/controllers/ApiController.php | |||
@@ -4,6 +4,7 @@ namespace Shaarli\Api\Controllers; | |||
4 | 4 | ||
5 | use Shaarli\Bookmark\BookmarkServiceInterface; | 5 | use Shaarli\Bookmark\BookmarkServiceInterface; |
6 | use Shaarli\Config\ConfigManager; | 6 | use Shaarli\Config\ConfigManager; |
7 | use Shaarli\History; | ||
7 | use Slim\Container; | 8 | use Slim\Container; |
8 | 9 | ||
9 | /** | 10 | /** |
@@ -31,7 +32,7 @@ abstract class ApiController | |||
31 | protected $bookmarkService; | 32 | protected $bookmarkService; |
32 | 33 | ||
33 | /** | 34 | /** |
34 | * @var HistoryController | 35 | * @var History |
35 | */ | 36 | */ |
36 | protected $history; | 37 | protected $history; |
37 | 38 | ||
diff --git a/application/api/controllers/Links.php b/application/api/controllers/Links.php index 16fc8688..6bf529e4 100644 --- a/application/api/controllers/Links.php +++ b/application/api/controllers/Links.php | |||
@@ -96,11 +96,12 @@ class Links extends ApiController | |||
96 | */ | 96 | */ |
97 | public function getLink($request, $response, $args) | 97 | public function getLink($request, $response, $args) |
98 | { | 98 | { |
99 | if (!$this->bookmarkService->exists($args['id'])) { | 99 | $id = is_integer_mixed($args['id']) ? (int) $args['id'] : null; |
100 | if ($id === null || ! $this->bookmarkService->exists($id)) { | ||
100 | throw new ApiLinkNotFoundException(); | 101 | throw new ApiLinkNotFoundException(); |
101 | } | 102 | } |
102 | $index = index_url($this->ci['environment']); | 103 | $index = index_url($this->ci['environment']); |
103 | $out = ApiUtils::formatLink($this->bookmarkService->get($args['id']), $index); | 104 | $out = ApiUtils::formatLink($this->bookmarkService->get($id), $index); |
104 | 105 | ||
105 | return $response->withJson($out, 200, $this->jsonStyle); | 106 | return $response->withJson($out, 200, $this->jsonStyle); |
106 | } | 107 | } |
@@ -115,8 +116,8 @@ class Links extends ApiController | |||
115 | */ | 116 | */ |
116 | public function postLink($request, $response) | 117 | public function postLink($request, $response) |
117 | { | 118 | { |
118 | $data = $request->getParsedBody(); | 119 | $data = (array) ($request->getParsedBody() ?? []); |
119 | $bookmark = ApiUtils::buildLinkFromRequest($data, $this->conf->get('privacy.default_private_links')); | 120 | $bookmark = ApiUtils::buildBookmarkFromRequest($data, $this->conf->get('privacy.default_private_links')); |
120 | // duplicate by URL, return 409 Conflict | 121 | // duplicate by URL, return 409 Conflict |
121 | if (! empty($bookmark->getUrl()) | 122 | if (! empty($bookmark->getUrl()) |
122 | && ! empty($dup = $this->bookmarkService->findByUrl($bookmark->getUrl())) | 123 | && ! empty($dup = $this->bookmarkService->findByUrl($bookmark->getUrl())) |
@@ -148,18 +149,19 @@ class Links extends ApiController | |||
148 | */ | 149 | */ |
149 | public function putLink($request, $response, $args) | 150 | public function putLink($request, $response, $args) |
150 | { | 151 | { |
151 | if (! $this->bookmarkService->exists($args['id'])) { | 152 | $id = is_integer_mixed($args['id']) ? (int) $args['id'] : null; |
153 | if ($id === null || !$this->bookmarkService->exists($id)) { | ||
152 | throw new ApiLinkNotFoundException(); | 154 | throw new ApiLinkNotFoundException(); |
153 | } | 155 | } |
154 | 156 | ||
155 | $index = index_url($this->ci['environment']); | 157 | $index = index_url($this->ci['environment']); |
156 | $data = $request->getParsedBody(); | 158 | $data = $request->getParsedBody(); |
157 | 159 | ||
158 | $requestBookmark = ApiUtils::buildLinkFromRequest($data, $this->conf->get('privacy.default_private_links')); | 160 | $requestBookmark = ApiUtils::buildBookmarkFromRequest($data, $this->conf->get('privacy.default_private_links')); |
159 | // duplicate URL on a different link, return 409 Conflict | 161 | // duplicate URL on a different link, return 409 Conflict |
160 | if (! empty($requestBookmark->getUrl()) | 162 | if (! empty($requestBookmark->getUrl()) |
161 | && ! empty($dup = $this->bookmarkService->findByUrl($requestBookmark->getUrl())) | 163 | && ! empty($dup = $this->bookmarkService->findByUrl($requestBookmark->getUrl())) |
162 | && $dup->getId() != $args['id'] | 164 | && $dup->getId() != $id |
163 | ) { | 165 | ) { |
164 | return $response->withJson( | 166 | return $response->withJson( |
165 | ApiUtils::formatLink($dup, $index), | 167 | ApiUtils::formatLink($dup, $index), |
@@ -168,7 +170,7 @@ class Links extends ApiController | |||
168 | ); | 170 | ); |
169 | } | 171 | } |
170 | 172 | ||
171 | $responseBookmark = $this->bookmarkService->get($args['id']); | 173 | $responseBookmark = $this->bookmarkService->get($id); |
172 | $responseBookmark = ApiUtils::updateLink($responseBookmark, $requestBookmark); | 174 | $responseBookmark = ApiUtils::updateLink($responseBookmark, $requestBookmark); |
173 | $this->bookmarkService->set($responseBookmark); | 175 | $this->bookmarkService->set($responseBookmark); |
174 | 176 | ||
@@ -189,10 +191,11 @@ class Links extends ApiController | |||
189 | */ | 191 | */ |
190 | public function deleteLink($request, $response, $args) | 192 | public function deleteLink($request, $response, $args) |
191 | { | 193 | { |
192 | if (! $this->bookmarkService->exists($args['id'])) { | 194 | $id = is_integer_mixed($args['id']) ? (int) $args['id'] : null; |
195 | if ($id === null || !$this->bookmarkService->exists($id)) { | ||
193 | throw new ApiLinkNotFoundException(); | 196 | throw new ApiLinkNotFoundException(); |
194 | } | 197 | } |
195 | $bookmark = $this->bookmarkService->get($args['id']); | 198 | $bookmark = $this->bookmarkService->get($id); |
196 | $this->bookmarkService->remove($bookmark); | 199 | $this->bookmarkService->remove($bookmark); |
197 | 200 | ||
198 | return $response->withStatus(204); | 201 | return $response->withStatus(204); |