aboutsummaryrefslogtreecommitdiffhomepage
path: root/application
diff options
context:
space:
mode:
Diffstat (limited to 'application')
-rw-r--r--application/ApplicationUtils.php1
-rw-r--r--application/Base64Url.php34
-rw-r--r--application/CachedPage.php4
-rw-r--r--application/HttpUtils.php2
-rw-r--r--application/LinkUtils.php4
-rw-r--r--application/PageBuilder.php2
-rw-r--r--application/ThemeUtils.php33
-rw-r--r--application/Updater.php47
-rw-r--r--application/api/ApiMiddleware.php11
-rw-r--r--application/api/ApiUtils.php12
-rw-r--r--application/config/ConfigIO.php6
-rw-r--r--application/config/ConfigJson.php6
-rw-r--r--application/config/ConfigManager.php1
-rw-r--r--application/config/ConfigPhp.php9
14 files changed, 144 insertions, 28 deletions
diff --git a/application/ApplicationUtils.php b/application/ApplicationUtils.php
index 7f963e97..a0f482b0 100644
--- a/application/ApplicationUtils.php
+++ b/application/ApplicationUtils.php
@@ -150,6 +150,7 @@ class ApplicationUtils
150 'inc', 150 'inc',
151 'plugins', 151 'plugins',
152 $conf->get('resource.raintpl_tpl'), 152 $conf->get('resource.raintpl_tpl'),
153 $conf->get('resource.raintpl_tpl').'/'.$conf->get('resource.theme'),
153 ) as $path) { 154 ) as $path) {
154 if (! is_readable(realpath($path))) { 155 if (! is_readable(realpath($path))) {
155 $errors[] = '"'.$path.'" directory is not readable'; 156 $errors[] = '"'.$path.'" directory is not readable';
diff --git a/application/Base64Url.php b/application/Base64Url.php
new file mode 100644
index 00000000..61590e43
--- /dev/null
+++ b/application/Base64Url.php
@@ -0,0 +1,34 @@
1<?php
2
3namespace Shaarli;
4
5
6/**
7 * URL-safe Base64 operations
8 *
9 * @see https://en.wikipedia.org/wiki/Base64#URL_applications
10 */
11class Base64Url
12{
13 /**
14 * Base64Url-encodes data
15 *
16 * @param string $data Data to encode
17 *
18 * @return string Base64Url-encoded data
19 */
20 public static function encode($data) {
21 return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
22 }
23
24 /**
25 * Decodes Base64Url-encoded data
26 *
27 * @param string $data Data to decode
28 *
29 * @return string Decoded data
30 */
31 public static function decode($data) {
32 return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
33 }
34}
diff --git a/application/CachedPage.php b/application/CachedPage.php
index 5087d0c4..e11cc52d 100644
--- a/application/CachedPage.php
+++ b/application/CachedPage.php
@@ -7,9 +7,6 @@ class CachedPage
7 // Directory containing page caches 7 // Directory containing page caches
8 private $cacheDir; 8 private $cacheDir;
9 9
10 // Full URL of the page to cache -typically the value returned by pageUrl()
11 private $url;
12
13 // Should this URL be cached (boolean)? 10 // Should this URL be cached (boolean)?
14 private $shouldBeCached; 11 private $shouldBeCached;
15 12
@@ -27,7 +24,6 @@ class CachedPage
27 { 24 {
28 // TODO: check write access to the cache directory 25 // TODO: check write access to the cache directory
29 $this->cacheDir = $cacheDir; 26 $this->cacheDir = $cacheDir;
30 $this->url = $url;
31 $this->filename = $this->cacheDir.'/'.sha1($url).'.cache'; 27 $this->filename = $this->cacheDir.'/'.sha1($url).'.cache';
32 $this->shouldBeCached = $shouldBeCached; 28 $this->shouldBeCached = $shouldBeCached;
33 } 29 }
diff --git a/application/HttpUtils.php b/application/HttpUtils.php
index e8fc1f5d..a81f9056 100644
--- a/application/HttpUtils.php
+++ b/application/HttpUtils.php
@@ -122,7 +122,7 @@ function get_http_response($url, $timeout = 30, $maxBytes = 4194304)
122 $content = substr($response, $headSize); 122 $content = substr($response, $headSize);
123 $headers = array(); 123 $headers = array();
124 foreach (preg_split('~[\r\n]+~', $rawHeadersLastRedir) as $line) { 124 foreach (preg_split('~[\r\n]+~', $rawHeadersLastRedir) as $line) {
125 if (empty($line) or ctype_space($line)) { 125 if (empty($line) || ctype_space($line)) {
126 continue; 126 continue;
127 } 127 }
128 $splitLine = explode(': ', $line, 2); 128 $splitLine = explode(': ', $line, 2);
diff --git a/application/LinkUtils.php b/application/LinkUtils.php
index cf58f808..976474de 100644
--- a/application/LinkUtils.php
+++ b/application/LinkUtils.php
@@ -89,7 +89,9 @@ function count_private($links)
89{ 89{
90 $cpt = 0; 90 $cpt = 0;
91 foreach ($links as $link) { 91 foreach ($links as $link) {
92 $cpt = $link['private'] == true ? $cpt + 1 : $cpt; 92 if ($link['private']) {
93 $cpt += 1;
94 }
93 } 95 }
94 96
95 return $cpt; 97 return $cpt;
diff --git a/application/PageBuilder.php b/application/PageBuilder.php
index 32c7f9f1..544aba7c 100644
--- a/application/PageBuilder.php
+++ b/application/PageBuilder.php
@@ -25,7 +25,7 @@ class PageBuilder
25 * 25 *
26 * @param ConfigManager $conf Configuration Manager instance (reference). 26 * @param ConfigManager $conf Configuration Manager instance (reference).
27 */ 27 */
28 function __construct(&$conf) 28 public function __construct(&$conf)
29 { 29 {
30 $this->tpl = false; 30 $this->tpl = false;
31 $this->conf = $conf; 31 $this->conf = $conf;
diff --git a/application/ThemeUtils.php b/application/ThemeUtils.php
new file mode 100644
index 00000000..2718ed13
--- /dev/null
+++ b/application/ThemeUtils.php
@@ -0,0 +1,33 @@
1<?php
2
3namespace Shaarli;
4
5/**
6 * Class ThemeUtils
7 *
8 * Utility functions related to theme management.
9 *
10 * @package Shaarli
11 */
12class ThemeUtils
13{
14 /**
15 * Get a list of available themes.
16 *
17 * It will return the name of any directory present in the template folder.
18 *
19 * @param string $tplDir Templates main directory.
20 *
21 * @return array List of theme names.
22 */
23 public static function getThemes($tplDir)
24 {
25 $allTheme = glob($tplDir.'/*', GLOB_ONLYDIR);
26 $themes = [];
27 foreach ($allTheme as $value) {
28 $themes[] = str_replace($tplDir.'/', '', $value);
29 }
30
31 return $themes;
32 }
33}
diff --git a/application/Updater.php b/application/Updater.php
index 38de3350..eb03c6d3 100644
--- a/application/Updater.php
+++ b/application/Updater.php
@@ -69,7 +69,7 @@ class Updater
69 return $updatesRan; 69 return $updatesRan;
70 } 70 }
71 71
72 if ($this->methods == null) { 72 if ($this->methods === null) {
73 throw new UpdaterException('Couldn\'t retrieve Updater class methods.'); 73 throw new UpdaterException('Couldn\'t retrieve Updater class methods.');
74 } 74 }
75 75
@@ -279,6 +279,51 @@ class Updater
279 $this->conf->write($this->isLoggedIn); 279 $this->conf->write($this->isLoggedIn);
280 return true; 280 return true;
281 } 281 }
282
283 /**
284 * New setting: theme name. If the default theme is used, nothing to do.
285 *
286 * If the user uses a custom theme, raintpl_tpl dir is updated to the parent directory,
287 * and the current theme is set as default in the theme setting.
288 *
289 * @return bool true if the update is successful, false otherwise.
290 */
291 public function updateMethodDefaultTheme()
292 {
293 // raintpl_tpl isn't the root template directory anymore.
294 // We run the update only if this folder still contains the template files.
295 $tplDir = $this->conf->get('resource.raintpl_tpl');
296 $tplFile = $tplDir . '/linklist.html';
297 if (! file_exists($tplFile)) {
298 return true;
299 }
300
301 $parent = dirname($tplDir);
302 $this->conf->set('resource.raintpl_tpl', $parent);
303 $this->conf->set('resource.theme', trim(str_replace($parent, '', $tplDir), '/'));
304 $this->conf->write($this->isLoggedIn);
305
306 // Dependency injection gore
307 RainTPL::$tpl_dir = $tplDir;
308
309 return true;
310 }
311
312 /**
313 * Move the file to inc/user.css to data/user.css.
314 *
315 * Note: Due to hardcoded paths, it's not unit testable. But one line of code should be fine.
316 *
317 * @return bool true if the update is successful, false otherwise.
318 */
319 public function updateMethodMoveUserCss()
320 {
321 if (! is_file('inc/user.css')) {
322 return true;
323 }
324
325 return rename('inc/user.css', 'data/user.css');
326 }
282} 327}
283 328
284/** 329/**
diff --git a/application/api/ApiMiddleware.php b/application/api/ApiMiddleware.php
index 162e88e0..522091ca 100644
--- a/application/api/ApiMiddleware.php
+++ b/application/api/ApiMiddleware.php
@@ -98,8 +98,7 @@ class ApiMiddleware
98 * @throws ApiAuthorizationException The token couldn't be validated. 98 * @throws ApiAuthorizationException The token couldn't be validated.
99 */ 99 */
100 protected function checkToken($request) { 100 protected function checkToken($request) {
101 $jwt = $request->getHeaderLine('jwt'); 101 if (! $request->hasHeader('Authorization')) {
102 if (empty($jwt)) {
103 throw new ApiAuthorizationException('JWT token not provided'); 102 throw new ApiAuthorizationException('JWT token not provided');
104 } 103 }
105 104
@@ -107,7 +106,13 @@ class ApiMiddleware
107 throw new ApiAuthorizationException('Token secret must be set in Shaarli\'s administration'); 106 throw new ApiAuthorizationException('Token secret must be set in Shaarli\'s administration');
108 } 107 }
109 108
110 ApiUtils::validateJwtToken($jwt, $this->conf->get('api.secret')); 109 $authorization = $request->getHeaderLine('Authorization');
110
111 if (! preg_match('/^Bearer (.*)/i', $authorization, $matches)) {
112 throw new ApiAuthorizationException('Invalid JWT header');
113 }
114
115 ApiUtils::validateJwtToken($matches[1], $this->conf->get('api.secret'));
111 } 116 }
112 117
113 /** 118 /**
diff --git a/application/api/ApiUtils.php b/application/api/ApiUtils.php
index d0242919..d4015865 100644
--- a/application/api/ApiUtils.php
+++ b/application/api/ApiUtils.php
@@ -1,13 +1,11 @@
1<?php 1<?php
2
3namespace Shaarli\Api; 2namespace Shaarli\Api;
4 3
4use Shaarli\Base64Url;
5use Shaarli\Api\Exceptions\ApiAuthorizationException; 5use Shaarli\Api\Exceptions\ApiAuthorizationException;
6 6
7/** 7/**
8 * Class ApiUtils 8 * REST API utilities
9 *
10 * Utility functions for the API.
11 */ 9 */
12class ApiUtils 10class ApiUtils
13{ 11{
@@ -26,17 +24,17 @@ class ApiUtils
26 throw new ApiAuthorizationException('Malformed JWT token'); 24 throw new ApiAuthorizationException('Malformed JWT token');
27 } 25 }
28 26
29 $genSign = hash_hmac('sha512', $parts[0] .'.'. $parts[1], $secret); 27 $genSign = Base64Url::encode(hash_hmac('sha512', $parts[0] .'.'. $parts[1], $secret, true));
30 if ($parts[2] != $genSign) { 28 if ($parts[2] != $genSign) {
31 throw new ApiAuthorizationException('Invalid JWT signature'); 29 throw new ApiAuthorizationException('Invalid JWT signature');
32 } 30 }
33 31
34 $header = json_decode(base64_decode($parts[0])); 32 $header = json_decode(Base64Url::decode($parts[0]));
35 if ($header === null) { 33 if ($header === null) {
36 throw new ApiAuthorizationException('Invalid JWT header'); 34 throw new ApiAuthorizationException('Invalid JWT header');
37 } 35 }
38 36
39 $payload = json_decode(base64_decode($parts[1])); 37 $payload = json_decode(Base64Url::decode($parts[1]));
40 if ($payload === null) { 38 if ($payload === null) {
41 throw new ApiAuthorizationException('Invalid JWT payload'); 39 throw new ApiAuthorizationException('Invalid JWT payload');
42 } 40 }
diff --git a/application/config/ConfigIO.php b/application/config/ConfigIO.php
index 2b68fe6a..be78b1c7 100644
--- a/application/config/ConfigIO.php
+++ b/application/config/ConfigIO.php
@@ -14,7 +14,7 @@ interface ConfigIO
14 * 14 *
15 * @return array All configuration in an array. 15 * @return array All configuration in an array.
16 */ 16 */
17 function read($filepath); 17 public function read($filepath);
18 18
19 /** 19 /**
20 * Write configuration. 20 * Write configuration.
@@ -22,12 +22,12 @@ interface ConfigIO
22 * @param string $filepath Config file absolute path. 22 * @param string $filepath Config file absolute path.
23 * @param array $conf All configuration in an array. 23 * @param array $conf All configuration in an array.
24 */ 24 */
25 function write($filepath, $conf); 25 public function write($filepath, $conf);
26 26
27 /** 27 /**
28 * Get config file extension according to config type. 28 * Get config file extension according to config type.
29 * 29 *
30 * @return string Config file extension. 30 * @return string Config file extension.
31 */ 31 */
32 function getExtension(); 32 public function getExtension();
33} 33}
diff --git a/application/config/ConfigJson.php b/application/config/ConfigJson.php
index 30007eb4..6b5d73f1 100644
--- a/application/config/ConfigJson.php
+++ b/application/config/ConfigJson.php
@@ -10,7 +10,7 @@ class ConfigJson implements ConfigIO
10 /** 10 /**
11 * @inheritdoc 11 * @inheritdoc
12 */ 12 */
13 function read($filepath) 13 public function read($filepath)
14 { 14 {
15 if (! is_readable($filepath)) { 15 if (! is_readable($filepath)) {
16 return array(); 16 return array();
@@ -29,7 +29,7 @@ class ConfigJson implements ConfigIO
29 /** 29 /**
30 * @inheritdoc 30 * @inheritdoc
31 */ 31 */
32 function write($filepath, $conf) 32 public function write($filepath, $conf)
33 { 33 {
34 // JSON_PRETTY_PRINT is available from PHP 5.4. 34 // JSON_PRETTY_PRINT is available from PHP 5.4.
35 $print = defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 0; 35 $print = defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 0;
@@ -46,7 +46,7 @@ class ConfigJson implements ConfigIO
46 /** 46 /**
47 * @inheritdoc 47 * @inheritdoc
48 */ 48 */
49 function getExtension() 49 public function getExtension()
50 { 50 {
51 return '.json.php'; 51 return '.json.php';
52 } 52 }
diff --git a/application/config/ConfigManager.php b/application/config/ConfigManager.php
index ca8918b5..a401887c 100644
--- a/application/config/ConfigManager.php
+++ b/application/config/ConfigManager.php
@@ -299,6 +299,7 @@ class ConfigManager
299 $this->setEmpty('resource.log', 'data/log.txt'); 299 $this->setEmpty('resource.log', 'data/log.txt');
300 $this->setEmpty('resource.update_check', 'data/lastupdatecheck.txt'); 300 $this->setEmpty('resource.update_check', 'data/lastupdatecheck.txt');
301 $this->setEmpty('resource.raintpl_tpl', 'tpl/'); 301 $this->setEmpty('resource.raintpl_tpl', 'tpl/');
302 $this->setEmpty('resource.theme', 'default');
302 $this->setEmpty('resource.raintpl_tmp', 'tmp/'); 303 $this->setEmpty('resource.raintpl_tmp', 'tmp/');
303 $this->setEmpty('resource.thumbnails_cache', 'cache'); 304 $this->setEmpty('resource.thumbnails_cache', 'cache');
304 $this->setEmpty('resource.page_cache', 'pagecache'); 305 $this->setEmpty('resource.page_cache', 'pagecache');
diff --git a/application/config/ConfigPhp.php b/application/config/ConfigPhp.php
index 27187b66..d7fd4baf 100644
--- a/application/config/ConfigPhp.php
+++ b/application/config/ConfigPhp.php
@@ -41,6 +41,7 @@ class ConfigPhp implements ConfigIO
41 'resource.log' => 'config.LOG_FILE', 41 'resource.log' => 'config.LOG_FILE',
42 'resource.update_check' => 'config.UPDATECHECK_FILENAME', 42 'resource.update_check' => 'config.UPDATECHECK_FILENAME',
43 'resource.raintpl_tpl' => 'config.RAINTPL_TPL', 43 'resource.raintpl_tpl' => 'config.RAINTPL_TPL',
44 'resource.theme' => 'config.theme',
44 'resource.raintpl_tmp' => 'config.RAINTPL_TMP', 45 'resource.raintpl_tmp' => 'config.RAINTPL_TMP',
45 'resource.thumbnails_cache' => 'config.CACHEDIR', 46 'resource.thumbnails_cache' => 'config.CACHEDIR',
46 'resource.page_cache' => 'config.PAGECACHE', 47 'resource.page_cache' => 'config.PAGECACHE',
@@ -71,7 +72,7 @@ class ConfigPhp implements ConfigIO
71 /** 72 /**
72 * @inheritdoc 73 * @inheritdoc
73 */ 74 */
74 function read($filepath) 75 public function read($filepath)
75 { 76 {
76 if (! file_exists($filepath) || ! is_readable($filepath)) { 77 if (! file_exists($filepath) || ! is_readable($filepath)) {
77 return array(); 78 return array();
@@ -91,7 +92,7 @@ class ConfigPhp implements ConfigIO
91 /** 92 /**
92 * @inheritdoc 93 * @inheritdoc
93 */ 94 */
94 function write($filepath, $conf) 95 public function write($filepath, $conf)
95 { 96 {
96 $configStr = '<?php '. PHP_EOL; 97 $configStr = '<?php '. PHP_EOL;
97 foreach (self::$ROOT_KEYS as $key) { 98 foreach (self::$ROOT_KEYS as $key) {
@@ -99,7 +100,7 @@ class ConfigPhp implements ConfigIO
99 $configStr .= '$GLOBALS[\'' . $key . '\'] = ' . var_export($conf[$key], true) . ';' . PHP_EOL; 100 $configStr .= '$GLOBALS[\'' . $key . '\'] = ' . var_export($conf[$key], true) . ';' . PHP_EOL;
100 } 101 }
101 } 102 }
102 103
103 // Store all $conf['config'] 104 // Store all $conf['config']
104 foreach ($conf['config'] as $key => $value) { 105 foreach ($conf['config'] as $key => $value) {
105 $configStr .= '$GLOBALS[\'config\'][\''. $key .'\'] = '.var_export($conf['config'][$key], true).';'. PHP_EOL; 106 $configStr .= '$GLOBALS[\'config\'][\''. $key .'\'] = '.var_export($conf['config'][$key], true).';'. PHP_EOL;
@@ -125,7 +126,7 @@ class ConfigPhp implements ConfigIO
125 /** 126 /**
126 * @inheritdoc 127 * @inheritdoc
127 */ 128 */
128 function getExtension() 129 public function getExtension()
129 { 130 {
130 return '.php'; 131 return '.php';
131 } 132 }