aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/class/Application.php32
-rw-r--r--app/class/Config.php116
-rw-r--r--app/class/Controller.php4
-rw-r--r--app/class/Controllerconnect.php66
-rw-r--r--app/class/Controlleruser.php21
-rw-r--r--app/class/Header.php24
-rw-r--r--app/class/Modelauthtoken.php72
-rw-r--r--app/class/Modelhome.php1
-rw-r--r--app/class/Modelrender.php20
-rw-r--r--app/class/Modeluser.php42
-rw-r--r--app/class/Opt.php20
-rw-r--r--app/class/Page.php5
-rw-r--r--app/class/Routes.php1
-rw-r--r--app/class/Summary.php62
-rw-r--r--app/fn/fn.php13
-rw-r--r--app/view/templates/backtopbar.php3
-rw-r--r--app/view/templates/connect.php3
-rw-r--r--app/view/templates/homeopt.php2
-rw-r--r--app/view/templates/user.php29
-rw-r--r--assets/css/home.css15
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 {
+