diff options
-rw-r--r-- | MANUAL.md | 48 | ||||
-rw-r--r-- | app/class/Controller.php | 27 | ||||
-rw-r--r-- | app/class/Controllerconnect.php | 49 | ||||
-rw-r--r-- | app/class/Controlleruser.php | 29 | ||||
-rw-r--r-- | app/class/Modelconnect.php | 45 | ||||
-rw-r--r-- | app/class/Routes.php | 1 | ||||
-rw-r--r-- | app/class/Session.php | 6 | ||||
-rw-r--r-- | app/class/User.php | 58 | ||||
-rw-r--r-- | app/view/templates/user.php | 20 | ||||
-rw-r--r-- | composer.json | 1 | ||||
-rw-r--r-- | composer.lock | 53 |
11 files changed, 297 insertions, 40 deletions
@@ -26,7 +26,7 @@ This 4 steps tutorial will introduce you to the basic __W__ moves. The first thing you have to do before creating a page is to **choose an address** for this page. Each page have a unique address that identify it, it is the [**page id**](#page-id). You can use the address bar of your web browser to directly access, [edit](#edit) or [delete](#delete) a page. -You can type anything in your address bar. If it is an already exisiting page_id, you will access a page. Otherwise, you will arrive to an empty space waiting to be filled. +You can type anything in your address bar (after your W installation root). If it is an already exisiting page_id, you will access a page. Otherwise, you will arrive to an empty space waiting to be filled. Once you've typed an address and found nothing, if you are connected, you now have the opportunity to create a page at this address. @@ -69,7 +69,7 @@ One of the most interesting things to do when you use internet publishing, is to All those methods will create a link pointing to the `<page_id>` you've given. -Those kind of links are called internal links beccause they stay inside of your domain. To set a link outside of your website, simply remplace `<page_id>` by +Those kind of links are called internal links beccause they stay inside of your domain. To set a link outside of your website, simply remplace `<page_id>` by the website adress you whant to target (ex : `https://w-cms.top`), but this won't work with the third method as it is'nt a W page. #### Insert images @@ -114,7 +114,7 @@ In the home menu [super editors and above](#super-editor) can : - __File :__ Import pages as JSON file. (usefull for transfering pages from a W instance to another). - __Edit :__ Apply changes, render, or delete multiple pages at once. - __Filters :__ Use your [filtering options](#options) to generate a [automatic menu](#page-list) you can later include in a page. -- __Bookmarks :__ Save your [filtering options](#options) presets here. Common and personnal storages are possible. +- __Bookmarks :__ Create some [bookmarks](#bookmarks) to save your [filtering options](#options) as presets. - __Display :__ Set columns to be shown (user based) and tag colors. @@ -134,7 +134,7 @@ Just select the options you want and press "Fitler". Use the "Reset" button to c This panel is also usefull to set up a [page list](#page-list) to include the same list of page you've filtered in any page. -##### Pages +##### list view The table is composed of [meta](#meta-infos) datas and actions links that are : @@ -142,6 +142,15 @@ __EDIT__, __READ__, __DELETE__ and __DOWNLOAD__, they are equivalent to [pages c To edit columns you want to see, use the [menu](#home-menu)>Display submenu. +##### map view + +The map give you an overview of your website, showing you links between pages. + +By default orphans pages are hidden, but you can ajust settings to fit your needs. + +- left click on a page to read it +- right click to edit it + #### Edition The edition interface is accessible when [typing `/edit`](#edit) after an existing [page_id](#page-id) in the address bar. Or from the [home](#home), by clicking on the pencil button. @@ -177,13 +186,38 @@ When you need to use images, sound or videos in your pages, or any other type of ##### Media menu -The media menu allow you to do more powerfull function like moving medias or delete folders. +The media menu allow you to do more powerfull function like moving medias or delete folders it is only accessible by [super editors](#super-editor) and above. + +- __file :__ to import new files, create or delete directories +- __edit :__ to edit selected items +- __filter :__ to export filter settings as [medialist](#media-list) +- __Bookmarks :__ Create some [bookmarks](#bookmarks) to save your [filtering options](#media-filters) as presets. + + +##### Explorer + +The explorer allow you to navigate between differents directories. It will show you the amount of files in every folder. + +##### Media Filters + +By ajusting filters, you can #### Admin #### User manager +#### Bookmarks + +Bookmarks can be created as shortcuts to quickly jump to a specified view. + +There are two kinds of bookmarks : +- Home bookmarks +- Media bookmars + +Each one is doing the same thing : saving a specific filter setting and allow you to access it in one click. + +After ajusting [home options](#options), or [media filters](#media-filters), select the bookmark menu (in the [home menu](#home-menu) or [media menu](#media-menu)), add a name and a symbol, this will add a new bookmark in the main top bar ! @@ -451,6 +485,10 @@ Date and Time are just a By default, page's date and time are the same as creation date and time. +##### Datemodif + +You can't edit manualy this date. It's just the last time the page has been edited. + ##### Thumbnail The thumbnail have two use cases : diff --git a/app/class/Controller.php b/app/class/Controller.php index 11a2c12..c631726 100644 --- a/app/class/Controller.php +++ b/app/class/Controller.php @@ -45,17 +45,30 @@ class Controller public function setuser() { - if (empty($this->session->user)) { - $this->user = new User(); - } else { - if (!$this->user = $this->usermanager->get($this->session->user)) { - if (!$this->user = $this->usermanager->readcookie()) { - $this->user = new User(); + // check session, then cookies + if (!empty($this->session->user)) { + $user = $this->usermanager->get($this->session->user); + } elseif (!empty($_COOKIE['authtoken'])) { + try { + $modelconnect = new Modelconnect(); + $datas = $modelconnect->checkcookie(); + $user = $this->usermanager->get($datas['userid']); + if ($user !== false && $user->checksession($datas['wsession'])) { + $this->session->addtosession("wsession", $datas['wsession']); + $this->session->addtosession("user", $datas['userid']); } else { - $this->session->addtosession('user', $this->user->id()); + $user = false; } + } catch (Exception $e) { + Model::sendflashmessage("Invalid Autentification cookie exist : $e", "warning"); } } + // create visitor + if (empty($user)) { + $this->user = new User(); + } else { + $this->user = $user; + } } public function initplates() diff --git a/app/class/Controllerconnect.php b/app/class/Controllerconnect.php index 8347a8f..4790c63 100644 --- a/app/class/Controllerconnect.php +++ b/app/class/Controllerconnect.php @@ -2,8 +2,12 @@ namespace Wcms; +use RuntimeException; + class Controllerconnect extends Controller { + /** @var Modelconnect */ + protected $modelconnect; public function log() { @@ -38,21 +42,36 @@ class Controllerconnect extends Controller { if (!empty($_POST['pass']) && !empty($_POST['user'])) { $this->user = $this->usermanager->passwordcheck($_POST['user'], $_POST['pass']); - if ($this->user != false) { - if ( + if ( + $this->user != false + && ( $this->user->expiredate() === false || $this->user->level() === 10 || $this->user->expiredate('date') > $this->now - ) { - $this->user->connectcounter(); - $this->usermanager->add($this->user); - $this->session->addtosession('user', $this->user->id()); - - if ($_POST['rememberme'] && $this->user->cookie() > 0) { - $token = $this->createauthtoken(); - if ($token) { - $_SESSION['user' . Config::basepath()]['authtoken'] = $token; + ) + ) { + $this->user->connectcounter(); + $this->usermanager->add($this->user); + $this->session->addtosession('user', $this->user->id()); + + if ($_POST['rememberme']) { + if ($this->user->cookie() > 0) { + try { + $this->modelconnect = new Modelconnect(); + $wsession = $this->user->newsession(); + $this->modelconnect->createauthcookie( + $this->user->id(), + $wsession, + $this->user->cookie() + ); + $this->usermanager->add($this->user); + $this->session->addtosession('wsession', $wsession); + } catch (RuntimeException $e) { + Model::sendflashmessage("Can't create authentification cookie : $e", "warning"); } + } else { + $message = "Can't remember you beccause user cookie conservation time is set to 0 days"; + Model::sendflashmessage($message, "warning"); } } } @@ -66,11 +85,11 @@ class Controllerconnect extends Controller public function logout($route, $id = null) { - $this->user = $this->usermanager->logout(); $this->session->addtosession('user', ''); - if (!empty($_SESSION['user' . Config::basepath()]['authtoken'])) { - $this->destroyauthtoken($_SESSION['user' . Config::basepath()]['authtoken']); - } + $this->user->destroysession($this->session->wsession); + $this->session->addtosession('wsession', ''); + $this->usermanager->add($this->user); + if ($id !== null && $route !== 'home') { $this->routedirect($route, ['page' => $id]); } else { diff --git a/app/class/Controlleruser.php b/app/class/Controlleruser.php index 0345434..1e61c1a 100644 --- a/app/class/Controlleruser.php +++ b/app/class/Controlleruser.php @@ -40,9 +40,6 @@ class Controlleruser extends Controller } catch (RuntimeException $th) { Model::sendflashmessage('There was a problem when updating preference : ' . $th->getMessage(), 'error'); } - if ($_POST['passwordhash']) { - $user->hashpassword(); - } $this->usermanager->add($user); $this->routedirect('user'); } else { @@ -50,6 +47,32 @@ class Controlleruser extends Controller } } + public function password() + { + if ($this->user->iseditor()) { + if ( + !empty($_POST['password1']) && + !empty($_POST['password2']) && + $_POST['password1'] === $_POST['password2'] + ) { + if ( + $this->user->setpassword($_POST['password1']) && + $this->user->hashpassword() && + $this->usermanager->add($this->user) + ) { + Model::sendflashmessage('password updated successfully', 'success'); + } else { + Model::sendflashmessage("password is not compatible or an error occured", 'error'); + } + } else { + Model::sendflashmessage("passwords does not match", "error"); + } + $this->routedirect('user'); + } else { + $this->routedirect('home'); + } + } + public function bookmark() { diff --git a/app/class/Modelconnect.php b/app/class/Modelconnect.php new file mode 100644 index 0000000..1201d36 --- /dev/null +++ b/app/class/Modelconnect.php @@ -0,0 +1,45 @@ +<?php + +namespace Wcms; + +use Firebase\JWT\JWT; +use RuntimeException; +use Exception; + +class Modelconnect extends Model +{ + + /** + * @param string $userid + * @param string $wsession + * @param int $conservation + * @throws RuntimeException if secret key is not set or cant send cookie + */ + public function createauthcookie(string $userid, string $wsession, int $conservation) + { + $datas = [ + "userid" => $userid, + "wsession" => $wsession + ]; + if (empty(Config::secretkey())) { + throw new RuntimeException("Secret Key not set"); + } + $jwt = JWT::encode($datas, Config::secretkey()); + $cookie = setcookie('authtoken', $jwt, time() + $conservation * 24 * 3600, "", "", false, true); + if (!$cookie) { + throw new RuntimeException("Cant be send"); + } + } + + /** + * Check cookie using JWT + * @throws Exception + */ + public function checkcookie() + { + if (!empty($_COOKIE['authtoken'])) { + $datas = JWT::decode($_COOKIE['authtoken'], Config::secretkey(), ['HS256']); + return get_object_vars($datas); + } + } +} diff --git a/app/class/Routes.php b/app/class/Routes.php index 13bd2ac..65d8444 100644 --- a/app/class/Routes.php +++ b/app/class/Routes.php @@ -47,6 +47,7 @@ class Routes ['POST', '/!user/update', 'Controlleruser#update', 'userupdate'], ['POST', '/!user/bookmark', 'Controlleruser#bookmark', 'userbookmark'], ['POST', '/!user/pref', 'Controlleruser#pref', 'userpref'], + ['POST', '/!user/password', 'Controlleruser#password', 'userpassword'], ['POST', '/!user/token', 'Controlleruser#token', 'usertoken'], ['GET', '/!info', 'Controllerinfo#desktop', 'info'], ['GET', '/!timeline', 'Controllertimeline#desktop', 'timeline'], diff --git a/app/class/Session.php b/app/class/Session.php index 64b6b26..5228237 100644 --- a/app/class/Session.php +++ b/app/class/Session.php @@ -12,6 +12,7 @@ class Session extends Item public $showrightpanel = false; public $homedisplay = 'list'; public $mediadisplay = 'list'; + public $wsession = ''; public function __construct($datas = []) { @@ -78,4 +79,9 @@ class Session extends Item $this->mediadisplay = $mediadisplay; } } + + public function setwsession($wsession) + { + $this->wsession = $wsession; + } } diff --git a/app/class/User.php b/app/class/User.php index e78c10c..f9ea120 100644 --- a/app/class/User.php +++ b/app/class/User.php @@ -19,6 +19,8 @@ class User extends Item protected $expiredate = false; /** @var Bookmark[] Associative array as `id => Bookmark`*/ protected $bookmark = []; + /** @var array sessions */ + protected $sessions = []; protected $display = ['bookmark' => false]; public function __construct($datas = []) @@ -103,6 +105,11 @@ class User extends Item return $this->bookmark; } + public function sessions() + { + return $this->sessions; + } + public function display() { return $this->display; @@ -134,16 +141,18 @@ class User extends Item } } - public function setpassword($password) + /** + * @return bool if password is compatible and set, otherwise flase + */ + public function setpassword($password): bool { if (!empty($password) && is_string($password)) { if (strlen($password) >= Model::PASSWORD_MIN_LENGTH && strlen($password) <= Model::PASSWORD_MAX_LENGTH) { $this->password = $password; return true; - } else { - return false; } } + return false; } public function setsignature(string $signature) @@ -218,6 +227,13 @@ class User extends Item } } + public function setsessions($sessions) + { + if (is_array($sessions)) { + $this->sessions = $sessions; + } + } + public function setdisplay($display) { if (is_array($display)) { @@ -268,6 +284,42 @@ class User extends Item return false; } + /** + * Generate new unique session ID + * @param string $info session info to store + * @return string session key + */ + public function newsession(string $info = "no_info"): string + { + $exist = true; + while ($exist === true) { + $session = bin2hex(random_bytes(10)); + $exist = key_exists($session, $this->sessions()); + } + $this->sessions[$session] = $info; + return $session; + } + + /** + * Remove Session from user + * @param string $session session ID to remove + * @return bool true if session exist and was destroyed, false if key does not exist + */ + public function destroysession(string $session): bool + { + if (key_exists($session, $this->sessions)) { + unset($this->sessions[$session]); + return true; + } else { + return false; + } + } + + public function checksession(string $session): bool + { + return key_exists($session, $this->sessions); + } + public function isvisitor() diff --git a/app/view/templates/user.php b/app/view/templates/user.php index faa44aa..31df074 100644 --- a/app/view/templates/user.php +++ b/app/view/templates/user.php @@ -40,15 +40,25 @@ $this->layout('layout', ['title' => 'user', 'stylesheets' => [$css . 'home.css'] <label for="cookie">Cookie conservation time <i>(In days)</i></label> <p>When you tick the <em>remember-me</em> checkbox during login, you can choose how much time <strong>W</strong> will remember you.</p> - <input type="password" name="password" id="password" minlength="<?= Wcms\Model::PASSWORD_MIN_LENGTH ?>" maxlength="<?= Wcms\Model::PASSWORD_MAX_LENGTH ?>"> - <label for="password">New password</label> + <input type="submit" value="update preferences"> - <input type="hidden" name="passwordhash" value="1"> + </form> + + <form action="<?= $this->url('userpassword') ?>" method="post"> + <h3>Password</h3> + + <label for="password1">Type your new password</label> + </br> + <input type="password" name="password1" id="password1" minlength="<?= Wcms\Model::PASSWORD_MIN_LENGTH ?>" required> + </br> + <label for="password2">Confirm password</label> + </br> + <input type="password" name="password2" id="password2" minlength="<?= Wcms\Model::PASSWORD_MIN_LENGTH ?>" required> <p>Password have to be between <?= Wcms\Model::PASSWORD_MIN_LENGTH ?> and <?= Wcms\Model::PASSWORD_MAX_LENGTH ?> characters long.</p> - <input type="submit" value="update preferences"> - + <input type="submit" value="update password"> + </form> </div> diff --git a/composer.json b/composer.json index 95a2d94..dccf6ab 100644 --- a/composer.json +++ b/composer.json @@ -4,6 +4,7 @@ "require": { "php": ">=7.2.0", "altorouter/altorouter": "^1.2", + "firebase/php-jwt": "^5.2", "jamesmoss/flywheel": "^0.5.2", "league/plates": "^3.3", "michelf/php-markdown": "^1.8" diff --git a/composer.lock b/composer.lock index 5606478..7d41d88 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "6da5a2cb510d9953dfe07df3411f9cd9", + "content-hash": "271a2f7b5c32b5641b02ea8f50d55f73", "packages": [ { "name": "altorouter/altorouter", @@ -62,6 +62,56 @@ "time": "2015-11-30T00:47:43+00:00" }, { + "name": "firebase/php-jwt", + "version": "v5.2.0", + "source": { + "type": "git", + "url": "https://github.com/firebase/php-jwt.git", + "reference": "feb0e820b8436873675fd3aca04f3728eb2185cb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/feb0e820b8436873675fd3aca04f3728eb2185cb", + "reference": "feb0e820b8436873675fd3aca04f3728eb2185cb", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": ">=4.8 <=9" + }, + "type": "library", + "autoload": { + "psr-4": { + "Firebase\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Neuman Vong", + "email": "neuman+pear@twilio.com", + "role": "Developer" + }, + { + "name": "Anant Narayanan", + "email": "anant@php.net", + "role": "Developer" + } + ], + "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", + "homepage": "https://github.com/firebase/php-jwt", + "keywords": [ + "jwt", + "php" + ], + "time": "2020-03-25T18:49:23+00:00" + }, + { "name": "jamesmoss/flywheel", "version": "0.5.3", "source": { @@ -3359,7 +3409,6 @@ "psr", "psr-7" ], - "abandoned": "laminas/laminas-diactoros", "time": "2019-11-13T19:16:13+00:00" } ], |