aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md2
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--Makefile14
-rw-r--r--application/LinkDB.php2
-rw-r--r--application/config/ConfigManager.php6
-rw-r--r--composer.json2
-rw-r--r--doc/md/Plugin-System.md4
-rw-r--r--doc/md/Plugins.md2
-rw-r--r--doc/md/Release-Shaarli.md6
-rw-r--r--doc/md/Security.md3
-rw-r--r--doc/md/Shaarli-configuration.md5
-rw-r--r--doc/md/index.md2
-rw-r--r--index.php174
-rw-r--r--plugins/playvideos/README.md2
-rw-r--r--tpl/default/js/shaarli.js6
-rw-r--r--tpl/default/loginform.html3
-rw-r--r--tpl/default/tools.html2
-rw-r--r--tpl/vintage/loginform.html4
18 files changed, 129 insertions, 112 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4b018cb4..60262d56 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -61,7 +61,7 @@ The documentation has been migrated to ReadTheDocs:
61This release introduces the REST API, and requires updating HTTP server 61This release introduces the REST API, and requires updating HTTP server
62configuration to enable URL rewriting, see: 62configuration to enable URL rewriting, see:
63- https://shaarli.github.io/api-documentation/ 63- https://shaarli.github.io/api-documentation/
64- https://github.com/shaarli/Shaarli/wiki/Server-configuration 64- https://shaarli.readthedocs.io/en/master/Server-configuration/
65 65
66**WARNING**: Shaarli now requires PHP 5.5+. 66**WARNING**: Shaarli now requires PHP 5.5+.
67 67
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index bb82951d..03564fd2 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -54,7 +54,7 @@ Please report any problem you might find.
54 * starting from branch ` master`, switch to a new branch (eg. `git checkout -b my-awesome-feature`) 54 * starting from branch ` master`, switch to a new branch (eg. `git checkout -b my-awesome-feature`)
55 * edit the required files (from the Github web interface or your text editor) 55 * edit the required files (from the Github web interface or your text editor)
56 * add and commit your changes with a meaningful commit message (eg `Cool new feature, fixes issue #1001`) 56 * add and commit your changes with a meaningful commit message (eg `Cool new feature, fixes issue #1001`)
57 * run unit tests against your patched version, see [Running unit tests](https://github.com/shaarli/Shaarli/wiki/Running-unit-tests) 57 * run unit tests against your patched version, see [Running unit tests](https://shaarli.readthedocs.io/en/master/Unit-tests/#run-unit-tests)
58 * Open your fork in the Github web interface and click the "Compare and Pull Request" button, enter required info and submit your Pull Request. 58 * Open your fork in the Github web interface and click the "Compare and Pull Request" button, enter required info and submit your Pull Request.
59 59
60All changes you will do on the `my-awesome-feature` in the future will be added to your Pull Request. Don't work directly on the master branch, don't do unrelated work on your `my-awesome-feature` branch. 60All changes you will do on the `my-awesome-feature` in the future will be added to your Pull Request. Don't work directly on the master branch, don't do unrelated work on your `my-awesome-feature` branch.
diff --git a/Makefile b/Makefile
index 6483fca7..40badb1d 100644
--- a/Makefile
+++ b/Makefile
@@ -159,14 +159,14 @@ composer_dependencies: clean
159 find vendor/ -name ".git" -type d -exec rm -rf {} + 159 find vendor/ -name ".git" -type d -exec rm -rf {} +
160 160
161### generate a release tarball and include 3rd-party dependencies 161### generate a release tarball and include 3rd-party dependencies
162release_tar: composer_dependencies doc_html 162release_tar: composer_dependencies htmldoc
163 git archive --prefix=$(ARCHIVE_PREFIX) -o $(ARCHIVE_VERSION).tar HEAD 163 git archive --prefix=$(ARCHIVE_PREFIX) -o $(ARCHIVE_VERSION).tar HEAD
164 tar rvf $(ARCHIVE_VERSION).tar --transform "s|^vendor|$(ARCHIVE_PREFIX)vendor|" vendor/ 164 tar rvf $(ARCHIVE_VERSION).tar --transform "s|^vendor|$(ARCHIVE_PREFIX)vendor|" vendor/
165 tar rvf $(ARCHIVE_VERSION).tar --transform "s|^doc/html|$(ARCHIVE_PREFIX)doc/html|" doc/html/ 165 tar rvf $(ARCHIVE_VERSION).tar --transform "s|^doc/html|$(ARCHIVE_PREFIX)doc/html|" doc/html/
166 gzip $(ARCHIVE_VERSION).tar 166 gzip $(ARCHIVE_VERSION).tar
167 167
168### generate a release zip and include 3rd-party dependencies 168### generate a release zip and include 3rd-party dependencies
169release_zip: composer_dependencies doc_html 169release_zip: composer_dependencies htmldoc
170 git archive --prefix=$(ARCHIVE_PREFIX) -o $(ARCHIVE_VERSION).zip -9 HEAD 170 git archive --prefix=$(ARCHIVE_PREFIX) -o $(ARCHIVE_VERSION).zip -9 HEAD
171 mkdir -p $(ARCHIVE_PREFIX)/{doc,vendor} 171 mkdir -p $(ARCHIVE_PREFIX)/{doc,vendor}
172 rsync -a doc/html/ $(ARCHIVE_PREFIX)doc/html/ 172 rsync -a doc/html/ $(ARCHIVE_PREFIX)doc/html/
@@ -195,17 +195,11 @@ doxygen: clean
195 @rm -rf doxygen 195 @rm -rf doxygen
196 @( cat Doxyfile ; echo "PROJECT_NUMBER=`git describe`" ) | doxygen - 196 @( cat Doxyfile ; echo "PROJECT_NUMBER=`git describe`" ) | doxygen -
197 197
198### Convert local markdown documentation to HTML 198### generate HTML documentation from Markdown pages with MkDocs
199# 199htmldoc:
200# For all pages:
201# - convert GitHub-flavoured relative links to standard Markdown
202# - generate html documentation with mkdocs
203htmlpages:
204 python3 -m venv venv/ 200 python3 -m venv venv/
205 bash -c 'source venv/bin/activate; \ 201 bash -c 'source venv/bin/activate; \
206 pip install mkdocs; \ 202 pip install mkdocs; \
207 mkdocs build' 203 mkdocs build'
208 find doc/html/ -type f -exec chmod a-x '{}' \; 204 find doc/html/ -type f -exec chmod a-x '{}' \;
209 rm -r venv 205 rm -r venv
210
211doc_html: authors htmlpages
diff --git a/application/LinkDB.php b/application/LinkDB.php
index 9308164a..22c1f0ab 100644
--- a/application/LinkDB.php
+++ b/application/LinkDB.php
@@ -249,7 +249,7 @@ class LinkDB implements Iterator, Countable, ArrayAccess
249 $link = array( 249 $link = array(
250 'id' => 1, 250 'id' => 1,
251 'title'=>' Shaarli: the personal, minimalist, super-fast, no-database delicious clone', 251 'title'=>' Shaarli: the personal, minimalist, super-fast, no-database delicious clone',
252 'url'=>'https://github.com/shaarli/Shaarli/wiki', 252 'url'=>'https://shaarli.readthedocs.io',
253 'description'=>'Welcome to Shaarli! This is your first public bookmark. To edit or delete me, you must first login. 253 'description'=>'Welcome to Shaarli! This is your first public bookmark. To edit or delete me, you must first login.
254 254
255To learn how to use Shaarli, consult the link "Help/documentation" at the bottom of this page. 255To learn how to use Shaarli, consult the link "Help/documentation" at the bottom of this page.
diff --git a/application/config/ConfigManager.php b/application/config/ConfigManager.php
index 8eab26f1..fdd5b3d7 100644
--- a/application/config/ConfigManager.php
+++ b/application/config/ConfigManager.php
@@ -9,8 +9,8 @@ use Shaarli\Config\Exception\UnauthorizedConfigException;
9 * 9 *
10 * Manages all Shaarli's settings. 10 * Manages all Shaarli's settings.
11 * See the documentation for more information on settings: 11 * See the documentation for more information on settings:
12 * - doc/Shaarli-configuration.html 12 * - doc/md/Shaarli-configuration.md
13 * - https://github.com/shaarli/Shaarli/wiki/Shaarli-configuration 13 * - https://shaarli.readthedocs.io/en/master/Shaarli-configuration/#configuration
14 */ 14 */
15class ConfigManager 15class ConfigManager
16{ 16{
@@ -328,6 +328,8 @@ class ConfigManager
328 $this->setEmpty('privacy.default_private_links', false); 328 $this->setEmpty('privacy.default_private_links', false);
329 $this->setEmpty('privacy.hide_public_links', false); 329 $this->setEmpty('privacy.hide_public_links', false);
330 $this->setEmpty('privacy.hide_timestamps', false); 330 $this->setEmpty('privacy.hide_timestamps', false);
331 // default state of the 'remember me' checkbox of the login form
332 $this->setEmpty('privacy.remember_user_default', true);
331 333
332 $this->setEmpty('thumbnail.enable_thumbnails', true); 334 $this->setEmpty('thumbnail.enable_thumbnails', true);
333 $this->setEmpty('thumbnail.enable_localcache', true); 335 $this->setEmpty('thumbnail.enable_localcache', true);
diff --git a/composer.json b/composer.json
index 756ea588..afb8aca4 100644
--- a/composer.json
+++ b/composer.json
@@ -6,7 +6,7 @@
6 "homepage": "https://github.com/shaarli/Shaarli", 6 "homepage": "https://github.com/shaarli/Shaarli",
7 "support": { 7 "support": {
8 "issues": "https://github.com/shaarli/Shaarli/issues", 8 "issues": "https://github.com/shaarli/Shaarli/issues",
9 "wiki": "https://github.com/shaarli/Shaarli/wiki" 9 "wiki": "https://shaarli.readthedocs.io"
10 }, 10 },
11 "keywords": ["bookmark", "link", "share", "web"], 11 "keywords": ["bookmark", "link", "share", "web"],
12 "config": { 12 "config": {
diff --git a/doc/md/Plugin-System.md b/doc/md/Plugin-System.md
index 30f0ae74..cbec04c0 100644
--- a/doc/md/Plugin-System.md
+++ b/doc/md/Plugin-System.md
@@ -49,10 +49,10 @@ hook_<plugin_name>_<hook_name>($data, $conf)
49 49
50Parameters: 50Parameters:
51 51
52- data: see [$data section](https://github.com/shaarli/Shaarli/wiki/Plugin-System#plugins-data) 52- data: see [$data section](https://shaarli.readthedocs.io/en/master/Plugin-System/#plugins-data)
53- conf: the `ConfigManager` instance. 53- conf: the `ConfigManager` instance.
54 54
55For exemple, if my plugin want to add data to the header, this function is needed: 55For example, if my plugin want to add data to the header, this function is needed:
56 56
57 hook_demo_plugin_render_header 57 hook_demo_plugin_render_header
58 58
diff --git a/doc/md/Plugins.md b/doc/md/Plugins.md
index 7d40637f..463dae17 100644
--- a/doc/md/Plugins.md
+++ b/doc/md/Plugins.md
@@ -72,4 +72,4 @@ Usage of each plugin is documented in it's README file:
72 72
73#### Third party plugins 73#### Third party plugins
74 74
75See [Community & related software](https://github.com/shaarli/Shaarli/wiki/Community-%26-Related-software#third-party-plugins) 75See [Community & related software](https://shaarli.readthedocs.io/en/master/Community-&-Related-software/)
diff --git a/doc/md/Release-Shaarli.md b/doc/md/Release-Shaarli.md
index 974a7438..e22eabc9 100644
--- a/doc/md/Release-Shaarli.md
+++ b/doc/md/Release-Shaarli.md
@@ -46,6 +46,12 @@ TBA
46 46
47 47
48## Increment the version code, update docs, create and push a signed tag 48## Increment the version code, update docs, create and push a signed tag
49### Update the list of Git contributors
50```bash
51$ make authors
52$ git commit -s -m "Update AUTHORS"
53```
54
49### Create and merge a Pull Request 55### Create and merge a Pull Request
50This one is pretty straightforward ;-) 56This one is pretty straightforward ;-)
51 57
diff --git a/doc/md/Security.md b/doc/md/Security.md
index 36f629af..65db4225 100644
--- a/doc/md/Security.md
+++ b/doc/md/Security.md
@@ -1,9 +1,6 @@
1## Client browser 1## Client browser
2- Shaarli relies on `HTTP_REFERER` for some functions (like redirects and clicking on tags). If you have disabled or masqueraded `HTTP_REFERER` in your browser, some features of Shaarli may not work 2- Shaarli relies on `HTTP_REFERER` for some functions (like redirects and clicking on tags). If you have disabled or masqueraded `HTTP_REFERER` in your browser, some features of Shaarli may not work
3 3
4## PHP
5- `magic_quotes` is an horrible option of PHP which is often activated on servers. No serious developer should rely on this horror to secure their code against SQL injections. You should disable it (and Shaarli expects this option to be disabled). Nevertheless, I have added code to cope with `magic_quotes` on, so you should not be bothered even on crappy hosts.
6
7## Server and sessions 4## Server and sessions
8- Directories are protected using `.htaccess` files 5- Directories are protected using `.htaccess` files
9- Forms are protected against XSRF (Cross-site requests forgery): 6- Forms are protected against XSRF (Cross-site requests forgery):
diff --git a/doc/md/Shaarli-configuration.md b/doc/md/Shaarli-configuration.md
index 188a3c09..d90e95eb 100644
--- a/doc/md/Shaarli-configuration.md
+++ b/doc/md/Shaarli-configuration.md
@@ -91,6 +91,8 @@ _These settings should not be edited_
91- **default_private_links**: Check the private checkbox by default for every new link. 91- **default_private_links**: Check the private checkbox by default for every new link.
92- **hide_public_links**: All links are hidden while logged out. 92- **hide_public_links**: All links are hidden while logged out.
93- **hide_timestamps**: Timestamps are hidden. 93- **hide_timestamps**: Timestamps are hidden.
94- **remember_user_default**: Default state of the login page's *remember me* checkbox
95 - `true`: checked by default, `false`: unchecked by default
94 96
95### Feed 97### Feed
96 98
@@ -192,7 +194,8 @@ _These settings should not be edited_
192 "privacy": { 194 "privacy": {
193 "default_private_links": true, 195 "default_private_links": true,
194 "hide_public_links": false, 196 "hide_public_links": false,
195 "hide_timestamps": false 197 "hide_timestamps": false,
198 "remember_user_default": true
196 }, 199 },
197 "thumbnail": { 200 "thumbnail": {
198 "enable_thumbnails": true, 201 "enable_thumbnails": true,
diff --git a/doc/md/index.md b/doc/md/index.md
index b10e3cf4..24ada6c7 100644
--- a/doc/md/index.md
+++ b/doc/md/index.md
@@ -37,7 +37,7 @@ Login: `demo`; Password: `demo`
37 - daily RSS feed 37 - daily RSS feed
38- permalinks for easy reference 38- permalinks for easy reference
39- links can be public or private 39- links can be public or private
40- extensible through [plugins](https://github.com/shaarli/Shaarli/wiki/Plugins#plugin-usage) 40- extensible through [plugins](https://shaarli.readthedocs.io/en/master/Plugins/#plugin-usage)
41 41
42### Tag, view and search your links! 42### Tag, view and search your links!
43- add a custom title and description to archived links 43- add a custom title and description to archived links
diff --git a/index.php b/index.php
index de993f14..218d317d 100644
--- a/index.php
+++ b/index.php
@@ -48,8 +48,8 @@ if (! file_exists(__DIR__ . '/vendor/autoload.php')) {
48 ."If you installed Shaarli through Git or using the development branch,\n" 48 ."If you installed Shaarli through Git or using the development branch,\n"
49 ."please refer to the installation documentation to install PHP" 49 ."please refer to the installation documentation to install PHP"
50 ." dependencies using Composer:\n" 50 ." dependencies using Composer:\n"
51 ."- https://github.com/shaarli/Shaarli/wiki/Server-requirements\n" 51 ."- https://shaarli.readthedocs.io/en/master/Server-requirements/\n"
52 ."- https://github.com/shaarli/Shaarli/wiki/Download-and-Installation"; 52 ."- https://shaarli.readthedocs.io/en/master/Download-and-Installation/";
53 exit; 53 exit;
54} 54}
55require_once 'inc/rain.tpl.class.php'; 55require_once 'inc/rain.tpl.class.php';
@@ -133,15 +133,6 @@ date_default_timezone_set($conf->get('general.timezone', 'UTC'));
133 133
134ob_start(); // Output buffering for the page cache. 134ob_start(); // Output buffering for the page cache.
135 135
136// In case stupid admin has left magic_quotes enabled in php.ini:
137if (get_magic_quotes_gpc())
138{
139 function stripslashes_deep($value) { $value = is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value); return $value; }
140 $_POST = array_map('stripslashes_deep', $_POST);
141 $_GET = array_map('stripslashes_deep', $_GET);
142 $_COOKIE = array_map('stripslashes_deep', $_COOKIE);
143}
144
145// Prevent caching on client side or proxy: (yes, it's ugly) 136// Prevent caching on client side or proxy: (yes, it's ugly)
146header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); 137header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
147header("Cache-Control: no-store, no-cache, must-revalidate"); 138header("Cache-Control: no-store, no-cache, must-revalidate");
@@ -186,42 +177,42 @@ if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
186 */ 177 */
187function setup_login_state($conf) 178function setup_login_state($conf)
188{ 179{
189 if ($conf->get('security.open_shaarli')) { 180 if ($conf->get('security.open_shaarli')) {
190 return true; 181 return true;
191 } 182 }
192 $userIsLoggedIn = false; // By default, we do not consider the user as logged in; 183 $userIsLoggedIn = false; // By default, we do not consider the user as logged in;
193 $loginFailure = false; // If set to true, every attempt to authenticate the user will fail. This indicates that an important condition isn't met. 184 $loginFailure = false; // If set to true, every attempt to authenticate the user will fail. This indicates that an important condition isn't met.
194 if (! $conf->exists('credentials.login')) { 185 if (! $conf->exists('credentials.login')) {
195 $userIsLoggedIn = false; // Shaarli is not configured yet. 186 $userIsLoggedIn = false; // Shaarli is not configured yet.
196 $loginFailure = true; 187 $loginFailure = true;
197 } 188 }
198 if (isset($_COOKIE['shaarli_staySignedIn']) && 189 if (isset($_COOKIE['shaarli_staySignedIn']) &&
199 $_COOKIE['shaarli_staySignedIn']===STAY_SIGNED_IN_TOKEN && 190 $_COOKIE['shaarli_staySignedIn']===STAY_SIGNED_IN_TOKEN &&
200 !$loginFailure) 191 !$loginFailure)
201 { 192 {
202 fillSessionInfo($conf); 193 fillSessionInfo($conf);
203 $userIsLoggedIn = true; 194 $userIsLoggedIn = true;
204 } 195 }
205 // If session does not exist on server side, or IP address has changed, or session has expired, logout. 196 // If session does not exist on server side, or IP address has changed, or session has expired, logout.
206 if (empty($_SESSION['uid']) 197 if (empty($_SESSION['uid'])
207 || ($conf->get('security.session_protection_disabled') === false && $_SESSION['ip'] != allIPs()) 198 || ($conf->get('security.session_protection_disabled') === false && $_SESSION['ip'] != allIPs())
208 || time() >= $_SESSION['expires_on']) 199 || time() >= $_SESSION['expires_on'])
209 { 200 {
210 logout(); 201 logout();
211 $userIsLoggedIn = false; 202 $userIsLoggedIn = false;
212 $loginFailure = true; 203 $loginFailure = true;
213 } 204 }
214 if (!empty($_SESSION['longlastingsession'])) { 205 if (!empty($_SESSION['longlastingsession'])) {
215 $_SESSION['expires_on']=time()+$_SESSION['longlastingsession']; // In case of "Stay signed in" checked. 206 $_SESSION['expires_on']=time()+$_SESSION['longlastingsession']; // In case of "Stay signed in" checked.
216 } 207 }
217 else { 208 else {
218 $_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT; // Standard session expiration date. 209 $_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT; // Standard session expiration date.
219 } 210 }
220 if (!$loginFailure) { 211 if (!$loginFailure) {
221 $userIsLoggedIn = true; 212 $userIsLoggedIn = true;
222 } 213 }
223 214
224 return $userIsLoggedIn; 215 return $userIsLoggedIn;
225} 216}
226$userIsLoggedIn = setup_login_state($conf); 217$userIsLoggedIn = setup_login_state($conf);
227 218
@@ -245,10 +236,10 @@ function allIPs()
245 */ 236 */
246function fillSessionInfo($conf) 237function fillSessionInfo($conf)
247{ 238{
248 $_SESSION['uid'] = sha1(uniqid('',true).'_'.mt_rand()); // Generate unique random number (different than phpsessionid) 239 $_SESSION['uid'] = sha1(uniqid('',true).'_'.mt_rand()); // Generate unique random number (different than phpsessionid)
249 $_SESSION['ip']=allIPs(); // We store IP address(es) of the client to make sure session is not hijacked. 240 $_SESSION['ip']=allIPs(); // We store IP address(es) of the client to make sure session is not hijacked.
250 $_SESSION['username']= $conf->get('credentials.login'); 241 $_SESSION['username']= $conf->get('credentials.login');
251 $_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT; // Set session expiration. 242 $_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT; // Set session expiration.
252} 243}
253 244
254/** 245/**
@@ -265,7 +256,7 @@ function check_auth($login, $password, $conf)
265 $hash = sha1($password . $login . $conf->get('credentials.salt')); 256 $hash = sha1($password . $login . $conf->get('credentials.salt'));
266 if ($login == $conf->get('credentials.login') && $hash == $conf->get('credentials.hash')) 257 if ($login == $conf->get('credentials.login') && $hash == $conf->get('credentials.hash'))
267 { // Login/password is correct. 258 { // Login/password is correct.
268 fillSessionInfo($conf); 259 fillSessionInfo($conf);
269 logm($conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], 'Login successful'); 260 logm($conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], 'Login successful');
270 return true; 261 return true;
271 } 262 }
@@ -394,9 +385,10 @@ if (isset($_POST['login']))
394 // If user wants to keep the session cookie even after the browser closes: 385 // If user wants to keep the session cookie even after the browser closes:
395 if (!empty($_POST['longlastingsession'])) 386 if (!empty($_POST['longlastingsession']))
396 { 387 {
397 setcookie('shaarli_staySignedIn', STAY_SIGNED_IN_TOKEN, time()+31536000, WEB_PATH); 388 $_SESSION['longlastingsession'] = 31536000; // (31536000 seconds = 1 year)
398 $_SESSION['longlastingsession']=31536000; // (31536000 seconds = 1 year) 389 $expiration = time() + $_SESSION['longlastingsession']; // calculate relative cookie expiration (1 year from now)
399 $_SESSION['expires_on']=time()+$_SESSION['longlastingsession']; // Set session expiration on server-side. 390 setcookie('shaarli_staySignedIn', STAY_SIGNED_IN_TOKEN, $expiration, WEB_PATH);
391 $_SESSION['expires_on'] = $expiration; // Set session expiration on server-side.
400 392
401 $cookiedir = ''; if(dirname($_SERVER['SCRIPT_NAME'])!='/') $cookiedir=dirname($_SERVER["SCRIPT_NAME"]).'/'; 393 $cookiedir = ''; if(dirname($_SERVER['SCRIPT_NAME'])!='/') $cookiedir=dirname($_SERVER["SCRIPT_NAME"]).'/';
402 session_set_cookie_params($_SESSION['longlastingsession'],$cookiedir,$_SERVER['SERVER_NAME']); // Set session cookie expiration on client side 394 session_set_cookie_params($_SESSION['longlastingsession'],$cookiedir,$_SERVER['SERVER_NAME']); // Set session cookie expiration on client side
@@ -591,20 +583,29 @@ function showDailyRSS($conf) {
591 */ 583 */
592function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager) 584function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager)
593{ 585{
594 $day=date('Ymd',strtotime('-1 day')); // Yesterday, in format YYYYMMDD. 586 $day = date('Ymd', strtotime('-1 day')); // Yesterday, in format YYYYMMDD.
595 if (isset($_GET['day'])) $day=$_GET['day']; 587 if (isset($_GET['day'])) {
588 $day = $_GET['day'];
589 }
596 590
597 $days = $LINKSDB->days(); 591 $days = $LINKSDB->days();
598 $i = array_search($day,$days); 592 $i = array_search($day, $days);
599 if ($i===false) { $i=count($days)-1; $day=$days[$i]; } 593 if ($i === false && count($days)) {
600 $previousday=''; 594 // no links for day, but at least one day with links
601 $nextday=''; 595 $i = count($days) - 1;
602 if ($i!==false) 596 $day = $days[$i];
603 {
604 if ($i>=1) $previousday=$days[$i-1];
605 if ($i<count($days)-1) $nextday=$days[$i+1];
606 } 597 }
598 $previousday = '';
599 $nextday = '';
607 600
601 if ($i !== false) {
602 if ($i >= 1) {
603 $previousday=$days[$i - 1];
604 }
605 if ($i < count($days) - 1) {
606 $nextday = $days[$i + 1];
607 }
608 }
608 try { 609 try {
609 $linksToDisplay = $LINKSDB->filterDay($day); 610 $linksToDisplay = $LINKSDB->filterDay($day);
610 } catch (Exception $exc) { 611 } catch (Exception $exc) {
@@ -613,9 +614,7 @@ function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager)
613 } 614 }
614 615
615 // We pre-format some fields for proper output. 616 // We pre-format some fields for proper output.
616 foreach($linksToDisplay as $key=>$link) 617 foreach($linksToDisplay as $key => $link) {
617 {
618
619 $taglist = explode(' ',$link['tags']); 618 $taglist = explode(' ',$link['tags']);
620 uasort($taglist, 'strcasecmp'); 619 uasort($taglist, 'strcasecmp');
621 $linksToDisplay[$key]['taglist']=$taglist; 620 $linksToDisplay[$key]['taglist']=$taglist;
@@ -629,21 +628,22 @@ function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager)
629 so I manually spread entries with a simple method: I roughly evaluate the 628 so I manually spread entries with a simple method: I roughly evaluate the
630 height of a div according to title and description length. 629 height of a div according to title and description length.
631 */ 630 */
632 $columns=array(array(),array(),array()); // Entries to display, for each column. 631 $columns = array(array(), array(), array()); // Entries to display, for each column.
633 $fill=array(0,0,0); // Rough estimate of columns fill. 632 $fill = array(0, 0, 0); // Rough estimate of columns fill.
634 foreach($linksToDisplay as $key=>$link) 633 foreach($linksToDisplay as $key => $link) {
635 {
636 // Roughly estimate length of entry (by counting characters) 634 // Roughly estimate length of entry (by counting characters)
637 // Title: 30 chars = 1 line. 1 line is 30 pixels height. 635 // Title: 30 chars = 1 line. 1 line is 30 pixels height.
638 // Description: 836 characters gives roughly 342 pixel height. 636 // Description: 836 characters gives roughly 342 pixel height.
639 // This is not perfect, but it's usually OK. 637 // This is not perfect, but it's usually OK.
640 $length=strlen($link['title'])+(342*strlen($link['description']))/836; 638 $length = strlen($link['title']) + (342 * strlen($link['description'])) / 836;
641 if ($link['thumbnail']) $length +=100; // 1 thumbnails roughly takes 100 pixels height. 639 if ($link['thumbnail']) {
640 $length += 100; // 1 thumbnails roughly takes 100 pixels height.
641 }
642 // Then put in column which is the less filled: 642 // Then put in column which is the less filled:
643 $smallest=min($fill); // find smallest value in array. 643 $smallest = min($fill); // find smallest value in array.
644 $index=array_search($smallest,$fill); // find index of this smallest value. 644 $index = array_search($smallest, $fill); // find index of this smallest value.
645 array_push($columns[$index],$link); // Put entry in this column. 645 array_push($columns[$index], $link); // Put entry in this column.
646 $fill[$index]+=$length; 646 $fill[$index] += $length;
647 } 647 }
648 648
649 $dayDate = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $day.'_000000'); 649 $dayDate = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $day.'_000000');
@@ -745,6 +745,8 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
745 $PAGE->assign('username', escape($_GET['username'])); 745 $PAGE->assign('username', escape($_GET['username']));
746 } 746 }
747 $PAGE->assign('returnurl',(isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']):'')); 747 $PAGE->assign('returnurl',(isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']):''));
748 // add default state of the 'remember me' checkbox
749 $PAGE->assign('remember_user_default', $conf->get('privacy.remember_user_default'));
748 $PAGE->renderPage('loginform'); 750 $PAGE->renderPage('loginform');
749 exit; 751 exit;
750 } 752 }
@@ -803,7 +805,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
803 $maxcount = max($maxcount, $value); 805 $maxcount = max($maxcount, $value);
804 } 806 }
805 807
806 alphabetical_sort($tags, true, true); 808 alphabetical_sort($tags, false, true);
807 809
808 $tagList = array(); 810 $tagList = array();
809 foreach($tags as $key => $value) { 811 foreach($tags as $key => $value) {
@@ -1233,7 +1235,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
1233 // Linkdate is kept here to: 1235 // Linkdate is kept here to:
1234 // - use the same permalink for notes as they're displayed when creating them 1236 // - use the same permalink for notes as they're displayed when creating them
1235 // - let users hack creation date of their posts 1237 // - let users hack creation date of their posts
1236 // See: https://github.com/shaarli/Shaarli/wiki/Datastore-hacks#changing-the-timestamp-for-a-link 1238 // See: https://shaarli.readthedocs.io/en/master/Various-hacks/#changing-the-timestamp-for-a-shaare
1237 $linkdate = escape($_POST['lf_linkdate']); 1239 $linkdate = escape($_POST['lf_linkdate']);
1238 if (isset($LINKSDB[$id])) { 1240 if (isset($LINKSDB[$id])) {
1239 // Edit 1241 // Edit
@@ -1256,6 +1258,9 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
1256 // Remove duplicates. 1258 // Remove duplicates.
1257 $tags = implode(' ', array_unique(explode(' ', $tags))); 1259 $tags = implode(' ', array_unique(explode(' ', $tags)));
1258 1260
1261 if (empty(trim($_POST['lf_url']))) {
1262 $_POST['lf_url'] = '?' . smallHash($linkdate . $id);
1263 }
1259 $url = whitelist_protocols(trim($_POST['lf_url']), $conf->get('security.allowed_protocols')); 1264 $url = whitelist_protocols(trim($_POST['lf_url']), $conf->get('security.allowed_protocols'));
1260 1265
1261 $link = array( 1266 $link = array(
@@ -1325,10 +1330,17 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
1325 die('Wrong token.'); 1330 die('Wrong token.');
1326 } 1331 }
1327 1332
1328 if (strpos($_GET['lf_linkdate'], ' ') !== false) { 1333 $ids = trim($_GET['lf_linkdate']);
1329 $ids = array_values(array_filter(preg_split('/\s+/', escape($_GET['lf_linkdate'])))); 1334 if (strpos($ids, ' ') !== false) {
1335 // multiple, space-separated ids provided
1336 $ids = array_values(array_filter(preg_split('/\s+/', escape($ids))));
1330 } else { 1337 } else {
1331 $ids = [$_GET['lf_linkdate']]; 1338 // only a single id provided
1339 $ids = [$ids];
1340 }
1341 // assert at least one id is given
1342 if(!count($ids)){
1343 die('no id provided');
1332 } 1344 }
1333 foreach ($ids as $id) { 1345 foreach ($ids as $id) {
1334 $id = (int) escape($id); 1346 $id = (int) escape($id);
diff --git a/plugins/playvideos/README.md b/plugins/playvideos/README.md
index b1698470..ab4be22a 100644
--- a/plugins/playvideos/README.md
+++ b/plugins/playvideos/README.md
@@ -8,7 +8,7 @@ This uses code from https://zaius.github.io/youtube_playlist/ and is currently o
8 8
9#### Installation and setup 9#### Installation and setup
10 10
11This is a default Shaarli plugin, you just have to enable it. See https://github.com/shaarli/Shaarli/wiki/Shaarli-configuration/ 11This is a default Shaarli plugin, you just have to enable it. See https://shaarli.readthedocs.io/en/master/Shaarli-configuration/
12 12
13 13
14#### Troubleshooting 14#### Troubleshooting
diff --git a/tpl/default/js/shaarli.js b/tpl/default/js/shaarli.js
index e0b4c752..1c66ebbd 100644
--- a/tpl/default/js/shaarli.js
+++ b/tpl/default/js/shaarli.js
@@ -401,14 +401,14 @@ window.onload = function () {
401 401
402 var message = 'Are you sure you want to delete '+ links.length +' links?\n'; 402 var message = 'Are you sure you want to delete '+ links.length +' links?\n';
403 message += 'This action is IRREVERSIBLE!\n\nTitles:\n'; 403 message += 'This action is IRREVERSIBLE!\n\nTitles:\n';
404 var ids = ''; 404 var ids = [];
405 links.forEach(function(item) { 405 links.forEach(function(item) {
406 message += ' - '+ item['title'] +'\n'; 406 message += ' - '+ item['title'] +'\n';
407 ids += item['id'] +'+'; 407 ids.push(item['id']);
408 }); 408 });
409 409
410 if (window.confirm(message)) { 410 if (window.confirm(message)) {
411 window.location = '?delete_link&lf_linkdate='+ ids +'&token='+ token.value; 411 window.location = '?delete_link&lf_linkdate='+ ids.join('+') +'&token='+ token.value;
412 } 412 }
413 }); 413 });
414 } 414 }
diff --git a/tpl/default/loginform.html b/tpl/default/loginform.html
index eb6d8378..5777a218 100644
--- a/tpl/default/loginform.html
+++ b/tpl/default/loginform.html
@@ -30,7 +30,8 @@
30 </div> 30 </div>
31 <div class="remember-me"> 31 <div class="remember-me">
32 <input type="checkbox" name="longlastingsession" id="longlastingsessionform" 32 <input type="checkbox" name="longlastingsession" id="longlastingsessionform"
33 checked="checked" tabindex="22"> 33 {if="$remember_user_default"}checked="checked"{/if}
34 tabindex="22">
34 <label for="longlastingsessionform">{'Remember me'|t}</label> 35 <label for="longlastingsessionform">{'Remember me'|t}</label>
35 </div> 36 </div>
36 <div> 37 <div>
diff --git a/tpl/default/tools.html b/tpl/default/tools.html
index 35173d17..72fd58af 100644
--- a/tpl/default/tools.html
+++ b/tpl/default/tools.html
@@ -97,7 +97,7 @@
97 var%20desc=document.getSelection().toString(); 97 var%20desc=document.getSelection().toString();
98 if(desc.length>4000){ 98 if(desc.length>4000){
99 desc=desc.substr(0,4000)+'...'; 99 desc=desc.substr(0,4000)+'...';
100 alert("{function="str_replace(' ', '%20', t('The selected text is too long, it will be truncated.'))"}"); 100 alert('{function="str_replace(' ', '%20', t('The selected text is too long, it will be truncated.'))"}');
101 } 101 }
102 window.open( 102 window.open(
103 '{$pageabsaddr}?private=1&amp;post='+ 103 '{$pageabsaddr}?private=1&amp;post='+
diff --git a/tpl/vintage/loginform.html b/tpl/vintage/loginform.html
index 84176385..1becd44f 100644
--- a/tpl/vintage/loginform.html
+++ b/tpl/vintage/loginform.html
@@ -24,7 +24,9 @@
24 </label> 24 </label>
25 <input type="submit" value="Login" class="bigbutton" tabindex="4"> 25 <input type="submit" value="Login" class="bigbutton" tabindex="4">
26 <label for="longlastingsession"> 26 <label for="longlastingsession">
27 <input type="checkbox" name="longlastingsession" id="longlastingsession" tabindex="3"> 27 <input type="checkbox" name="longlastingsession"
28 id="longlastingsession" tabindex="3"
29 {if="$remember_user_default"}checked="checked"{/if}>
28 Stay signed in (Do not check on public computers)</label> 30 Stay signed in (Do not check on public computers)</label>
29 <input type="hidden" name="token" value="{$token}"> 31 <input type="hidden" name="token" value="{$token}">
30 {if="$returnurl"}<input type="hidden" name="returnurl" value="{$returnurl}">{/if} 32 {if="$returnurl"}<input type="hidden" name="returnurl" value="{$returnurl}">{/if}