diff options
-rw-r--r-- | app/class/Application.php | 32 | ||||
-rw-r--r-- | app/class/Config.php | 116 | ||||
-rw-r--r-- | app/class/Controller.php | 4 | ||||
-rw-r--r-- | app/class/Controllerconnect.php | 66 | ||||
-rw-r--r-- | app/class/Controlleruser.php | 21 | ||||
-rw-r--r-- | app/class/Header.php | 24 | ||||
-rw-r--r-- | app/class/Modelauthtoken.php | 72 | ||||
-rw-r--r-- | app/class/Modelhome.php | 1 | ||||
-rw-r--r-- | app/class/Modelrender.php | 20 | ||||
-rw-r--r-- | app/class/Modeluser.php | 42 | ||||
-rw-r--r-- | app/class/Opt.php | 20 | ||||
-rw-r--r-- | app/class/Page.php | 5 | ||||
-rw-r--r-- | app/class/Routes.php | 1 | ||||
-rw-r--r-- | app/class/Summary.php | 62 | ||||
-rw-r--r-- | app/fn/fn.php | 13 | ||||
-rw-r--r-- | app/view/templates/backtopbar.php | 3 | ||||
-rw-r--r-- | app/view/templates/connect.php | 3 | ||||
-rw-r--r-- | app/view/templates/homeopt.php | 2 | ||||
-rw-r--r-- | app/view/templates/user.php | 29 | ||||
-rw-r--r-- | assets/css/home.css | 15 |
20 files changed, 384 insertions, 167 deletions
diff --git a/app/class/Application.php b/app/class/Application.php index 70c899f..4ddf37e 100644 --- a/app/class/Application.php +++ b/app/class/Application.php @@ -41,7 +41,7 @@ class Application } else { if(Config::readconfig()) { - if(!Config::checkbasepath() || empty(Config::pagetable()) || !is_dir(Model::RENDER_DIR) || !Config::checkdomain()) { + if(!Config::checkbasepath() || empty(Config::pagetable()) || !is_dir(Model::RENDER_DIR) || !Config::checkdomain() || empty(Config::secretkey())) { echo '<ul>'; if(!Config::checkbasepath()) { echo '<li>Wrong path</li>'; @@ -55,6 +55,9 @@ class Application if(!is_dir(Model::RENDER_DIR)) { echo '<li>Render path not existing</li>'; } + if(!is_dir(Model::RENDER_DIR)) { + echo '<li>Secret Key not set or not valid</li>'; + } echo '</ul>'; $this->configform(); exit; @@ -84,18 +87,25 @@ class Application <form action="" method="post"> <div> - <h2> - <label for="basepath">Path to W-CMS</label> - </h2> - <input type="text" name="configinit[basepath]" value="<?= Config::basepath() ?>" id="basepath"> - <p><i>Leave it empty if W-CMS is in your root folder, otherwise, indicate the subfolder(s) in witch you installed the CMS</i></p> + <h2> + <label for="basepath">Path to W-CMS</label> + </h2> + <input type="text" name="configinit[basepath]" value="<?= Config::basepath() ?>" id="basepath"> + <p><i>Leave it empty if W-CMS is in your root folder, otherwise, indicate the subfolder(s) in witch you installed the CMS</i></p> </div> <div> - <h2> - <label for="pagetable">Name of your database table</label> - </h2> - <input type="text" name="configinit[pagetable]" value="<?= Config::pagetable() ?>" id="pagetable"> - <p><i>Set the name of the first folder that is going to store all your work</i></p> + <h2> + <label for="pagetable">Name of your database table</label> + </h2> + <input type="text" name="configinit[pagetable]" value="<?= Config::pagetable() ?>" id="pagetable"> + <p><i>Set the name of the first folder that is going to store all your work</i></p> + </div> + <div> + <h2> + <label for="secretkey">Secret Key</label> + </h2> + <input type="text" name="configinit[secretkey]" value="<?= bin2hex(random_bytes(10)) ?>" id="secretkey" minlength="16" maxlength="128" required> + <p><i>The secret key is used to secure cookies. There are no need to remind it. (16 to 128 characters)</i></p> </div> <input type="submit" value="set"> </form> diff --git a/app/class/Config.php b/app/class/Config.php index 2cfdcd3..4736410 100644 --- a/app/class/Config.php +++ b/app/class/Config.php @@ -11,7 +11,7 @@ abstract class Config protected static $domain = ''; protected static $fontsize = 15; protected static $basepath = ''; - protected static $route404; + protected static $route404; protected static $alerttitle = ''; protected static $alertlink = ''; protected static $alertlinktext = ''; @@ -22,10 +22,10 @@ abstract class Config protected static $privatepass = false; protected static $notpublishedpass = false; protected static $alertcss = false; - protected static $defaultbody = '%HEADER%'. PHP_EOL .PHP_EOL . '%NAV%'. PHP_EOL .PHP_EOL . '%ASIDE%'. PHP_EOL .PHP_EOL . '%MAIN%'. PHP_EOL .PHP_EOL . '%FOOTER%'; + protected static $defaultbody = '%HEADER%' . PHP_EOL . PHP_EOL . '%NAV%' . PHP_EOL . PHP_EOL . '%ASIDE%' . PHP_EOL . PHP_EOL . '%MAIN%' . PHP_EOL . PHP_EOL . '%FOOTER%'; protected static $defaultfavicon = ''; protected static $defaultthumbnail = ''; - protected static $analytics = ''; + protected static $analytics = ''; protected static $externallinkblank = true; protected static $internallinkblank = false; protected static $reccursiverender = true; @@ -34,10 +34,14 @@ abstract class Config protected static $homeredirect = null; protected static $interfacecss = null; protected static $bookmark = []; + protected static $secretkey = null; protected static $sentrydsn = ''; + const SECRET_KEY_MIN = 16; + const SECRET_KEY_MAX = 128; -// _______________________________________ F U N _______________________________________ + + // _______________________________________ F U N _______________________________________ @@ -92,9 +96,9 @@ abstract class Config /** * Calculate Domain name */ - public static function getdomain() - { - self::$domain = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST']; + public static function getdomain() + { + self::$domain = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST']; } /** @@ -109,12 +113,12 @@ abstract class Config * Generate full url adress where W is installed * @return string url adress finished by a slash "/" */ - public static function url($endslash = true) : string + public static function url($endslash = true): string { return self::$domain . (!empty(self::$basepath) ? '/' . self::$basepath : "") . ($endslash ? '/' : ''); } -// ________________________________________ G E T _______________________________________ + // ________________________________________ G E T _______________________________________ public static function pagetable() { @@ -134,9 +138,9 @@ abstract class Config /** * @param bool $trailingslash If not empty basepath, add a trailing slash after the basepath */ - public static function basepath(bool $trailingslash = false) : string + public static function basepath(bool $trailingslash = false): string { - if($trailingslash && !empty(self::$basepath)) { + if ($trailingslash && !empty(self::$basepath)) { return self::$basepath . '/'; } else { return self::$basepath; @@ -187,12 +191,12 @@ abstract class Config { return self::$privatepass; } - + public static function notpublishedpass() { return self::$notpublishedpass; } - + public static function alertcss() { return self::$alertcss; @@ -258,13 +262,18 @@ abstract class Config return self::$bookmark; } + public static function secretkey() + { + return self::$secretkey; + } + public static function sentrydsn() { return self::$sentrydsn; } -// __________________________________________ S E T ______________________________________ + // __________________________________________ S E T ______________________________________ public static function setpagetable($pagetable) { @@ -291,68 +300,68 @@ abstract class Config public static function setroute404($id) { - if(is_string($id)) { + if (is_string($id)) { self::$route404 = idclean($id); } } public static function setalerttitle($alerttitle) { - if(is_string($alerttitle)) { + if (is_string($alerttitle)) { self::$alerttitle = strip_tags($alerttitle); } } public static function setalertlink($alertlink) { - if(is_string($alertlink)) { + if (is_string($alertlink)) { self::$alertlink = idclean(strip_tags($alertlink)); } } public static function setalertlinktext($alertlinktext) { - if(is_string($alertlinktext)) { + if (is_string($alertlinktext)) { self::$alertlinktext = strip_tags($alertlinktext); } } public static function setexistnot($existnot) { - if(is_string($existnot)) { + if (is_string($existnot)) { self::$existnot = strip_tags($existnot); } } public static function setprivate($private) { - if(is_string($private)) { + if (is_string($private)) { self::$private = strip_tags($private); } } public static function setnotpublished($notpublished) { - if(is_string($notpublished)) { + if (is_string($notpublished)) { self::$notpublished = strip_tags($notpublished); } } - + public static function setexistnotpass($existnotpass) { self::$existnotpass = boolval($existnotpass); } - + public static function setprivatepass($privatepass) { self::$privatepass = boolval($privatepass); } - + public static function setnotpublishedpass($notpublishedpass) { self::$notpublishedpass = boolval($notpublishedpass); } - + public static function setalertcss($alertcss) { self::$alertcss = boolval($alertcss); @@ -360,32 +369,32 @@ abstract class Config public static function setdefaultbody($defaultbody) { - if(is_string($defaultbody)) { + if (is_string($defaultbody)) { self::$defaultbody = $defaultbody; } } public static function setdefaultfavicon($defaultfavicon) { - if(is_string($defaultfavicon)) { + if (is_string($defaultfavicon)) { self::$defaultfavicon = $defaultfavicon; } } public static function setdefaultthumbnail($defaultthumbnail) { - if(is_string($defaultthumbnail)) { + if (is_string($defaultthumbnail)) { self::$defaultthumbnail = $defaultthumbnail; } } public static function setanalytics($analytics) { - if(is_string($analytics) && strlen($analytics) < 25) { + if (is_string($analytics) && strlen($analytics) < 25) { self::$analytics = $analytics; } } - + public static function setexternallinkblank($externallinkblank) { self::$externallinkblank = boolval($externallinkblank); @@ -404,21 +413,21 @@ abstract class Config public static function setdefaultprivacy($defaultprivacy) { $defaultprivacy = intval($defaultprivacy); - if($defaultprivacy >= 0 && $defaultprivacy <= 2) { + if ($defaultprivacy >= 0 && $defaultprivacy <= 2) { self::$defaultprivacy = $defaultprivacy; } } public static function sethomepage($homepage) { - if(in_array($homepage, Model::HOMEPAGE)) { + if (in_array($homepage, Model::HOMEPAGE)) { self::$homepage = $homepage; } } public static function sethomeredirect($homeredirect) { - if(is_string($homeredirect) && strlen($homeredirect) > 0) { + if (is_string($homeredirect) && strlen($homeredirect) > 0) { self::$homeredirect = idclean($homeredirect); } else { self::$homeredirect = null; @@ -427,7 +436,7 @@ abstract class Config public static function setinterfacecss($interfacecss) { - if(is_string($interfacecss) && file_exists(Model::CSS_DIR . $interfacecss)) { + if (is_string($interfacecss) && file_exists(Model::CSS_DIR . $interfacecss)) { self::$interfacecss = $interfacecss; } else { self::$interfacecss = null; @@ -436,11 +445,24 @@ abstract class Config public static function setbookmark($bookmark) { - if(is_array($bookmark)) { + if (is_array($bookmark)) { self::$bookmark = $bookmark; } } + public static function setsecretkey($secretkey) + { + if (is_string($secretkey)) { + $stripedsecretkey = strip_tags($secretkey); + if ($stripedsecretkey === $secretkey) { + $length = strlen($secretkey); + if ($length < self::SECRET_KEY_MAX && $length > self::SECRET_KEY_MIN) { + self::$secretkey = $secretkey; + } + } + } + } + public static function setsentrydsn($sentrydsn) { if (is_string($sentrydsn)) { @@ -457,31 +479,17 @@ abstract class Config public static function addbookmark(string $id, string $query) { - if(!empty($id) && !empty($query)) { - $id = idclean($id); - $id = substr($id, 0, 16); - self::$bookmark[$id] = $query; + if (!empty($id) && !empty($query)) { + $id = idclean($id); + $id = substr($id, 0, 16); + self::$bookmark[$id] = $query; } } public static function deletebookmark(string $id) { - if(key_exists($id, self::$bookmark)) { + if (key_exists($id, self::$bookmark)) { unset(self::$bookmark[$id]); } } - - - - } - - - - - - - - - -?>
\ No newline at end of file diff --git a/app/class/Controller.php b/app/class/Controller.php index c3787b2..ab40a82 100644 --- a/app/class/Controller.php +++ b/app/class/Controller.php @@ -2,6 +2,7 @@ namespace Wcms; +use DateTime; use DateTimeImmutable; use League\Plates\Engine; @@ -34,7 +35,7 @@ class Controller public function setuser() { - $this->usermanager = new Modeluser; + $this->usermanager = new Modeluser; $this->user = $this->usermanager->readsession(); } @@ -63,6 +64,7 @@ class Controller $commonsparams['user'] = $this->user; $commonsparams['pagelist'] = $this->pagemanager->list(); $commonsparams['css'] = Model::csspath(); + $commonsparams['now'] = new DateTimeImmutable(); return $commonsparams; } diff --git a/app/class/Controllerconnect.php b/app/class/Controllerconnect.php index 592c0ee..e9af86a 100644 --- a/app/class/Controllerconnect.php +++ b/app/class/Controllerconnect.php @@ -21,7 +21,7 @@ class Controllerconnect extends Controller public function connect() { - if(isset($_SESSION['pageupdate'])) { + if (isset($_SESSION['pageupdate'])) { $pageupdate['route'] = 'pageedit'; $pageupdate['id'] = $_SESSION['pageupdate']['id']; } else { @@ -38,14 +38,22 @@ class Controllerconnect extends Controller { if (isset($_POST['pass'])) { $this->user = $this->usermanager->passwordcheck($_POST['pass']); - if($this->user != false) { - if($this->user->expiredate() === false || $this->user->level() === 10 || $this->user->expiredate('date') > $this->now) { + if ($this->user != false) { + if ($this->user->expiredate() === false || $this->user->level() === 10 || $this->user->expiredate('date') > $this->now) { $this->user->connectcounter(); $this->usermanager->add($this->user); $this->usermanager->writesession($this->user); $_SESSION['workspace']['showleftpanel'] = true; $_SESSION['workspace']['showrightpanel'] = false; - } + + if ($_POST['rememberme'] && $this->user->cookie() > 0) { + $token = $this->createauthtoken(); + if ($token) { + $_SESSION['user' . Config::basepath()]['authtoken'] = $token; + } + } + + } } } if ($id !== null) { @@ -59,6 +67,9 @@ class Controllerconnect extends Controller { $this->user = $this->usermanager->logout(); $this->usermanager->writesession($this->user); + if(!empty($_SESSION['user' . Config::basepath()]['authtoken'])) { + $this->destroyauthtoken($_SESSION['user' . Config::basepath()]['authtoken']); + } if ($id !== null && $route !== 'home') { $this->routedirect($route, ['page' => $id]); } else { @@ -66,13 +77,50 @@ class Controllerconnect extends Controller } } + /** + * Create a token stored in the database and then a cookie + * + * @return string|bool Token in cas of success, otherwise, false. + */ + public function createauthtoken() + { + $authtoken = new Modelauthtoken(); + $tokenid = $authtoken->add($this->user); + if ($tokenid !== false) { + $cookiecreation = $this->creatauthcookie($tokenid, $this->user->cookie()); + if ($cookiecreation) { + return $tokenid; + } + } else { + return false; + } + } -} - - - + /** + * Create a cookie called `authtoken` + * + * @param string $token Token string + * @param int $conservation Time in day to keep the token + * + * @return bool True in cas of success, otherwise, false. + */ + public function creatauthcookie(string $token, int $conservation): bool + { + $hash = secrethash($token); + $cookie = $token . ':' . $hash; + return setcookie('authtoken', $cookie, time() + $conservation * 24 * 3600, null, null, false, true); + } + /** + * Destroy the current token + */ + public function destroyauthtoken(string $id) + { + $authtoken = new Modelauthtoken(); + $dbdelete = $authtoken->delete($id); + //deleteauthcookie + } -?>
\ No newline at end of file +} diff --git a/app/class/Controlleruser.php b/app/class/Controlleruser.php index 3856914..0ec8092 100644 --- a/app/class/Controlleruser.php +++ b/app/class/Controlleruser.php @@ -12,12 +12,15 @@ class Controlleruser extends Controller public function desktop() { if($this->user->iseditor()) { - $getuser = $this->usermanager->get($this->user); + $authtokenmanager = new Modelauthtoken(); + $datas['tokenlist'] = $authtokenmanager->listbyuser($this->user->id()); + $datas['getuser'] = $this->usermanager->get($this->user); + if($this->user->isadmin()) { - $userlist = $this->usermanager->getlister(); - $this->showtemplate('user', ['userlist' => $userlist, 'getuser' => $getuser, 'now' => $this->now->format('Y-m-d')]); + $datas['userlist'] = $this->usermanager->getlister(); + $this->showtemplate('user', $datas); } else { - $this->showtemplate('user', ['getuser' => $getuser]); + $this->showtemplate('user', $datas); } } else { $this->routedirect('home'); @@ -59,6 +62,16 @@ class Controlleruser extends Controller } } + public function token() + { + if (isset($_POST['tokendelete'])) { + + $authtokenmanager = new Modelauthtoken(); + $authtokenmanager->delete($_POST['tokendelete']); + } + $this->routedirect('user'); + } + public function update() { if($this->user->isadmin() && isset($_POST['action'])) { diff --git a/app/class/Header.php b/app/class/Header.php new file mode 100644 index 0000000..0165e59 --- /dev/null +++ b/app/class/Header.php @@ -0,0 +1,24 @@ +<?php + +namespace Wcms; + +/** + * Simple "c struct like" class that represent a Header's datas. + * All members are public because there is no logic in this class. It is only + * used to pass data from one element to another with cleanly typed members. + */ +class Header +{ + /** @var string $id the id of this header. */ + public $id; + /** @var int $level the level of deepness of this header. */ + public $level; + /** @var string $title the title displayed by this header. */ + public $title; + + public function __construct(string $id, int $level, string $title) { + $this->id = $id; + $this->level = $level; + $this->title = $title; + } +} diff --git a/app/class/Modelauthtoken.php b/app/class/Modelauthtoken.php new file mode 100644 index 0000000..91a2a05 --- /dev/null +++ b/app/class/Modelauthtoken.php @@ -0,0 +1,72 @@ +<?php + +namespace Wcms; + +use DateTimeImmutable; +use JamesMoss\Flywheel\Document; + +class Modelauthtoken extends Modeldb +{ + + const AUTHTOKEN_REPO_NAME = 'authtoken'; + const AUTHTOKEN_ID_LENGTH = 30; + + public function __construct() + { + parent::__construct(); + $this->storeinit(self::AUTHTOKEN_REPO_NAME); + } + + /** + * Add a Token in the database according to the Users datas + * + * @param User $user + */ + public function add(User $user) + { + $datas = [ + 'user' => $user->id(), + 'ip' => $_SERVER['SERVER_ADDR'], + 'date' => new DateTimeImmutable(), + 'conservation' => $user->cookie(), + 'useragent' => $_SERVER['HTTP_USER_AGENT'] + ]; + $tokendata = new Document($datas); + + $exist = true; + while ($exist !== false) { + $id = bin2hex(random_bytes(self::AUTHTOKEN_ID_LENGTH)); + $exist = $this->repo->findById($id); + } + + $tokendata->setId($id); + return $this->repo->store($tokendata); + + } + + public function getbytoken(string $token) + { + return $this->repo->findById($token); + } + + public function delete(string $token) + { + return $this->repo->delete($token); + } + + /** + * @param string $id user Id + */ + public function listbyuser(string $id) + { + return $this->repo->query()->where('user', '==', $id)->orderBy('date')->execute(); + } + +} + + + + + + +?>
\ No newline at end of file diff --git a/app/class/Modelhome.php b/app/class/Modelhome.php index b7b063e..e8bdbf8 100644 --- a/app/class/Modelhome.php +++ b/app/class/Modelhome.php @@ -13,7 +13,6 @@ class Modelhome extends Modelpage { $opt = new Opt(); - $opt->setcol(['id', 'tag', 'linkto', 'description', 'title', 'datemodif', 'datecreation', 'date', 'secure', 'authors', 'visitcount', 'editcount', 'affcount']); $opt->settaglist($table); $opt->setauthorlist($table); $opt->setpageidlist($table); diff --git a/app/class/Modelrender.php b/app/class/Modelrender.php index 29a3fa7..091179d 100644 --- a/app/class/Modelrender.php +++ b/app/class/Modelrender.php @@ -437,17 +437,23 @@ class Modelrender extends Modelpage $max = 6; } - $sum = []; $text = preg_replace_callback( - '/<h([' . $min . '-' . $max . '])(\s+(\s*\w+="\w+")*)?\s*>(.+)<\/h[' . $min . '-' . $max . ']>/mU', - function ($matches) use (&$sum) { - $cleanid = idclean($matches[4]); - $sum[$cleanid][$matches[1]] = $matches[4]; - return '<h' . $matches[1] . $matches[2] . ' id="' . $cleanid . '">' . $matches[4] . '</h' . $matches[1] . '>'; + "/<h([$min-$max])((.*)id=\"([^\"]*)\"(.*)|.*)>(.+)<\/h[$min-$max]>/mU", + function ($matches) { + $level = $matches[1]; + $beforeid = $matches[3]; + $id = $matches[4]; + $afterid = $matches[5]; + $content = $matches[6]; + // if no custom id is defined, use idclean of the content as id + if (empty($id)) { + $id = idclean($content); + } + $this->sum[] = new Header($id, intval($level), $content); + return "<h$level $beforeid id=\"$id\" $afterid>$content</h$level>"; }, $text ); - $this->sum[$element] = $sum; return $text; } diff --git a/app/class/Modeluser.php b/app/class/Modeluser.php index 071320e..9ee04ba 100644 --- a/app/class/Modeluser.php +++ b/app/class/Modeluser.php @@ -21,16 +21,16 @@ class Modeluser extends Modeldb $this->storeinit(self::USER_REPO_NAME); } + /** + * Write session cookie according to users datas and define the current authtoken being used + * + * @param User $user Current user to keep in session + */ public function writesession(User $user) { - $_SESSION['user' . Config::basepath()] = ['level' => $user->level(), 'id' => $user->id(), 'columns' =>$user->columns()]; - } - - public function writecookie(User $user) - { - $cookiehash = - $cookie = ['level' => $user->level(), 'id' => $user->id()]; - setcookie('user ' . Config::basepath(), $cookie, time() + $user->cookie()*24*3600, null, null, false, true); + $_SESSION['user' . Config::basepath()]['level'] = $user->level(); + $_SESSION['user' . Config::basepath()]['id'] = $user->id(); + $_SESSION['user' . Config::basepath()]['columns'] = $user->columns(); } public function readsession() @@ -41,9 +41,27 @@ class Modeluser extends Modeldb $user = new User($userdatas); $user = $this->get($user); return $user; - } else { - return new User(['id' => '', 'level' => 0]); } + + if(isset($_COOKIE['authtoken']) && strpos($_COOKIE['authtoken'], ':')) { + list($cookietoken, $cookiemac) = explode(':', $_COOKIE['authtoken']); + $authtokenmanager = new Modelauthtoken(); + $dbtoken = $authtokenmanager->getbytoken($cookietoken); + + if ($dbtoken !== false) { + if(hash_equals($cookiemac, secrethash($dbtoken->getId()))) { + $user = $this->get($dbtoken->user); + if ($user !== false) { + $this->writesession($user, $_COOKIE['authtoken']); + } + return $user; + } + + } + } + + return new User(['id' => '', 'level' => 0]); + } @@ -56,7 +74,7 @@ class Modeluser extends Modeldb /** - * @return array list of User objects + * @return User[] associative array of User objects `id => User` */ public function getlister() { @@ -159,7 +177,7 @@ class Modeluser extends Modeldb /** - * @param string|User $id + * @param string|User $id Can be an User object or a string ID * * @return User|false User object or false in case of error */ diff --git a/app/class/Opt.php b/app/class/Opt.php index 59a3302..ecfbbc1 100644 --- a/app/class/Opt.php +++ b/app/class/Opt.php @@ -12,7 +12,6 @@ class Opt extends Item protected $authorcompare = 'AND'; protected $secure = 4; protected $linkto = ''; - protected $col = ['id']; protected $taglist = []; protected $authorlist = []; protected $invert = 0; @@ -25,7 +24,8 @@ class Opt extends Item public function __construct(array $data = []) { $this->hydrate($data); - $this->pagevarlist = get_object_vars(new Page()); + $page = new Page(); + $this->pagevarlist = ($page->getobjectvars()); } @@ -246,15 +246,6 @@ class Opt extends Item return $this->linkto; } - public function col($type = 'array') - { - if ($type == 'string') { - return implode(', ', $this->col); - } else { - return ($this->col); - } - } - public function taglist() { return $this->taglist; @@ -355,13 +346,6 @@ class Opt extends Item } } - public function setcol($col) - { - if (is_array($col)) { - $this->col = array_intersect($this->pagevarlist, $col); - } - } - public function settaglist(array $pagelist) { $taglist = []; diff --git a/app/class/Page.php b/app/class/Page.php index eefbca7..da19f61 100644 --- a/app/class/Page.php +++ b/app/class/Page.php @@ -64,6 +64,11 @@ class Page extends Dbitem $this->hydrate($datas); } + public function getobjectvars() : array + { + return get_object_vars($this); + } + public function reset() { $now = new DateTimeImmutable(null, timezone_open("Europe/Paris")); diff --git a/app/class/Routes.php b/app/class/Routes.php index e71bf59..03e193c 100644 --- a/app/class/Routes.php +++ b/app/class/Routes.php @@ -43,6 +43,7 @@ class Routes ['POST', '/!user/add', 'Controlleruser#add', 'useradd'], ['POST', '/!user/update', 'Controlleruser#update', 'userupdate'], ['POST', '/!user/pref', 'Controlleruser#pref', 'userpref'], + ['POST', '/!user/token', 'Controlleruser#token', 'usertoken'], ['GET', '/!info', 'Controllerinfo#desktop', 'info'], ['GET', '/!timeline', 'Controllertimeline#desktop', 'timeline'], ['POST', '/!timeline/add', 'Controllertimeline#add', 'timelineadd'], diff --git a/app/class/Summary.php b/app/class/Summary.php index 373fb33..b8b17e9 100644 --- a/app/class/Summary.php +++ b/app/class/Summary.php @@ -16,7 +16,7 @@ class Summary extends Item /** @var int Maximum summary level*/ protected $max = 6; - /** @var array Headers datas */ + /** @var Header[] Headers datas */ protected $sum = []; /** @var string Name of element to display */ @@ -48,46 +48,30 @@ class Summary extends Item public function sumparser() { $sumstring = ''; - - - foreach ($this->sum as $type => $element) { - if(!empty($element) && (empty($this->element) || $type === $this->element)) { - - $filteredsum = []; - - foreach ($element as $key => $menu) { - $deepness = array_keys($menu)[0]; - if($deepness >= $this->min && $deepness <= $this->max) { - $filteredsum[$key] = $menu; - } - } - - $last = 0; - foreach ($filteredsum as $title => $list) { - foreach ($list as $h => $link) { - if ($h > $last) { - for ($i = 1; $i <= ($h - $last); $i++) { - $sumstring .= '<ul>' . PHP_EOL; - } - $sumstring .= '<li><a href="#' . $title . '">' . $link . '</a></li>' . PHP_EOL; - } elseif ($h < $last) { - for ($i = 1; $i <= ($last - $h); $i++) { - $sumstring .= '</ul>' . PHP_EOL; - } - $sumstring .= '<li><a href="#' . $title . '">' . $link . '</a></li>' . PHP_EOL; - } elseif ($h = $last) { - $sumstring .= '<li><a href="#' . $title . '">' . $link . '</a></li>' . PHP_EOL; - } - $last = $h; - } - } - for ($i = 1; $i <= ($last); $i++) { - $sumstring .= '</ul>' . PHP_EOL; - } - + $minlevel = $this->min - 1; + $prevlevel = $minlevel; + + foreach ($this->sum as $header) { + if ($header->level < $this->min || $header->level > $this->max) { + // not in the accepted range, skiping this header. + continue; + }; + for ($i = $header->level; $i > $prevlevel; $i--) { + $sumstring .= '<ul><li>'; + } + for ($i = $header->level; $i < $prevlevel; $i++) { + $sumstring .= '</li></ul>'; } + if ($header->level <= $prevlevel) { + $sumstring .= '</li><li>'; + } + $sumstring .= "<a href=\"#$header->id\">$header->title</a>"; + $prevlevel = $header->level; + } + for ($i = $minlevel; $i < $prevlevel; $i++) { + $sumstring .= "</li></ul>"; } - return $sumstring; + return $sumstring; } diff --git a/app/fn/fn.php b/app/fn/fn.php index 3ca31c9..01e643b 100644 --- a/app/fn/fn.php +++ b/app/fn/fn.php @@ -324,6 +324,19 @@ function options(array $options, $selected = null) : string } +/** + * Hash a Token using secret key and sha256 + * + * @param string $token Input token + * + * @return string Hashed mac + */ +function secrethash(string $token) : string +{ + return hash_hmac('sha256', $token, Wcms\Config::secretkey()); +} + + diff --git a/app/view/templates/backtopbar.php b/app/view/templates/backtopbar.php index c1dd361..0710c85 100644 --- a/app/view/templates/backtopbar.php +++ b/app/view/templates/backtopbar.php @@ -63,6 +63,9 @@ if($user->isadmin()) { <form action="<?= $this->url('log') ?>" method="post" id="connect"> <input type="password" name="pass" id="loginpass" placeholder="password" autofocus> <input type="hidden" name="route" value="home"> +<input type="hidden" name="rememberme" value="0"> +<input type="checkbox" name="rememberme" id="rememberme" value="1"> +<label for="rememberme">Remember me</label> <input type="submit" name="log" value="login"> </form> diff --git a/app/view/templates/connect.php b/app/view/templates/connect.php index e21b360..6fd5b14 100644 --- a/app/view/templates/connect.php +++ b/app/view/templates/connect.php @@ -19,6 +19,9 @@ if(in_array($route, ['pageedit', 'pageread', 'pageread/', 'pageadd'])) { } ?> <input type="password" name="pass" id="loginpass" placeholder="password" autofocus> +<input type="hidden" name="rememberme" value="0"> +<input type="checkbox" name="rememberme" id="rememberme" value="1"> +<label for="rememberme">Remember me</label> <input name="log" type="submit" value="login"> </form> diff --git a/app/view/templates/homeopt.php b/app/view/templates/homeopt.php index ed7315d..b720aea 100644 --- a/app/view/templates/homeopt.php +++ b/app/view/templates/homeopt.php @@ -16,7 +16,7 @@ <legend>Sort</legend> <select name="sortby" id="sortby"> <?php - foreach ($opt->col('array') as $key => $col) { + foreach (Wcms\Model::COLUMNS as $col) { echo '<option value="' . $col . '" ' . ($opt->sortby() == $col ? "selected" : "") . '>' . $col . '</option>'; } ?> diff --git a/app/view/templates/user.php b/app/view/templates/user.php index f7b2b25..ca944fd 100644 --- a/app/view/templates/user.php +++ b/app/view/templates/user.php @@ -10,7 +10,7 @@ <main class="user"> - <section> + <section id="pref"> <div class="block"> @@ -36,12 +36,35 @@ <p> <input type="number" name="cookie" value="<?= $getuser->cookie() ?>" id="cookie" min="0" max="365"> <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="submit" value="submit"> </p> </form> + + + <h2>Sessions Tokens</h2> + + <ul> + + <?php foreach ($tokenlist as $token ) { + ?> + <li > + <code> + ip : <?= $token->ip ?> | date : <?= $token->date['date'] ?> | conservation : <?= $token->conservation ?> days | user agent : <?= $token->useragent ?> + </code> + <form action="<?= $this->url('usertoken') ?>" method="post"> + <input type="hidden" name="tokendelete" value="<?= $token->getId() ?>" > + <input type="submit" value="delete"> + </form> + + </li> + <?php + } ?> + </ul> + </div> @@ -89,7 +112,7 @@ </select> </td> <td> - <input type="date" name="expiredate" id="expiredate" min="<?= $now ?>"> + <input type="date" name="expiredate" id="expiredate" min="<?= $now->format('Y-m-d'); ?>"> </td> <td> <input type="submit" value="add"> @@ -136,7 +159,7 @@ <td> - <input type="date" name="expiredate" id="expiredate"<?= $user->expiredate() !== false ? 'value="' . $user->expiredate('string') . '"' : '' ?>> + <input type="date" name="expiredate" id="expiredate"<?= $user->expiredate() !== false ? 'value="' . $user->expiredate('string') . '"' : '' ?> min="<?= $now->format('Y-m-d'); ?>"> <span>reset<input type="checkbox" name="expiredate" id="expiredate" value="null"></span> </td> diff --git a/assets/css/home.css b/assets/css/home.css index ef59a53..2ac00a8 100644 --- a/assets/css/home.css +++ b/assets/css/home.css @@ -22,6 +22,7 @@ main { display: flex; height: 100%; /* width: 100%; */ + overflow-y: auto; } @@ -109,7 +110,7 @@ div#deepsearchbar { -aside .submenu code { +aside .submenu code, main.user li code { overflow: auto; display: block; white-space: nowrap; @@ -143,8 +144,7 @@ main.home table .id { #home2table a.linkto { font-family: monospace; font-size: medium; - text-decoration: underline; - text-decoration-color: white; + background-color: #7b97b9; } nav span.counter { @@ -272,10 +272,6 @@ th { color: black; } -main { - overflow-y: auto; -} - main.admin input, main.admin select, main.admin textarea { display: block; width: 100%; @@ -489,6 +485,10 @@ td.code { } +main.user section#pref { + max-width: 500px; +} + main.user table form { display: inline-block; @@ -651,3 +651,4 @@ footer { + |