Browse Source

Added Cookie, UserCookie, Secury classes + updated Container

Visman 8 years ago
parent
commit
41b38f3ebb

+ 1 - 1
admin_options.php

@@ -734,7 +734,7 @@ generate_admin_menu('options');
 									<th scope="row"><?php echo $lang_admin_options['SMTP password label'] ?></th>
 									<td>
 										<label><input type="checkbox" name="form[smtp_change_pass]" value="1" />&#160;<?php echo $lang_admin_options['SMTP change password help'] ?></label>
-<?php $smtp_pass = !empty($pun_config['o_smtp_pass']) ? random_key(mb_strlen($pun_config['o_smtp_pass']), true) : ''; ?>
+<?php $smtp_pass = !empty($pun_config['o_smtp_pass']) ? $container->get('Secury')->randomPass(mb_strlen($pun_config['o_smtp_pass'])) : ''; ?>
 										<input type="password" name="form[smtp_pass1]" size="25" maxlength="50" value="<?php echo $smtp_pass ?>" />
 										<input type="password" name="form[smtp_pass2]" size="25" maxlength="50" value="<?php echo $smtp_pass ?>" />
 										<span><?php echo $lang_admin_options['SMTP password help'] ?></span>

+ 116 - 0
app/Core/Cookie.php

@@ -0,0 +1,116 @@
+<?php
+
+namespace ForkBB\Core;
+
+class Cookie
+{
+    /**
+     * @var Secury
+     */
+    protected $secury;
+
+    /**
+     * Префикс для наименований
+     * @var string
+     */
+    protected $prefix;
+
+    /**
+     * Домен
+     * @var string
+     */
+    protected $domain;
+
+    /**
+     * Путь
+     * @var string
+     */
+    protected $path;
+
+    /**
+     * Флаг передачи кук по защищенному соединению
+     * @var bool
+     */
+    protected $secure;
+
+    /**
+     * Конструктор
+     *
+     * @param Secury $secury
+     * @param array $options
+     */
+    public function __construct($secury, array $options)
+    {
+        $this->secury = $secury;
+
+        $options += [
+            'prefix' => '',
+            'domain' => '',
+            'path'   => '',
+            'secure' => false,
+        ];
+
+        $this->prefix = (string) $options['prefix'];
+        $this->domain = (string) $options['domain'];
+        $this->path = (string) $options['path'];
+        $this->secure = (bool) $options['secure'];
+    }
+
+    /**
+     * Устанавливает куку
+     *
+     * @param string $name
+     * @param string $value
+     * @param int $expire
+     * @param string $path
+     * @param string $domain
+     * @param bool $secure
+     * @param bool $httponly
+     *
+     * @return bool
+     */
+    public function set($name, $value, $expire = 0, $path = null, $domain = null, $secure = false, $httponly = true)
+    {
+        $name = $this->prefix . $name;
+        $path = isset($path) ? $path : $this->path;
+        $domain = isset($domain) ? $domain : $this->domain;
+        $secure = $this->secure || (bool) $secure;
+        $result = setcookie($name, $value, $expire, $path, $domain, $secure, (bool) $httponly);
+        if ($result) {
+            $_COOKIE[$name] = $value;
+        }
+        return $result;
+    }
+
+    /**
+     * Получает значение куки
+     *
+     * @param string $name
+     * @param mixed $default
+     *
+     * @return mixed
+     */
+    public function get($name, $default = null)
+    {
+        $name = $this->prefix . $name;
+        return isset($_COOKIE[$name]) ? $this->secury->replInvalidChars($_COOKIE[$name]) : $default;
+    }
+
+    /**
+     * Удаляет куку
+     *
+     * @param string $name
+     * @param string $path
+     * @param string $domain
+     *
+     * @return bool
+     */
+    public function delete($name, $path = null, $domain = null)
+    {
+        $result = $this->set($name, '', 1, $path, $domain);
+        if ($result) {
+            unset($_COOKIE[$this->prefix . $name]);
+        }
+        return $result;
+    }
+}

+ 178 - 0
app/Core/Cookie/UserCookie.php

@@ -0,0 +1,178 @@
+<?php
+
+namespace ForkBB\Core\Cookie;
+
+class UserCookie
+{
+    const NAME = 'user';
+
+    /**
+     * @var Secury
+     */
+    protected $secury;
+
+    /**
+     * @var Cookie
+     */
+    protected $cookie;
+
+    /**
+     * Флаг указывающий на режим "запомнить меня"
+     * @var bool
+     */
+    protected $remember;
+
+    /**
+     * Номер юзера из куки аутентификации
+     * @var int
+     */
+    protected $uId;
+
+    /**
+     * Время "протухания" куки аутентификации
+     * @var int
+     */
+    protected $expTime;
+
+    /**
+     * Хэш хэша пароля юзера из куки аутентификации
+     * @var string
+     */
+    protected $passHash;
+
+    /**
+     * Период действия куки аутентификации в секундах для режима "не запоминать меня"
+     * @var int
+     */
+    protected $timeMin;
+
+    /**
+     * Период действия куки аутентификации в секундах для режима "запомнить меня"
+     * @var int
+     */
+    protected $timeMax;
+
+    /**
+     * Конструктор
+     *
+     * @param Secury $secury
+     * @param Cookie $cookie
+     * @param int $timeMin
+     * @param int $timeMax
+     */
+    public function __construct($secury, $cookie, $timeMin, $timeMax)
+    {
+        $this->secury = $secury;
+        $this->cookie = $cookie;
+        $this->timeMin = $timeMin;
+        $this->timeMax = $timeMax;
+
+        $this->init();
+    }
+
+    /**
+     * Выделение данных из куки аутентификации
+     */
+    protected function init()
+    {
+        $ckUser = $this->cookie->get(self::NAME);
+
+        if (null === $ckUser
+            || ! preg_match('%^([\+\-])(\d{1,10})\-(\d{10})\-([a-f\d]{32,})\-([a-f\d]{32,})$%Di', $ckUser, $matches)
+        ) {
+            return;
+        }
+
+        $remember = $matches[1] === '+';
+        $uId = (int) $matches[2];
+        $expTime = (int) $matches[3];
+        $passHash = $matches[4];
+        $ckHash = $matches[5];
+
+        if ($uId < 2
+            || $expTime < time()
+            || ! hash_equals($this->secury->hmac($uId . $expTime . $passHash, 'cookie'), $ckHash)
+        ) {
+            return;
+        }
+
+        $this->remember = $remember;
+        $this->uId = $uId;
+        $this->expTime = $expTime;
+        $this->passHash = $passHash;
+    }
+
+    /**
+     * Возвращает id юзера из печеньки
+     *
+     * @return int|false
+     */
+    public function id()
+    {
+        return $this->uId ?: false;
+    }
+
+    /**
+     * Проверка хэша пароля
+     *
+     * @param int $id
+     * @param string $hash
+     *
+     * @return bool
+     */
+    public function verifyHash($id, $hash)
+    {
+        return (int) $id === $this->uId
+               && hash_equals($this->passHash, $this->secury->hmac($hash . $this->expTime, 'password'));
+
+    }
+
+    /**
+     * Установка печеньки аутентификации юзера
+     *
+     * @param int $id
+     * @param string $hash
+     * @param bool $remember
+     *
+     * @return bool
+     */
+    public function setUserCookie($id, $hash, $remember = null)
+    {
+        if ($id < 2) {
+            return $this->deleteUserCookie();
+        }
+
+        if ($remember
+            || (null === $remember
+                && (int) $id === $this->uId
+                && $this->remember
+            )
+        ) {
+            $expTime = time() + $this->timeMax;
+            $expire = $expTime;
+            $prefix = '+';
+        } else {
+            $expTime = time() + $this->timeMin;
+            $expire = 0;
+            $prefix = '-';
+        }
+        $passHash = $this->secury->hmac($hash . $expTime, 'password');
+        $ckHash = $this->secury->hmac($id . $expTime . $passHash, 'cookie');
+
+        return $this->cookie->set(self::NAME, $prefix . $id . '-' . $expTime . '-' . $passHash . '-' . $ckHash, $expire);
+    }
+
+    /**
+     * Удаление печеньки аутентификации юзера
+     *
+     * @return bool
+     */
+    public function deleteUserCookie()
+    {
+        if (null === $this->cookie->get(self::NAME)) {
+            return true;
+        } else {
+            return $this->cookie->delete(self::NAME);
+        }
+    }
+}

+ 6 - 6
app/Core/Install.php

@@ -40,7 +40,7 @@ class Install implements ContainerAwareInterface
     {
         $config = file_get_contents($this->c->getParameter('DIR_CONFIG') . 'main.dist.php');
         if (false === $config) {
-            exit('Error open main.dist.php');
+            exit('Error open main.dist.php'); //????
         }
         $config = str_replace('_BASE_URL_', addslashes($base_url), $config);
         $config = str_replace('_DB_TYPE_', addslashes($db_type), $config);
@@ -50,7 +50,7 @@ class Install implements ContainerAwareInterface
         $config = str_replace('_DB_NAME_', addslashes($db_name), $config);
         $config = str_replace('_DB_PREFIX_', addslashes($db_prefix), $config);
         $config = str_replace('_COOKIE_PREFIX_', addslashes($cookie_prefix), $config);
-        $config = str_replace('_COOKIE_SALT_', addslashes(random_key(21, false, true)), $config);
+        $config = str_replace('_SALT_FOR_HMAC_', addslashes($this->c->get('Secury')->randomPass(21)), $config);
 
         return $config;
     }
@@ -1892,7 +1892,7 @@ foreach ($styles as $temp)
             $db->query('INSERT INTO '.$db_prefix.'users (group_id, username, password, email) VALUES(3, \''.$db->escape($lang_install['Guest']).'\', \''.$db->escape($lang_install['Guest']).'\', \''.$db->escape($lang_install['Guest']).'\')')
                 or error('Unable to add guest user. Please check your configuration and try again', __FILE__, __LINE__, $db->error());
 
-            $db->query('INSERT INTO '.$db_prefix.'users (group_id, username, password, email, language, style, num_posts, last_post, registered, registration_ip, last_visit) VALUES(1, \''.$db->escape($username).'\', \''.pun_hash($password1).'\', \''.$email.'\', \''.$db->escape($default_lang).'\', \''.$db->escape($default_style).'\', 1, '.$now.', '.$now.', \''.$db->escape(get_remote_address()).'\', '.$now.')')
+            $db->query('INSERT INTO '.$db_prefix.'users (group_id, username, password, email, language, style, num_posts, last_post, registered, registration_ip, last_visit) VALUES(1, \''.$db->escape($username).'\', \''.$db->escape(password_hash($password1, PASSWORD_DEFAULT)).'\', \''.$db->escape($email).'\', \''.$db->escape($default_lang).'\', \''.$db->escape($default_style).'\', 1, '.$now.', '.$now.', \''.$db->escape(get_remote_address()).'\', '.$now.')')
                 or error('Unable to add administrator user. Please check your configuration and try again', __FILE__, __LINE__, $db->error());
 
             // New PMS - Visman
@@ -1996,8 +1996,8 @@ foreach ($styles as $temp)
                 'o_coding_forms'          => 1,    // кодирование форм - Visman
                 'o_check_ip'              => 0,    // проверка ip администрации - Visman
                 'o_crypto_enable'         => 1,    // случайные имена полей форм - Visman
-                'o_crypto_pas'            => random_pass(25),
-                'o_crypto_salt'           => random_pass(13),
+                'o_crypto_pas'            => $this->c->get('Secury')->randomPass(25),
+                'o_crypto_salt'           => $this->c->get('Secury')->randomPass(13),
                 'o_enable_acaptcha'       => 1, // математическая каптча
                 'st_max_users'            => 1,    // статистика по максимуму юзеров - Visman
                 'st_max_users_time'       => time(),
@@ -2039,7 +2039,7 @@ foreach ($styles as $temp)
                 $alerts[] = $lang_install['Alert upload'];
 
             // Add some random bytes at the end of the cookie name to prevent collisions
-            $cookie_prefix = 'fork' . random_key(7, false, true) . '_';
+            $cookie_prefix = 'fork' . $container->get('Secury')->randomHash(7) . '_';
 
             // Generate the main.php file data
             $config = $this->generate_config_file($base_url, $db_type, $db_host, $db_name, $db_username, $db_password, $db_prefix, $cookie_prefix);

+ 20 - 25
app/Core/Request.php

@@ -4,6 +4,21 @@ namespace ForkBB\Core;
 
 class Request
 {
+    /**
+     * @var Secury
+     */
+    protected $secury;
+
+    /**
+     * Конструктор
+     *
+     * @param Secury $secury
+     */
+    public function __construct($secury)
+    {
+        $this->secury = $secury;
+    }
+
     /**
      * @param string $key
      *
@@ -97,7 +112,7 @@ class Request
     public function post($key, $default = null)
     {
         if (isset($_POST[$key])) {
-            return $this->replBadChars($_POST[$key]);
+            return $this->secury->replInvalidChars($_POST[$key]);
         }
         return $default;
     }
@@ -111,7 +126,7 @@ class Request
     public function postStr($key, $default = null)
     {
         if (isset($_POST[$key]) && is_string($_POST[$key])) {
-            return (string) $this->replBadChars($_POST[$key]);
+            return (string) $this->secury->replInvalidChars($_POST[$key]);
         }
         return $default;
     }
@@ -155,7 +170,7 @@ class Request
         if (isset($_POST[$key]) && is_array($_POST[$key])) {
             $k = key($_POST[$key]);
             if (null !== $k) {
-                return is_int($k) ? (int) $k : (string) $this->replBadChars($k);
+                return is_int($k) ? (int) $k : (string) $this->secury->replInvalidChars($k);
             }
         }
         return $default;
@@ -180,7 +195,7 @@ class Request
     public function get($key, $default = null)
     {
         if (isset($_GET[$key])) {
-            return $this->replBadChars($_GET[$key]);
+            return $this->secury->replInvalidChars($_GET[$key]);
         }
         return $default;
     }
@@ -194,7 +209,7 @@ class Request
     public function getStr($key, $default = null)
     {
         if (isset($_GET[$key]) && is_string($_GET[$key])) {
-            return (string) $this->replBadChars($_GET[$key]);
+            return (string) $this->secury->replInvalidChars($_GET[$key]);
         }
         return $default;
     }
@@ -226,24 +241,4 @@ class Request
         }
         return $default;
     }
-
-    /**
-     * @param string|array $data
-     *
-     * @return string|array
-     */
-    protected function replBadChars($data)
-    {
-        if (is_array($data)) {
-            return array_map([$this, 'replBadChars'], $data);
-        }
-
-        // slow, small memory
-        //$data = mb_convert_encoding((string) $data, 'UTF-8', 'UTF-8');
-        // fast, large memory
-        $data = htmlspecialchars_decode(htmlspecialchars((string) $data, ENT_SUBSTITUTE, 'UTF-8'));
-
-        // Remove control characters
-        return preg_replace('%[\x00-\x08\x0B-\x0C\x0E-\x1F]%', '', $data);
-    }
 }

+ 132 - 0
app/Core/Secury.php

@@ -0,0 +1,132 @@
+<?php
+
+namespace ForkBB\Core;
+
+use RuntimeException;
+use UnexpectedValueException;
+use InvalidArgumentException;
+
+class Secury
+{
+    /**
+     * Algorithm and salt for hash_hmac
+     * @var array
+     */
+    protected $hmac;
+
+    /**
+     * Конструктор
+     *
+     * @param array $hmac
+     */
+    public function __construct(array $hmac)
+    {
+        if (empty($hmac['salt']) || empty($hmac['algo'])) {
+            throw new InvalidArgumentException('Algorithm and salt can not be empty');
+        }
+        if (! in_array($hmac['algo'], hash_algos())) {
+            throw new UnexpectedValueException('Algorithm not supported');
+        }
+        $this->hmac = $hmac;
+    }
+
+    /**
+     * Обертка для hash_hmac
+     *
+     * @param string $data
+     * @param string $key
+     *
+     * @return string
+     */
+    public function hmac($data, $key)
+    {
+        if (empty($key)) {
+            throw new InvalidArgumentException('Key can not be empty');
+        }
+        return hash_hmac($this->hmac['algo'], $data, $this->hmac['salt'] . $key);
+    }
+
+    /**
+     * Возвращает случайный набор байтов заданной длины
+     *
+     * @param int $len
+     *
+     * @return string
+     */
+    public function randomKey($len)
+    {
+        $key = '';
+        if (function_exists('random_bytes')) {
+            $key .= (string) random_bytes($len);
+        }
+        if (strlen($key) < $len && function_exists('mcrypt_create_iv')) {
+            $key .= (string) mcrypt_create_iv($len, MCRYPT_DEV_URANDOM);
+        }
+        if (strlen($key) < $len && function_exists('openssl_random_pseudo_bytes')) {
+            $tmp = (string) openssl_random_pseudo_bytes($len, $strong);
+            if ($strong) {
+                $key .= $tmp;
+            }
+        }
+        if (strlen($key) < $len) {
+            throw new RuntimeException('Could not gather sufficient random data');
+        }
+
+    	return $key;
+    }
+
+    /**
+     * Возвращает случайную строку заданной длины состоящую из символов 0-9 и a-f
+     *
+     * @param int $len
+     *
+     * @return string
+     */
+    public function randomHash($len)
+    {
+        return substr(bin2hex($this->randomKey($len)), 0, $len);
+    }
+
+    /**
+     * Возвращает случайную строку заданной длины состоящую из цифр, латиницы,
+     * знака минус и символа подчеркивания
+     *
+     * @param int $len
+     *
+     * @return string
+     */
+    public function randomPass($len)
+    {
+        $key = $this->randomKey($len);
+        $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
+        $result = '';
+        for ($i = 0; $i < $len; ++$i) {
+            $result .= substr($chars, (ord($key[$i]) % strlen($chars)), 1);
+        }
+
+        return $result;
+    }
+
+    /**
+     * Replacing invalid UTF-8 characters and remove control characters
+     *
+     * @param string|array $data
+     *
+     * @return string|array
+     */
+    public function replInvalidChars($data)
+    {
+        if (is_array($data)) {
+            return array_map([$this, 'replInvalidChars'], $data);
+        }
+
+        // Replacing invalid UTF-8 characters
+        // slow, small memory
+        //$data = mb_convert_encoding((string) $data, 'UTF-8', 'UTF-8');
+        // fast, large memory
+        $data = htmlspecialchars_decode(htmlspecialchars((string) $data, ENT_SUBSTITUTE, 'UTF-8'));
+
+        // Remove control characters
+        return preg_replace('%[\x00-\x08\x0B-\x0C\x0E-\x1F]%', '', $data);
+    }
+}

+ 12 - 1
app/config/install.php

@@ -8,8 +8,15 @@ return [
     'DB_NAME'     => '_DB_NAME_',
     'DB_PREFIX'   => '_DB_PREFIX_',
     'P_CONNECT'   => false,
+    'HMAC' => [
+        'algo' => 'sha1',
+        'salt' => '_SALT_FOR_HMAC_',
+    ],
     'shared' => [
-        'Request' => \ForkBB\Core\Request::class,
+        'Request' => [
+            'class' => \ForkBB\Core\Request::class,
+            'Secury' => '@Secury',
+        ],
         'DBLoader' => [
             'class' => \ForkBB\Core\DBLoader::class,
             'db_host'     => '%DB_HOST%',
@@ -27,6 +34,10 @@ return [
             'class' => \ForkBB\Core\Install::class,
             'request' => '@Request',
         ],
+        'Secury' => [
+            'class' => \ForkBB\Core\Secury::class,
+            'hmac' => '%HMAC%',
+        ],
         'firstAction' => '@Install:start',
     ],
     'multiple'  => [],

+ 32 - 8
app/config/main.dist.php

@@ -12,16 +12,24 @@ return [
     'DB_NAME'     => '_DB_NAME_',
     'DB_PREFIX'   => '_DB_PREFIX_',
     'P_CONNECT'   => false,
-    'COOKIE_PREFIX' => '_COOKIE_PREFIX_',
-    'COOKIE_DOMAIN' => '',
-    'COOKIE_PATH'   => '/',
-    'COOKIE_SECURE' => false,
-    'COOKIE_SALT'   => '_COOKIE_SALT_',
-    'ALGO_FOR_HMAC' => 'sha1',
-    'SALT1' => '', // For FluxBB by Visman 1.5.10.74 and above
+    'TIME_REMEMBER' => 31536000,
+    'COOKIE' => [
+        'prefix' => '_COOKIE_PREFIX_',
+        'domain' => '',
+        'path'   => '/',
+        'secure' => false,
+    ],
+    'HMAC' => [
+        'algo' => 'sha1',
+        'salt' => '_SALT_FOR_HMAC_',
+    ],
+    'SALT1'       => '', // For FluxBB by Visman 1.5.10.74 and above
     'JQUERY_LINK' => '//ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js',
     'shared' => [
-        'Request' => \ForkBB\Core\Request::class,
+        'Request' => [
+            'class' => \ForkBB\Core\Request::class,
+            'Secury' => '@Secury',
+        ],
         'DBLoader' => [
             'class' => \ForkBB\Core\DBLoader::class,
             'db_host'     => '%DB_HOST%',
@@ -35,6 +43,22 @@ return [
             'factory method' => '@DBLoader:load',
             'type' => '%DB_TYPE%',
         ],
+        'Secury' => [
+            'class' => \ForkBB\Core\Secury::class,
+            'hmac' => '%HMAC%',
+        ],
+        'Cookie' => [
+            'class' => \ForkBB\Core\Cookie::class,
+            'Secury' => '@Secury',
+            'options' => '%COOKIE%'
+        ],
+        'UserCookie' => [
+            'class' => \ForkBB\Core\Cookie\UserCookie::class,
+            'Secury' => '@Secury',
+            'Cookie' => '@Cookie',
+            'timeMin' => '@config[o_timeout_visit]',
+            'timeMax' => '%TIME_REMEMBER%',
+        ],
         'firstAction' => \ForkBB\Core\Blank::class,
     ],
     'multiple'  => [],

+ 7 - 1
composer.json

@@ -11,8 +11,14 @@
             "homepage": "https://github.com/MioVisman"
         }
     ],
+    "repositories": [
+        {
+            "type": "vcs",
+            "url": "https://github.com/MioVisman/container"
+        }
+    ],
     "require": {
         "php": ">=5.6.0",
-        "artoodetoo/container": "dev-master"
+        "artoodetoo/container": "dev-visman"
     }
 }

+ 11 - 9
composer.lock

@@ -4,21 +4,21 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
         "This file is @generated automatically"
     ],
-    "hash": "ec3608ec80234fd3cec94b928cfb161c",
-    "content-hash": "624c9d21e02e6a9ad19afc8c1e907875",
+    "hash": "6f4e0ebde4d3b282bfe8097414a0e787",
+    "content-hash": "1356226a18a75fe9ec08328a2f553a59",
     "packages": [
         {
             "name": "artoodetoo/container",
-            "version": "dev-master",
+            "version": "dev-visman",
             "source": {
                 "type": "git",
-                "url": "https://github.com/artoodetoo/container.git",
-                "reference": "1c52096695eb699e2c63b6b84703794d94d0659f"
+                "url": "https://github.com/MioVisman/container.git",
+                "reference": "3ab08b97674dff417f36783c9e054c25540171d3"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/artoodetoo/container/zipball/1c52096695eb699e2c63b6b84703794d94d0659f",
-                "reference": "1c52096695eb699e2c63b6b84703794d94d0659f",
+                "url": "https://api.github.com/repos/MioVisman/container/zipball/3ab08b97674dff417f36783c9e054c25540171d3",
+                "reference": "3ab08b97674dff417f36783c9e054c25540171d3",
                 "shasum": ""
             },
             "require": {
@@ -30,7 +30,6 @@
                     "R2\\DependencyInjection\\": "src/"
                 }
             },
-            "notification-url": "https://packagist.org/downloads/",
             "license": [
                 "MIT"
             ],
@@ -44,7 +43,10 @@
                 "container",
                 "service"
             ],
-            "time": "2016-12-27 20:57:10"
+            "support": {
+                "source": "https://github.com/MioVisman/container/tree/visman"
+            },
+            "time": "2017-01-11 15:15:38"
         }
     ],
     "packages-dev": [],

+ 2 - 0
include/common.php

@@ -80,6 +80,8 @@ if (!defined('PUN_CONFIG_LOADED'))
 	require $container->getParameter('DIR_CACHE') . 'cache_config.php';
 }
 
+$container->set('config', $pun_config);
+
 // Verify that we are running the proper database schema revision
 if (empty($pun_config['i_fork_revision']) || $pun_config['i_fork_revision'] < FORK_REVISION) {
 	header('Location: db_update.php');

+ 79 - 207
include/functions.php

@@ -15,136 +15,100 @@ function check_cookie(&$pun_user)
 	global $container, $pun_config;
 
     $db = $container->get('DB');
-    $cookie_name = $container->getParameter('COOKIE_PREFIX');
-    $cookie_seed = $container->getParameter('COOKIE_SALT');
-
+    $userCookie = $container->get('UserCookie');
 	$now = time();
 
-	// If the cookie is set and it matches the correct pattern, then read the values from it
-	if (isset($_COOKIE[$cookie_name]) && preg_match('%^(\d+)\|([0-9a-fA-F]+)\|(\d+)\|([0-9a-fA-F]+)$%', $_COOKIE[$cookie_name], $matches))
-	{
-		$cookie = array(
-			'user_id'			=> intval($matches[1]),
-			'password_hash' 	=> $matches[2],
-			'expiration_time'	=> intval($matches[3]),
-			'cookie_hash'		=> $matches[4],
-		);
-	}
-
-	// If it has a non-guest user, and hasn't expired
-	if (isset($cookie) && $cookie['user_id'] > 1 && $cookie['expiration_time'] > $now)
-	{
-		// If the cookie has been tampered with
-		$is_authorized = hash_equals(forum_hmac($cookie['user_id'].'|'.$cookie['expiration_time'], $cookie_seed.'_cookie_hash'), $cookie['cookie_hash']);
-		if (!$is_authorized)
-		{
-			$expire = $now + 31536000; // The cookie expires after a year
-			pun_setcookie(1, pun_hash(uniqid(rand(), true)), $expire);
-			set_default_user();
-
-			return;
-		}
-
-		// Кто в этой теме - , o.witt_data - Visman
-		// Check if there's a user with the user ID and password hash from the cookie
-		$result = $db->query('SELECT u.*, g.*, o.logged, o.idle, o.witt_data FROM '.$db->prefix.'users AS u INNER JOIN '.$db->prefix.'groups AS g ON u.group_id=g.g_id LEFT JOIN '.$db->prefix.'online AS o ON o.user_id=u.id WHERE u.id='.intval($cookie['user_id'])) or error('Unable to fetch user information', __FILE__, __LINE__, $db->error());
-		$pun_user = $db->fetch_assoc($result);
-
-		// If user authorisation failed
-		$is_authorized = hash_equals(forum_hmac($pun_user['password'], $cookie_seed.'_password_hash'), $cookie['password_hash']);
-		if (!isset($pun_user['id']) || !$is_authorized)
-		{
-			$expire = $now + 31536000; // The cookie expires after a year
-			pun_setcookie(1, pun_hash(uniqid(rand(), true)), $expire);
-			set_default_user();
+	if (($userId = $userCookie->id()) === false) {
+		return set_default_user();
+    }
 
-			return;
-		}
+	// Кто в этой теме - , o.witt_data - Visman
+	// Check if there's a user with the user ID and password hash from the cookie
+	$result = $db->query('SELECT u.*, g.*, o.logged, o.idle, o.witt_data FROM '.$db->prefix.'users AS u INNER JOIN '.$db->prefix.'groups AS g ON u.group_id=g.g_id LEFT JOIN '.$db->prefix.'online AS o ON o.user_id=u.id WHERE u.id='.$userId) or error('Unable to fetch user information', __FILE__, __LINE__, $db->error());
+	$pun_user = $db->fetch_assoc($result);
 
-		// проверка ip админа и модератора - Visman
-		if ($pun_config['o_check_ip'] == '1' && ($pun_user['g_id'] == PUN_ADMIN || $pun_user['g_moderator'] == '1') && $pun_user['registration_ip'] != get_remote_address())
-		{
-			$expire = $now + 31536000; // The cookie expires after a year
-			pun_setcookie(1, pun_hash(uniqid(rand(), true)), $expire);
-			set_default_user();
+    if (empty($pun_user['id']) || ! $userCookie->verifyHash($pun_user['id'], $pun_user['password'])) {
+		return set_default_user();
+    }
 
-			return;
-		}
+	// проверка ip админа и модератора - Visman
+	if ($pun_config['o_check_ip'] == '1' && ($pun_user['g_id'] == PUN_ADMIN || $pun_user['g_moderator'] == '1') && $pun_user['registration_ip'] != get_remote_address())
+	{
+		return set_default_user();
+	}
 
-		// Send a new, updated cookie with a new expiration timestamp
-		$expire = ($cookie['expiration_time'] > $now + $pun_config['o_timeout_visit']) ? $now + 1209600 : $now + $pun_config['o_timeout_visit'];
-		pun_setcookie($pun_user['id'], $pun_user['password'], $expire);
+    $userCookie->setUserCookie($pun_user['id'], $pun_user['password']);
 
-		// Set a default language if the user selected language no longer exists
-		if (!file_exists(PUN_ROOT.'lang/'.$pun_user['language']))
-			$pun_user['language'] = $pun_config['o_default_lang'];
+	// Set a default language if the user selected language no longer exists
+	if (!file_exists(PUN_ROOT.'lang/'.$pun_user['language']))
+		$pun_user['language'] = $pun_config['o_default_lang'];
 
-		// Set a default style if the user selected style no longer exists
-		if (!file_exists(PUN_ROOT.'style/'.$pun_user['style'].'.css'))
-			$pun_user['style'] = $pun_config['o_default_style'];
+	// Set a default style if the user selected style no longer exists
+	if (!file_exists(PUN_ROOT.'style/'.$pun_user['style'].'.css'))
+		$pun_user['style'] = $pun_config['o_default_style'];
 
-		if (!$pun_user['disp_topics'])
-			$pun_user['disp_topics'] = $pun_config['o_disp_topics_default'];
-		if (!$pun_user['disp_posts'])
-			$pun_user['disp_posts'] = $pun_config['o_disp_posts_default'];
+	if (!$pun_user['disp_topics'])
+		$pun_user['disp_topics'] = $pun_config['o_disp_topics_default'];
+	if (!$pun_user['disp_posts'])
+		$pun_user['disp_posts'] = $pun_config['o_disp_posts_default'];
 
-		// Define this if you want this visit to affect the online list and the users last visit data
-		if (!defined('PUN_QUIET_VISIT'))
+	// Define this if you want this visit to affect the online list and the users last visit data
+	if (!defined('PUN_QUIET_VISIT'))
+	{
+		// Update the online list
+		if (!$pun_user['logged'])
 		{
-			// Update the online list
-			if (!$pun_user['logged'])
-			{
-				$pun_user['logged'] = $now;
+			$pun_user['logged'] = $now;
 
-				// With MySQL/MySQLi/SQLite, REPLACE INTO avoids a user having two rows in the online table
-				switch ($container->getParameter('DB_TYPE'))
-				{
-					case 'mysql':
-					case 'mysqli':
-					case 'mysql_innodb':
-					case 'mysqli_innodb':
-					case 'sqlite':
-						witt_query('REPLACE INTO '.$db->prefix.'online (user_id, ident, logged:?comma?::?column?:) VALUES('.$pun_user['id'].', \''.$db->escape($pun_user['username']).'\', '.$pun_user['logged'].':?comma?::?value?:)'); // MOD Кто в этой теме - Visman
-						break;
-
-					default:
-						witt_query('INSERT INTO '.$db->prefix.'online (user_id, ident, logged:?comma?::?column?:) SELECT '.$pun_user['id'].', \''.$db->escape($pun_user['username']).'\', '.$pun_user['logged'].':?comma?::?value?: WHERE NOT EXISTS (SELECT 1 FROM '.$db->prefix.'online WHERE user_id='.$pun_user['id'].')'); // MOD Кто в этой теме - Visman
-						break;
-				}
-
-				// Reset tracked topics
-				set_tracked_topics(null);
-			}
-			else
+			// With MySQL/MySQLi/SQLite, REPLACE INTO avoids a user having two rows in the online table
+			switch ($container->getParameter('DB_TYPE'))
 			{
-				// Special case: We've timed out, but no other user has browsed the forums since we timed out
-				if ($pun_user['logged'] < ($now-$pun_config['o_timeout_visit']))
-				{
-					$db->query('UPDATE '.$db->prefix.'users SET last_visit='.$pun_user['logged'].' WHERE id='.$pun_user['id']) or error('Unable to update user visit data', __FILE__, __LINE__, $db->error());
-					$pun_user['last_visit'] = $pun_user['logged'];
-				}
-
-				$idle_sql = ($pun_user['idle'] == '1') ? ', idle=0' : '';
-				witt_query('UPDATE '.$db->prefix.'online SET logged='.$now.$idle_sql.':?comma?::?column?::?equal?::?value?: WHERE user_id='.$pun_user['id']); // MOD Кто в этой теме - Visman
+				case 'mysql':
+				case 'mysqli':
+				case 'mysql_innodb':
+				case 'mysqli_innodb':
+				case 'sqlite':
+					witt_query('REPLACE INTO '.$db->prefix.'online (user_id, ident, logged:?comma?::?column?:) VALUES('.$pun_user['id'].', \''.$db->escape($pun_user['username']).'\', '.$pun_user['logged'].':?comma?::?value?:)'); // MOD Кто в этой теме - Visman
+					break;
 
-				// Update tracked topics with the current expire time
-				if (isset($_COOKIE[$cookie_name.'_track']))
-					forum_setcookie($cookie_name.'_track', $_COOKIE[$cookie_name.'_track'], $now + $pun_config['o_timeout_visit']);
+				default:
+					witt_query('INSERT INTO '.$db->prefix.'online (user_id, ident, logged:?comma?::?column?:) SELECT '.$pun_user['id'].', \''.$db->escape($pun_user['username']).'\', '.$pun_user['logged'].':?comma?::?value?: WHERE NOT EXISTS (SELECT 1 FROM '.$db->prefix.'online WHERE user_id='.$pun_user['id'].')'); // MOD Кто в этой теме - Visman
+					break;
 			}
+
+			// Reset tracked topics
+			set_tracked_topics(null);
 		}
 		else
 		{
-			if (!$pun_user['logged'])
-				$pun_user['logged'] = $pun_user['last_visit'];
-		}
+			// Special case: We've timed out, but no other user has browsed the forums since we timed out
+			if ($pun_user['logged'] < ($now-$pun_config['o_timeout_visit']))
+			{
+				$db->query('UPDATE '.$db->prefix.'users SET last_visit='.$pun_user['logged'].' WHERE id='.$pun_user['id']) or error('Unable to update user visit data', __FILE__, __LINE__, $db->error());
+				$pun_user['last_visit'] = $pun_user['logged'];
+			}
 
-		$pun_user['is_guest'] = false;
-		$pun_user['is_admmod'] = $pun_user['g_id'] == PUN_ADMIN || $pun_user['g_moderator'] == '1';
+			$idle_sql = ($pun_user['idle'] == '1') ? ', idle=0' : '';
+			witt_query('UPDATE '.$db->prefix.'online SET logged='.$now.$idle_sql.':?comma?::?column?::?equal?::?value?: WHERE user_id='.$pun_user['id']); // MOD Кто в этой теме - Visman
 
-		$pun_user['is_bot'] = false; // MOD определения ботов - Visman
+            $cookie = $container->get('Cookie');
+            $track = $cookie->get('track');
+			// Update tracked topics with the current expire time
+			if (isset($track)) {
+                $cookie->set('track', $track, $now + $pun_config['o_timeout_visit']);
+            }
+		}
 	}
 	else
-		set_default_user();
+	{
+		if (!$pun_user['logged'])
+			$pun_user['logged'] = $pun_user['last_visit'];
+	}
+
+	$pun_user['is_guest'] = false;
+	$pun_user['is_admmod'] = $pun_user['g_id'] == PUN_ADMIN || $pun_user['g_moderator'] == '1';
+
+	$pun_user['is_bot'] = false; // MOD определения ботов - Visman
 }
 
 
@@ -281,8 +245,7 @@ function set_default_user()
 	global $container, $pun_user, $pun_config, $languages;
 
     $db = $container->get('DB');
-    $cookie_name = $container->getParameter('COOKIE_PREFIX');
-
+    $container->get('UserCookie')->deleteUserCookie();
 
 	$remote_addr = get_remote_address();
 	
@@ -334,9 +297,11 @@ function set_default_user()
 	$pun_user['is_bot'] = (strpos($remote_addr, '[Bot]') !== false); // MOD определения ботов - Visman
 	$pun_user['ident'] = $remote_addr; // Кто в этой теме - Visman
 
-	if (!empty($_COOKIE[$cookie_name.'_glang'])) // быстрое переключение языка - Visman
+    // быстрое переключение языка - Visman
+    $language = $container->get('Cookie')->get('glang');
+	if (null !== $language)
 	{
-		$language = preg_replace('%[^\w]%', '', $_COOKIE[$cookie_name.'_glang']);
+		$language = preg_replace('%[^\w]%', '', $language);
 		$languages = forum_list_langs();
 		if (in_array($language, $languages))
 			$pun_user['language'] = $language;
@@ -380,45 +345,6 @@ function forum_hmac($data, $key, $raw_output = false)
 }
 
 
-//
-// Set a cookie, FluxBB style!
-// Wrapper for forum_setcookie
-//
-function pun_setcookie($user_id, $password_hash, $expire)
-{
-	global $container;
-
-    $cookie_name = $container->getParameter('COOKIE_PREFIX');
-    $cookie_seed = $container->getParameter('COOKIE_SALT');
-
-	forum_setcookie($cookie_name, $user_id.'|'.forum_hmac($password_hash, $cookie_seed.'_password_hash').'|'.$expire.'|'.forum_hmac($user_id.'|'.$expire, $cookie_seed.'_cookie_hash'), $expire);
-}
-
-
-//
-// Set a cookie, FluxBB style!
-//
-function forum_setcookie($name, $value, $expire)
-{
-	global $container, $pun_config;
-
-    $cookie_path = $container->getParameter('COOKIE_PATH');
-    $cookie_domain = $container->getParameter('COOKIE_DOMAIN');
-    $cookie_secure = $container->getParameter('COOKIE_SECURE');
-
-	if ($expire - time() - $pun_config['o_timeout_visit'] < 1)
-		$expire = 0;
-
-	// Enable sending of a P3P header
-	header('P3P: CP="CUR ADM"');
-
-	if (version_compare(PHP_VERSION, '5.2.0', '>='))
-		setcookie($name, $value, $expire, $cookie_path, $cookie_domain, $cookie_secure, true);
-	else
-		setcookie($name, $value, $expire, $cookie_path.'; HttpOnly', $cookie_domain, $cookie_secure);
-}
-
-
 //
 // Check whether the connecting user is banned (and delete any expired bans while we're at it)
 //
@@ -709,8 +635,6 @@ function set_tracked_topics($tracked_topics)
 {
 	global $container, $pun_config;
 
-    $cookie_name = $container->getParameter('COOKIE_PREFIX');
-
 	$cookie_data = '';
 	if (!empty($tracked_topics))
 	{
@@ -732,8 +656,7 @@ function set_tracked_topics($tracked_topics)
 		}
 	}
 
-	forum_setcookie($cookie_name.'_track', $cookie_data, time() + $pun_config['o_timeout_visit']);
-	$_COOKIE[$cookie_name.'_track'] = $cookie_data; // Set it directly in $_COOKIE as well
+    $container->get('Cookie')->set('track', $cookie_data, time() + $pun_config['o_timeout_visit']);
 }
 
 
@@ -744,9 +667,7 @@ function get_tracked_topics()
 {
 	global $container;
 
-    $cookie_name = $container->getParameter('COOKIE_PREFIX');
-
-	$cookie_data = isset($_COOKIE[$cookie_name.'_track']) ? $_COOKIE[$cookie_name.'_track'] : false;
+	$cookie_data = $container->get('Cookie')->get('track');
 	if (!$cookie_data)
 		return array('topics' => array(), 'forums' => array());
 
@@ -1149,45 +1070,6 @@ function forum_number_format($number, $decimals = 0)
 }
 
 
-//
-// Generate a random key of length $len
-//
-function random_key($len, $readable = false, $hash = false)
-{
-    $key = '';
-    if (function_exists('random_bytes')) {
-        $key .= (string) random_bytes($len);
-    }
-    if (strlen($key) < $len && function_exists('mcrypt_create_iv')) {
-        $key .= (string) mcrypt_create_iv($len, MCRYPT_DEV_URANDOM);
-    }
-    if (strlen($key) < $len && function_exists('openssl_random_pseudo_bytes')) {
-        $tmp = (string) openssl_random_pseudo_bytes($len, $strong);
-        if ($strong) {
-            $key .= $tmp;
-        }
-    }
-    if (strlen($key) < $len) {
-        throw new \Exception('Could not gather sufficient random data');
-    }
-
-	if ($hash)
-		return substr(bin2hex($key), 0, $len);
-	else if ($readable)
-	{
-		$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
-
-		$result = '';
-		for ($i = 0; $i < $len; ++$i)
-		$result .= substr($chars, (ord($key[$i]) % strlen($chars)), 1);
-
-		return $result;
-	}
-
-	return $key;
-}
-
-
 //
 // Make sure that HTTP_REFERER matches base_url/script
 // ********* новые ф-ии проверки подлинности - Visman
@@ -1269,16 +1151,6 @@ function validate_redirect($redirect_url, $fallback_url)
 }
 
 
-//
-// Generate a random password of length $len
-// Compatibility wrapper for random_key
-//
-function random_pass($len)
-{
-	return random_key($len, true);
-}
-
-
 //
 // Compute a hash of $str
 //

+ 1 - 1
index.php

@@ -153,7 +153,7 @@ else
 $page_js['f']['collapse'] = 'js/collapse.js';
 $page_js['c'][] = 'if (typeof FluxBB === \'undefined\' || !FluxBB) {var FluxBB = {};}
 FluxBB.vars = {
-	collapse_cookieid: "'.$container->getParameter('COOKIE_PREFIX').'",
+	collapse_cookieid: "'.$container->getParameter('COOKIE')['prefix'].'",
 	collapse_folder: "'.(file_exists(PUN_ROOT.'style/'.$pun_user['style'].'/exp_down.png') ? 'style/'.$pun_user['style'].'/' : 'img/').'"
 };
 FluxBB.collapse.init();';

+ 6 - 5
login.php

@@ -85,8 +85,7 @@ if ($request->isPost('form_sent') && $action === 'in')
 		// Remove this users guest entry from the online list
 		$db->query('DELETE FROM '.$db->prefix.'online WHERE ident=\''.$db->escape(get_remote_address()).'\'') or error('Unable to delete from online list', __FILE__, __LINE__, $db->error());
 
-		$expire = ($save_pass == '1') ? time() + 1209600 : time() + $pun_config['o_timeout_visit'];
-		pun_setcookie($cur_user['id'], $cur_user['password'], $expire);
+        $container->get('UserCookie')->setUserCookie($cur_user['id'], $cur_user['password'], $save_pass == '1');
 
 		// Reset tracked topics
 		set_tracked_topics(null);
@@ -116,7 +115,7 @@ else if ($action === 'out')
 	if (isset($pun_user['logged']))
 		$db->query('UPDATE '.$db->prefix.'users SET last_visit='.$pun_user['logged'].' WHERE id='.$pun_user['id']) or error('Unable to update user visit data', __FILE__, __LINE__, $db->error());
 
-	pun_setcookie(1, pun_hash(uniqid(rand(), true)), time() + 31536000);
+    $container->get('UserCookie')->deleteUserCookie();
 
 	redirect('index.php', $lang_login['Logout redirect']);
 }
@@ -162,6 +161,8 @@ else if ($action === 'forget' || $action === 'forget_2')
 				$mail_message = str_replace('<base_url>', get_base_url().'/', $mail_message);
 				$mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'], $mail_message);
 
+                $secury = $container->get('Secury');
+
 				// Loop through users we found
 				while ($cur_hit = $db->fetch_assoc($result))
 				{
@@ -169,8 +170,8 @@ else if ($action === 'forget' || $action === 'forget_2')
 						message(sprintf($lang_login['Email flood'], intval((3600 - (time() - $cur_hit['last_email_sent'])) / 60)), true);
 
 					// Generate a new password and a new password activation code
-					$new_password = random_pass(12);
-					$new_password_key = random_pass(8);
+					$new_password = $secury->randomPass(12);
+					$new_password_key = $secury->randomPass(8);
 
 					$db->query('UPDATE '.$db->prefix.'users SET activate_string=\''.pun_hash($new_password).'\', activate_key=\''.$new_password_key.'\', last_email_sent = '.time().' WHERE id='.$cur_hit['id']) or error('Unable to update activation data', __FILE__, __LINE__, $db->error());
 

+ 2 - 2
misc.php

@@ -16,7 +16,7 @@ require PUN_ROOT.'include/common.php';
 // Load the misc.php language file
 require PUN_ROOT.'lang/'.$pun_user['language'].'/misc.php';
 
-$request = $container->get('Reuqest');
+$request = $container->get('Request');
 
 $action = $request->getStr('action');
 
@@ -58,7 +58,7 @@ else if ($action === 'lang')
 
 	if ($pun_user['is_guest'])
 	{
-		forum_setcookie($container->getParameter('COOKIE_PREFIX') . '_glang', $language, time()+ 31536000);
+        $container->get('Cookie')->set('glang', $language, time()+ 31536000);
 	}
 	else
 		$db->query('UPDATE '.$db->prefix.'users SET language="'.$db->escape($language).'" WHERE id='.$pun_user['id']) or error('Unable to update profile', __FILE__, __LINE__, $db->error());

+ 3 - 3
profile.php

@@ -109,12 +109,12 @@ if ($action === 'change_pass')
 		if (!$authorized)
 			message($lang_profile['Wrong pass']);
 
-		$new_password_hash = pun_hash($new_password1);
+		$new_password_hash = pun_hash($new_password1);  //????
 
 		$db->query('UPDATE '.$db->prefix.'users SET password=\''.$new_password_hash.'\''.(!empty($cur_user['salt']) ? ', salt=NULL' : '').' WHERE id='.$id) or error('Unable to update password', __FILE__, __LINE__, $db->error());
 
 		if ($pun_user['id'] == $id)
-			pun_setcookie($pun_user['id'], $new_password_hash, time() + $pun_config['o_timeout_visit']);
+            $container->get('UserCookie')->setUserCookie($pun_user['id'], $new_password_hash, false);
 
 		redirect('profile.php?section=essentials&amp;id='.$id, $lang_profile['Pass updated redirect']);
 	}
@@ -260,7 +260,7 @@ else if ($action === 'change_email')
 		}
 
 
-		$new_email_key = random_pass(8);
+		$new_email_key = $container->get('Secury')->randomPass(8);
 
 		$db->query('UPDATE '.$db->prefix.'users SET activate_string=\''.$db->escape($new_email).'\', activate_key=\''.$new_email_key.'\' WHERE id='.$id) or error('Unable to update activation data', __FILE__, __LINE__, $db->error());
 

+ 4 - 4
register.php

@@ -82,7 +82,7 @@ if ($request->isPost('form_sent'))
 	{
 		$email2 = strtolower(trim($request->posStr('req_email2')));
 
-		$password1 = random_pass(12);
+		$password1 = $container->get('Secury')->randomPass(12);
 		$password2 = $password1;
 	}
 	else
@@ -160,7 +160,7 @@ if ($request->isPost('form_sent'))
 		$now = time();
 
 		$intial_group_id = ($pun_config['o_regs_verify'] == '0') ? $pun_config['o_default_user_group'] : PUN_UNVERIFIED;
-		$password_hash = pun_hash($password1);
+		$password_hash = password_hash($password1, PASSWORD_DEFAULT);
 
 		// Add the user
 		$db->query('INSERT INTO '.$db->prefix.'users (username, group_id, password, email, email_setting, timezone, dst, language, style, registered, registration_ip, last_visit) VALUES(\''.$db->escape($username).'\', '.$intial_group_id.', \''.$password_hash.'\', \''.$db->escape($email1).'\', '.$email_setting.', '.$timezone.' , '.$dst.', \''.$db->escape($language).'\', \''.$pun_config['o_default_style'].'\', '.$now.', \''.$db->escape(get_remote_address()).'\', '.$now.')') or error('Unable to create user', __FILE__, __LINE__, $db->error());
@@ -260,8 +260,8 @@ if ($request->isPost('form_sent'))
 			message($lang_register['Reg email'].' <a href="mailto:'.pun_htmlspecialchars($pun_config['o_admin_email']).'">'.pun_htmlspecialchars($pun_config['o_admin_email']).'</a>.', true);
 		}
 
-		pun_setcookie($new_uid, $password_hash, $save_pass === 1 ? time() + 1209600 : time() + $pun_config['o_timeout_visit']); // мод запоминания пароля - Visman
-		
+        $container->get('UserCookie')->setUserCookie($new_uid, $password_hash, $save_pass === 1);
+
 		// удаляем из онлайн таблицы запись для этого пользователя для правильного подсчета макс. кол-во пользователей - Visman
 		$db->query('DELETE FROM '.$db->prefix.'online WHERE ident=\''.$db->escape(get_remote_address()).'\'') or error('Unable to delete from online list', __FILE__, __LINE__, $db->error());
 

+ 25 - 20
vendor/artoodetoo/container/src/Container.php

@@ -99,10 +99,13 @@ class Container implements ContainerInterface
         $segments = explode('.', $name);
         $ptr =& $this->config;
         foreach ($segments as $s) {
-            if (!isset($ptr[$s])) {
+            if (isset($ptr[$s])
+                || (is_array($ptr) && array_key_exists($s, $ptr))
+            ) {
+                $ptr =& $ptr[$s];
+            } else {
                 return $default;
             }
-            $ptr =& $ptr[$s];
         }
 
         return $ptr;
@@ -140,17 +143,27 @@ class Container implements ContainerInterface
 
     protected function resolve($value)
     {
-        $matches = null;
-        if (is_string($value) && strpos($value, '%') !== false) {
-            // whole string substitution can return any type of value
-            if (preg_match('~^%(\w+)%$~', $value, $matches)) {
-                $value = $this->substitute($matches);
-            // partial string substitution casts value to string
-            } else {
-                $value = preg_replace_callback('~%(\w+)%~', [$this, 'substitute'], $value);
+        if (is_string($value)) {
+            if (strpos($value, '%') !== false) {
+                // whole string substitution can return any type of value
+                if (preg_match('~^%(\w+(?:\.\w+)*)%$~', $value, $matches)) {
+                    $value = $this->getParameter($matches[1]);
+                // partial string substitution casts value to string
+                } else {
+                    $value = preg_replace_callback('~%(\w+(?:\.\w+)*)%~',
+                        function ($matches) {
+                            return $this->getParameter($matches[1], '');
+                        }, $value);
+                }
+            } elseif (isset($value{0}) && $value{0} === '@') {
+                // получение данных из объекта как массива по индексу
+                if (preg_match('~^@([\w-]+)\[(\w+)\]$~', $value, $matches)) {
+                    $obj = $this->get($matches[1]);
+                    return isset($obj[$matches[2]]) ? $obj[$matches[2]] : null;
+                } else {
+                    return $this->get(substr($value, 1));
+                }
             }
-        } elseif (is_string($value) && isset($value{0}) && $value{0} == '@') {
-            return $this->get(substr($value, 1));
         } elseif (is_array($value)) {
             foreach ($value as &$v) {
                 $v = $this->resolve($v);
@@ -159,12 +172,4 @@ class Container implements ContainerInterface
         }
         return $value;
     }
-
-    protected function substitute($matches)
-    {
-        if (array_key_exists($matches[1], $this->config)) {
-            return $this->config[$matches[1]];
-        }
-        return '';
-    }
 }

+ 11 - 9
vendor/composer/installed.json

@@ -1,23 +1,23 @@
 [
     {
         "name": "artoodetoo/container",
-        "version": "dev-master",
-        "version_normalized": "9999999-dev",
+        "version": "dev-visman",
+        "version_normalized": "dev-visman",
         "source": {
             "type": "git",
-            "url": "https://github.com/artoodetoo/container.git",
-            "reference": "1c52096695eb699e2c63b6b84703794d94d0659f"
+            "url": "https://github.com/MioVisman/container.git",
+            "reference": "3ab08b97674dff417f36783c9e054c25540171d3"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/artoodetoo/container/zipball/1c52096695eb699e2c63b6b84703794d94d0659f",
-            "reference": "1c52096695eb699e2c63b6b84703794d94d0659f",
+            "url": "https://api.github.com/repos/MioVisman/container/zipball/3ab08b97674dff417f36783c9e054c25540171d3",
+            "reference": "3ab08b97674dff417f36783c9e054c25540171d3",
             "shasum": ""
         },
         "require": {
             "php": ">=5.6"
         },
-        "time": "2016-12-27 20:57:10",
+        "time": "2017-01-11 15:15:38",
         "type": "library",
         "installation-source": "dist",
         "autoload": {
@@ -25,7 +25,6 @@
                 "R2\\DependencyInjection\\": "src/"
             }
         },
-        "notification-url": "https://packagist.org/downloads/",
         "license": [
             "MIT"
         ],
@@ -38,6 +37,9 @@
         "keywords": [
             "container",
             "service"
-        ]
+        ],
+        "support": {
+            "source": "https://github.com/MioVisman/container/tree/visman"
+        }
     }
 ]