mirror of
https://github.com/Lastorder-DC/rhymix.git
synced 2026-01-04 01:01:41 +09:00
Merge pull request #567 from kijin/pr/session-class
세션 처리 관련 기능 정리 및 개선
This commit is contained in:
commit
99cb67b5db
33 changed files with 1934 additions and 353 deletions
|
|
@ -338,59 +338,23 @@ class Context
|
|||
array(&$oSessionController, 'open'), array(&$oSessionController, 'close'), array(&$oSessionModel, 'read'), array(&$oSessionController, 'write'), array(&$oSessionController, 'destroy'), array(&$oSessionController, 'gc')
|
||||
);
|
||||
}
|
||||
|
||||
// start session
|
||||
$relax_key_checks = ($this->act === 'procFileUpload' && preg_match('/shockwave\s?flash/i', $_SERVER['HTTP_USER_AGENT']));
|
||||
Rhymix\Framework\Session::start(false, $relax_key_checks);
|
||||
|
||||
// start session if it was previously started
|
||||
$session_name = session_name();
|
||||
$session_id = NULL;
|
||||
if($session_id = $_POST[$session_name])
|
||||
{
|
||||
session_id($session_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
$session_id = $_COOKIE[$session_name];
|
||||
}
|
||||
|
||||
if($session_id !== NULL || !config('session.delay'))
|
||||
{
|
||||
$this->setCacheControl(0, false);
|
||||
session_start();
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->setCacheControl(-1, true);
|
||||
$_SESSION = array();
|
||||
}
|
||||
|
||||
// start output buffer
|
||||
ob_start();
|
||||
|
||||
// set authentication information in Context and session
|
||||
if(self::isInstalled())
|
||||
if (self::isInstalled())
|
||||
{
|
||||
$oModuleModel = getModel('module');
|
||||
$oModuleModel->loadModuleExtends();
|
||||
|
||||
$oMemberModel = getModel('member');
|
||||
$oMemberController = getController('member');
|
||||
|
||||
if($oMemberController && $oMemberModel)
|
||||
if (Rhymix\Framework\Session::getMemberSrl())
|
||||
{
|
||||
// if signed in, validate it.
|
||||
if($oMemberModel->isLogged())
|
||||
{
|
||||
$oMemberController->setSessionInfo();
|
||||
}
|
||||
// check auto sign-in
|
||||
elseif($_COOKIE['xeak'])
|
||||
{
|
||||
$oMemberController->doAutologin();
|
||||
}
|
||||
|
||||
self::set('is_logged', $oMemberModel->isLogged());
|
||||
if($oMemberModel->isLogged())
|
||||
{
|
||||
self::set('logged_info', $oMemberModel->getLoggedInfo());
|
||||
}
|
||||
getController('member')->setSessionInfo();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -428,7 +392,7 @@ class Context
|
|||
*/
|
||||
public static function getSessionStatus()
|
||||
{
|
||||
return (session_id() !== '');
|
||||
return Rhymix\Framework\Session::isStarted();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -436,21 +400,9 @@ class Context
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function checkSessionStatus($force_start = false)
|
||||
public static function checkSessionStatus($force = false)
|
||||
{
|
||||
if(self::getSessionStatus())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if($force_start || (count($_SESSION) && !headers_sent()))
|
||||
{
|
||||
$tempSession = $_SESSION;
|
||||
unset($_SESSION);
|
||||
session_start();
|
||||
$_SESSION = $tempSession;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return Rhymix\Framework\Session::checkStart($force);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -467,9 +419,9 @@ class Context
|
|||
}
|
||||
|
||||
// Check session status and close it if open.
|
||||
if (self::checkSessionStatus())
|
||||
if (Rhymix\Framework\Session::checkStart())
|
||||
{
|
||||
session_write_close();
|
||||
Rhymix\Framework\Session::close();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -703,97 +655,7 @@ class Context
|
|||
*/
|
||||
public function checkSSO()
|
||||
{
|
||||
// pass if it's not GET request or XE is not yet installed
|
||||
if(!config('use_sso') || Rhymix\Framework\UA::isRobot())
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
$checkActList = array('rss' => 1, 'atom' => 1);
|
||||
if(self::getRequestMethod() != 'GET' || !self::isInstalled() || isset($checkActList[self::get('act')]))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// pass if default URL is not set
|
||||
$default_url = trim($this->db_info->default_url);
|
||||
if(!$default_url)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if(substr_compare($default_url, '/', -1) !== 0)
|
||||
{
|
||||
$default_url .= '/';
|
||||
}
|
||||
|
||||
// Get current site information (only the base URL, not the full URL)
|
||||
$current_site = self::getRequestUri();
|
||||
|
||||
// Step 1: if the current site is not the default site, send SSO validation request to the default site
|
||||
if($default_url !== $current_site && !self::get('sso_response') && $_COOKIE['sso'] !== md5($current_site))
|
||||
{
|
||||
// Set sso cookie to prevent multiple simultaneous SSO validation requests
|
||||
setcookie('sso', md5($current_site), 0, '/');
|
||||
|
||||
// Redirect to the default site
|
||||
$sso_request = Rhymix\Framework\Security::encrypt(Rhymix\Framework\URL::getCurrentURL());
|
||||
$redirect_url = $default_url . '?sso_request=' . urlencode($sso_request);
|
||||
header('Location:' . $redirect_url);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 2: receive and process SSO validation request at the default site
|
||||
if($default_url === $current_site && self::get('sso_request'))
|
||||
{
|
||||
// Get the URL of the origin site
|
||||
$sso_request = Rhymix\Framework\Security::decrypt(self::get('sso_request'));
|
||||
if (!$sso_request || !preg_match('!^https?://!', $sso_request))
|
||||
{
|
||||
self::displayErrorPage('SSO Error', 'Invalid SSO Request', 400);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that the origin site is a valid site in this XE installation (to prevent open redirect vuln)
|
||||
if(!getModel('module')->getSiteInfoByDomain(rtrim($url, '/'))->site_srl)
|
||||
{
|
||||
self::displayErrorPage('SSO Error', 'Invalid SSO Request', 400);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Redirect back to the origin site
|
||||
$sso_response = Rhymix\Framework\Security::encrypt(session_id());
|
||||
header('Location: ' . Rhymix\Framework\URL::modifyURL($sso_request, array('sso_response' => $sso_response)));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 3: back at the origin site, set session ID to be the same as the default site
|
||||
if($default_url !== $current_site && self::get('sso_response'))
|
||||
{
|
||||
// Check SSO response
|
||||
$sso_response = Rhymix\Framework\Security::decrypt(self::get('sso_response'));
|
||||
if ($sso_response === false)
|
||||
{
|
||||
self::displayErrorPage('SSO Error', 'Invalid SSO Response', 400);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that the response was given by the default site (to prevent session fixation CSRF)
|
||||
if(isset($_SERVER['HTTP_REFERER']) && strpos($_SERVER['HTTP_REFERER'], $default_url) !== 0)
|
||||
{
|
||||
self::displayErrorPage('SSO Error', 'Invalid SSO Response', 400);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set session ID
|
||||
setcookie(session_name(), $sso_response);
|
||||
|
||||
// Finally, redirect to the originally requested URL
|
||||
header('Location: ' . Rhymix\Framework\URL::getCurrentURL(array('sso_response' => null)));
|
||||
return false;
|
||||
}
|
||||
|
||||
// If none of the conditions above apply, proceed normally
|
||||
return TRUE;
|
||||
return !Rhymix\Framework\Session::checkSSO();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -956,6 +956,29 @@ class DBCubrid extends DB
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop table
|
||||
*
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
function dropTable($table_name)
|
||||
{
|
||||
// Generate the drop query
|
||||
$query = sprintf('drop class "%s"', $this->addQuotes($this->prefix . $table_name));
|
||||
|
||||
// Execute the drop query
|
||||
$output = $this->_query($query);
|
||||
if($output)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles insertAct
|
||||
* @param Object $queryObject
|
||||
|
|
|
|||
|
|
@ -748,6 +748,29 @@ class DBMssql extends DB
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop table
|
||||
*
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
function dropTable($table_name)
|
||||
{
|
||||
// Generate the drop query
|
||||
$query = sprintf('DROP TABLE %s', $this->addQuotes($this->prefix . $table_name));
|
||||
|
||||
// Execute the drop query
|
||||
$output = $this->_query($query);
|
||||
if($output)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles insertAct
|
||||
* @todo Lookup _filterNumber against sql injection - see if it is still needed and how to integrate
|
||||
|
|
|
|||
|
|
@ -682,6 +682,29 @@ class DBMysql extends DB
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop table
|
||||
*
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
function dropTable($table_name)
|
||||
{
|
||||
// Generate the drop query
|
||||
$query = sprintf('DROP TABLE `%s`', $this->addQuotes($this->prefix . $table_name));
|
||||
|
||||
// Execute the drop query
|
||||
$output = $this->_query($query);
|
||||
if($output)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles insertAct
|
||||
* @param Object $queryObject
|
||||
|
|
|
|||
|
|
@ -45,12 +45,22 @@ class Mobile
|
|||
|
||||
// Try to detect from URL arguments and cookies, and finally fall back to user-agent detection.
|
||||
$m = Context::get('m');
|
||||
$cookie = (isset($_COOKIE['mobile']) && $_SESSION['user_agent'] === md5($_SERVER['HTTP_USER_AGENT'])) ? $_COOKIE['mobile'] : null;
|
||||
if ($m === '1' || ($m === null && $cookie === 'true'))
|
||||
$cookie = isset($_COOKIE['rx_uatype']) ? $_COOKIE['rx_uatype'] : null;
|
||||
$uahash = base64_encode_urlsafe(md5($_SERVER['HTTP_USER_AGENT'], true));
|
||||
if (strncmp($cookie, $uahash . ':', strlen($uahash) + 1) !== 0)
|
||||
{
|
||||
$cookie = null;
|
||||
}
|
||||
elseif ($m === null)
|
||||
{
|
||||
$m = substr($cookie, -1);
|
||||
}
|
||||
|
||||
if ($m === '1')
|
||||
{
|
||||
self::$_ismobile = TRUE;
|
||||
}
|
||||
elseif ($m === '0' || ($m === null && $cookie === 'false'))
|
||||
elseif ($m === '0')
|
||||
{
|
||||
self::$_ismobile = FALSE;
|
||||
}
|
||||
|
|
@ -60,11 +70,11 @@ class Mobile
|
|||
}
|
||||
|
||||
// Set cookie to prevent recalculation.
|
||||
if ($cookie !== (self::$_ismobile ? 'true' : 'false'))
|
||||
$uatype = $uahash . ':' . (self::$_ismobile ? '1' : '0');
|
||||
if ($cookie !== $uatype)
|
||||
{
|
||||
$_SESSION['user_agent'] = md5($_SERVER['HTTP_USER_AGENT']);
|
||||
$_COOKIE['mobile'] = self::$_ismobile ? 'true' : 'false';
|
||||
setcookie('mobile', $_COOKIE['mobile'], 0, RX_BASEURL);
|
||||
setcookie('rx_uatype', $uatype, 0, RX_BASEURL);
|
||||
$_COOKIE['rx_uatype'] = $uatype;
|
||||
}
|
||||
|
||||
return self::$_ismobile;
|
||||
|
|
|
|||
|
|
@ -1178,6 +1178,12 @@ class ModuleHandler extends Handler
|
|||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Populate default properties
|
||||
if($oModule->user === false)
|
||||
{
|
||||
$oModule->user = Context::get('logged_info') ?: new Rhymix\Framework\Helpers\SessionHelper;
|
||||
}
|
||||
|
||||
// Load language files for the class
|
||||
if($module !== 'module')
|
||||
|
|
|
|||
|
|
@ -26,6 +26,20 @@ class ModuleObject extends Object
|
|||
var $module_config = NULL;
|
||||
var $ajaxRequestMethod = array('XMLRPC', 'JSON');
|
||||
var $gzhandler_enable = TRUE;
|
||||
var $user = FALSE;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param int $error Error code
|
||||
* @param string $message Error message
|
||||
* @return void
|
||||
*/
|
||||
function __construct($error = 0, $message = 'success')
|
||||
{
|
||||
$this->user = Context::get('logged_info') ?: new Rhymix\Framework\Helpers\SessionHelper;
|
||||
parent::__construct($error, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* setter to set the name of module
|
||||
|
|
|
|||
|
|
@ -20,6 +20,11 @@ class TemplateHandler
|
|||
private $skipTags = NULL;
|
||||
private $handler_mtime = 0;
|
||||
private static $rootTpl = NULL;
|
||||
|
||||
/**
|
||||
* Context variables accessible as $this in template files
|
||||
*/
|
||||
public $user = FALSE;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
|
|
@ -29,6 +34,7 @@ class TemplateHandler
|
|||
{
|
||||
$this->config = new stdClass;
|
||||
$this->handler_mtime = filemtime(__FILE__);
|
||||
$this->user = Context::get('logged_info') ?: new Rhymix\Framework\Helpers\SessionHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -818,7 +824,7 @@ class TemplateHandler
|
|||
}
|
||||
|
||||
return preg_replace_callback('@(?<!::|\\\\|(?<!eval\()\')\$([a-z_][a-z0-9_]*)@i', function($matches) {
|
||||
if (preg_match('/^(?:GLOBALS|_SERVER|_COOKIE|_GET|_POST|_REQUEST|__Context)$/', $matches[1]))
|
||||
if (preg_match('/^(?:GLOBALS|_SERVER|_COOKIE|_GET|_POST|_REQUEST|__Context|this)$/', $matches[1]))
|
||||
{
|
||||
return '$' . $matches[1];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,10 +7,12 @@
|
|||
*/
|
||||
return array(
|
||||
'autolang' => true,
|
||||
'auto_login' => true,
|
||||
'errorlogger' => true,
|
||||
'fix_mysql_utf8' => true,
|
||||
'member_communication' => true,
|
||||
'seo' => true,
|
||||
'session_shield' => true,
|
||||
'smartphone' => true,
|
||||
'zipperupper' => true,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -62,9 +62,9 @@ class DateTime
|
|||
*/
|
||||
public static function getTimezoneForCurrentUser()
|
||||
{
|
||||
if (isset($_SESSION['timezone']) && $_SESSION['timezone'])
|
||||
if (isset($_SESSION['RHYMIX']['timezone']) && $_SESSION['RHYMIX']['timezone'])
|
||||
{
|
||||
return $_SESSION['timezone'];
|
||||
return $_SESSION['RHYMIX']['timezone'];
|
||||
}
|
||||
elseif ($default = Config::get('locale.default_timezone'))
|
||||
{
|
||||
|
|
|
|||
101
common/framework/helpers/sessionhelper.php
Normal file
101
common/framework/helpers/sessionhelper.php
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
<?php
|
||||
|
||||
namespace Rhymix\Framework\Helpers;
|
||||
|
||||
/**
|
||||
* Session helper class.
|
||||
*/
|
||||
class SessionHelper
|
||||
{
|
||||
/**
|
||||
* Instance properties.
|
||||
*/
|
||||
public $member_srl = 0;
|
||||
public $is_admin = 'N';
|
||||
public $group_list = array();
|
||||
public $menu_list = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param int $member_srl (optional)
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($member_srl = null)
|
||||
{
|
||||
// Load member information.
|
||||
$member_srl = intval($member_srl);
|
||||
if ($member_srl)
|
||||
{
|
||||
$oMemberModel = getModel('member');
|
||||
$member_info = $oMemberModel->getMemberInfoByMemberSrl($member_srl);
|
||||
if (intval($member_info->member_srl) === $member_srl)
|
||||
{
|
||||
foreach (get_object_vars($member_info) as $key => $value)
|
||||
{
|
||||
$this->{$key} = $value;
|
||||
}
|
||||
$this->member_srl = $member_srl;
|
||||
$this->group_list = $oMemberModel->getMemberGroups($member_srl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this user is a member.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isMember()
|
||||
{
|
||||
return $this->member_srl > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this user is an administrator.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isAdmin()
|
||||
{
|
||||
return $this->is_admin === 'Y';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this user is an administrator of a module.
|
||||
*
|
||||
* @param int $module_srl (optional)
|
||||
* @return bool
|
||||
*/
|
||||
public function isModuleAdmin($module_srl = null)
|
||||
{
|
||||
return $this->is_admin === 'Y' || getModel('module')->isModuleAdmin($this, $module_srl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this user is valid (not denied or limited).
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid()
|
||||
{
|
||||
if ($this->denied === 'N' && (!$this->limit_date || substr($this->limit_date, 0, 8) < date('Ymd')))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of groups that this user belongs to.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getGroups()
|
||||
{
|
||||
return $this->group_list;
|
||||
}
|
||||
}
|
||||
|
|
@ -153,7 +153,7 @@ class Security
|
|||
* @param string $format
|
||||
* @return string
|
||||
*/
|
||||
public function getRandom($length = 32, $format = 'alnum')
|
||||
public static function getRandom($length = 32, $format = 'alnum')
|
||||
{
|
||||
// Find out how many bytes of entropy we really need.
|
||||
switch($format)
|
||||
|
|
|
|||
999
common/framework/session.php
Normal file
999
common/framework/session.php
Normal file
|
|
@ -0,0 +1,999 @@
|
|||
<?php
|
||||
|
||||
namespace Rhymix\Framework;
|
||||
|
||||
/**
|
||||
* The session class.
|
||||
*/
|
||||
class Session
|
||||
{
|
||||
/**
|
||||
* Properties for internal use only.
|
||||
*/
|
||||
protected static $_started = false;
|
||||
protected static $_autologin_key = false;
|
||||
protected static $_member_info = false;
|
||||
|
||||
/**
|
||||
* Get a session variable.
|
||||
*
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get($key)
|
||||
{
|
||||
$data = $_SESSION;
|
||||
$key = explode('.', $key);
|
||||
foreach ($key as $step)
|
||||
{
|
||||
if ($key === '' || !isset($data[$step]))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
$data = $data[$step];
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a session variable.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
*/
|
||||
public static function set($key, $value)
|
||||
{
|
||||
$data = &$_SESSION;
|
||||
$key = explode('.', $key);
|
||||
foreach ($key as $step)
|
||||
{
|
||||
$data = &$data[$step];
|
||||
}
|
||||
$data = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the session.
|
||||
*
|
||||
* This method is called automatically at Rhymix startup.
|
||||
* There is usually no need to call it manually.
|
||||
*
|
||||
* @param bool $force (optional)
|
||||
* @param bool $relax_key_checks (optional)
|
||||
* @return bool
|
||||
*/
|
||||
public static function start($force = false, $relax_key_checks = false)
|
||||
{
|
||||
// Do not start the session if it is already started.
|
||||
if (self::$_started)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set session parameters.
|
||||
list($lifetime, $refresh_interval, $domain, $path) = self::_getParams();
|
||||
ini_set('session.gc_maxlifetime', $lifetime + 28800);
|
||||
ini_set('session.use_cookies', 1);
|
||||
ini_set('session.use_only_cookies', 1);
|
||||
ini_set('session.use_strict_mode', 1);
|
||||
session_set_cookie_params($lifetime, $path, $domain, false, false);
|
||||
session_name($session_name = Config::get('session.name') ?: session_name());
|
||||
|
||||
// Get session ID from POST parameter if using relaxed key checks.
|
||||
if ($relax_key_checks && isset($_POST[$session_name]))
|
||||
{
|
||||
session_id($_POST[$session_name]);
|
||||
}
|
||||
|
||||
// Abort if using delayed session.
|
||||
if(Config::get('session.delay') && !$force && !isset($_COOKIE[$session_name]))
|
||||
{
|
||||
$_SESSION = array();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Start the PHP native session.
|
||||
if (!session_start())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Mark the session as started.
|
||||
self::$_started = true;
|
||||
|
||||
// Fetch session keys.
|
||||
list($key1, $key2, self::$_autologin_key) = self::_getKeys();
|
||||
$must_create = $must_refresh = $must_resend_keys = false;
|
||||
|
||||
// Validate the HTTP key.
|
||||
if (isset($_SESSION['RHYMIX']) && $_SESSION['RHYMIX'])
|
||||
{
|
||||
if (!isset($_SESSION['RHYMIX']['keys'][$domain]) && config('use_sso'))
|
||||
{
|
||||
$must_refresh = true;
|
||||
}
|
||||
elseif ($_SESSION['RHYMIX']['keys'][$domain]['key1'] === $key1 && $key1 !== null)
|
||||
{
|
||||
// OK
|
||||
}
|
||||
elseif ($_SESSION['RHYMIX']['keys'][$domain]['key1_prev'] === $key1 && $key1 !== null)
|
||||
{
|
||||
$must_resend_keys = true;
|
||||
}
|
||||
elseif (!$relax_key_checks)
|
||||
{
|
||||
// Hacked session! Destroy everything.
|
||||
$_SESSION = array();
|
||||
$must_create = true;
|
||||
self::destroyAutologinKeys();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$must_create = true;
|
||||
}
|
||||
|
||||
// Validate the SSL key.
|
||||
if (!$must_create && \RX_SSL)
|
||||
{
|
||||
if (!isset($_SESSION['RHYMIX']['keys'][$domain]['key2']))
|
||||
{
|
||||
$must_refresh = true;
|
||||
}
|
||||
elseif ($_SESSION['RHYMIX']['keys'][$domain]['key2'] === $key2 && $key2 !== null)
|
||||
{
|
||||
// OK
|
||||
}
|
||||
elseif ($_SESSION['RHYMIX']['keys'][$domain]['key2_prev'] === $key2 && $key2 !== null)
|
||||
{
|
||||
$must_resend_keys = true;
|
||||
}
|
||||
elseif (!$relax_key_checks)
|
||||
{
|
||||
// Hacked session! Destroy everything.
|
||||
$_SESSION = array();
|
||||
$must_create = true;
|
||||
self::destroyAutologinKeys();
|
||||
}
|
||||
}
|
||||
|
||||
// Check the refresh interval.
|
||||
if (!$must_create && $_SESSION['RHYMIX']['keys'][$domain]['key1_time'] < time() - $refresh_interval && !$relax_key_checks)
|
||||
{
|
||||
$must_refresh = true;
|
||||
}
|
||||
elseif (!$must_create && \RX_SSL && $_SESSION['RHYMIX']['keys'][$domain]['key2_time'] < time() - $refresh_interval && !$relax_key_checks)
|
||||
{
|
||||
$must_refresh = true;
|
||||
}
|
||||
|
||||
// If a member is logged in, check if the current session is valid for the member_srl.
|
||||
if (isset($_SESSION['RHYMIX']['login']) && $_SESSION['RHYMIX']['login'] && !self::isValid($_SESSION['RHYMIX']['login']))
|
||||
{
|
||||
$_SESSION['RHYMIX']['login'] = $_SESSION['member_srl'] = false;
|
||||
$must_create = true;
|
||||
}
|
||||
|
||||
// Create or refresh the session if needed.
|
||||
if ($must_create)
|
||||
{
|
||||
return self::create();
|
||||
}
|
||||
elseif ($must_refresh)
|
||||
{
|
||||
return self::refresh();
|
||||
}
|
||||
elseif ($must_resend_keys)
|
||||
{
|
||||
return self::_setKeys();
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the session needs to be started.
|
||||
*
|
||||
* This method is called automatically at Rhymix shutdown.
|
||||
* It is only necessary if the session is delayed.
|
||||
*
|
||||
* @param bool $force (optional)
|
||||
* @return bool
|
||||
*/
|
||||
public static function checkStart($force = false)
|
||||
{
|
||||
// Return if the session is already started.
|
||||
if (self::$_started)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Start the session if it contains data.
|
||||
if ($force || (count($_SESSION) && !headers_sent()))
|
||||
{
|
||||
// Copy session data to a temporary array.
|
||||
$temp = $_SESSION;
|
||||
unset($_SESSION);
|
||||
|
||||
// Start the session.
|
||||
self::start(true);
|
||||
|
||||
// Copy session data back to $_SESSION.
|
||||
foreach ($temp as $key => $val)
|
||||
{
|
||||
if ($key !== 'RHYMIX')
|
||||
{
|
||||
$_SESSION[$key] = $val;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return false if nothing needed to be done.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this session needs to be shared with another site with SSO.
|
||||
*
|
||||
* This method uses more or less the same logic as XE's SSO mechanism.
|
||||
* It may need to be changed to a more secure mechanism later.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function checkSSO()
|
||||
{
|
||||
// Abort if SSO is disabled, the visitor is a robot, or this is not a typical GET request.
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'GET' || !config('use_sso') || UA::isRobot() || in_array(\Context::get('act'), array('rss', 'atom')))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Abort of the default URL is not set.
|
||||
$default_url = \Context::getDefaultUrl();
|
||||
if (!$default_url)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the current site information.
|
||||
$current_url = URL::getCurrentURL();
|
||||
$current_host = parse_url($current_url, \PHP_URL_HOST);
|
||||
$default_host = parse_url($default_url, \PHP_URL_HOST);
|
||||
|
||||
// Step 1: if the current site is not the default site, send SSO validation request to the default site.
|
||||
if($default_host !== $current_host && !\Context::get('sso_response') && $_COOKIE['sso'] !== md5($current_host))
|
||||
{
|
||||
// Set sso cookie to prevent multiple simultaneous SSO validation requests.
|
||||
setcookie('sso', md5($current_host), 0, '/');
|
||||
|
||||
// Redirect to the default site.
|
||||
$sso_request = Security::encrypt($current_url);
|
||||
header('Location:' . URL::modifyURL($default_url, array('sso_request' => $sso_request)));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Step 2: receive and process SSO validation request at the default site.
|
||||
if($default_host === $current_host && \Context::get('sso_request'))
|
||||
{
|
||||
// Get the URL of the origin site
|
||||
$sso_request = Security::decrypt(\Context::get('sso_request'));
|
||||
if (!$sso_request || !preg_match('!^https?://!', $sso_request))
|
||||
{
|
||||
\Context::displayErrorPage('SSO Error', 'Invalid SSO Request', 400);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Redirect back to the origin site.
|
||||
$sso_response = Security::encrypt(session_id());
|
||||
header('Location: ' . URL::modifyURL($sso_request, array('sso_response' => $sso_response)));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Step 3: back at the origin site, set session ID to be the same as the default site.
|
||||
if($default_host !== $current_host && \Context::get('sso_response'))
|
||||
{
|
||||
// Check SSO response
|
||||
$sso_response = Security::decrypt(\Context::get('sso_response'));
|
||||
if ($sso_response === false)
|
||||
{
|
||||
\Context::displayErrorPage('SSO Error', 'Invalid SSO Response', 400);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check that the response was given by the default site (to prevent session fixation CSRF).
|
||||
if(isset($_SERVER['HTTP_REFERER']) && strpos($_SERVER['HTTP_REFERER'], $default_url) !== 0)
|
||||
{
|
||||
\Context::displayErrorPage('SSO Error', 'Invalid SSO Response', 400);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Set session ID.
|
||||
self::close();
|
||||
session_id($sso_response);
|
||||
self::start();
|
||||
|
||||
// Finally, redirect to the originally requested URL.
|
||||
header('Location: ' . URL::getCurrentURL(array('sso_response' => null)));
|
||||
return true;
|
||||
}
|
||||
|
||||
// If none of the conditions above apply, proceed normally.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the data structure for a new Rhymix session.
|
||||
*
|
||||
* This method is called automatically by start() when needed.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function create()
|
||||
{
|
||||
// Create the data structure for a new Rhymix session.
|
||||
$_SESSION['RHYMIX'] = array();
|
||||
$_SESSION['RHYMIX']['login'] = false;
|
||||
$_SESSION['RHYMIX']['last_login'] = false;
|
||||
$_SESSION['RHYMIX']['ipaddress'] = $_SESSION['ipaddress'] = \RX_CLIENT_IP;
|
||||
$_SESSION['RHYMIX']['useragent'] = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
|
||||
$_SESSION['RHYMIX']['language'] = \Context::getLangType();
|
||||
$_SESSION['RHYMIX']['timezone'] = DateTime::getTimezoneForCurrentUser();
|
||||
$_SESSION['RHYMIX']['secret'] = Security::getRandom(32, 'alnum');
|
||||
$_SESSION['RHYMIX']['tokens'] = array();
|
||||
$_SESSION['is_logged'] = false;
|
||||
$_SESSION['is_admin'] = '';
|
||||
|
||||
// Ensure backward compatibility with XE session.
|
||||
$member_srl = isset($_SESSION['member_srl']) ? ($_SESSION['member_srl'] ?: false) : false;
|
||||
if ($member_srl && self::isValid($member_srl))
|
||||
{
|
||||
self::login($member_srl, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
$_SESSION['member_srl'] = false;
|
||||
}
|
||||
|
||||
// Try autologin.
|
||||
if (!$member_srl && self::$_autologin_key)
|
||||
{
|
||||
$member_srl = getController('member')->doAutologin(self::$_autologin_key);
|
||||
if ($member_srl && self::isValid($member_srl))
|
||||
{
|
||||
self::login($member_srl, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
self::destroyAutologinKeys();
|
||||
}
|
||||
}
|
||||
|
||||
// Pass control to refresh() to generate security keys.
|
||||
return self::refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the session.
|
||||
*
|
||||
* This method can be used to invalidate old session cookies.
|
||||
* It is called automatically when someone logs in or out.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function refresh()
|
||||
{
|
||||
// Get session parameters.
|
||||
list($lifetime, $refresh_interval, $domain, $path) = self::_getParams();
|
||||
|
||||
// Set the domain initialization timestamp.
|
||||
if (!isset($_SESSION['RHYMIX']['keys'][$domain]['started']))
|
||||
{
|
||||
$_SESSION['RHYMIX']['keys'][$domain]['started'] = time();
|
||||
}
|
||||
|
||||
// Reset the trusted information.
|
||||
if (!isset($_SESSION['RHYMIX']['keys'][$domain]['trusted']))
|
||||
{
|
||||
$_SESSION['RHYMIX']['keys'][$domain]['trusted'] = 0;
|
||||
}
|
||||
|
||||
// Create or refresh the HTTP-only key.
|
||||
if (isset($_SESSION['RHYMIX']['keys'][$domain]['key1']))
|
||||
{
|
||||
$_SESSION['RHYMIX']['keys'][$domain]['key1_prev'] = $_SESSION['RHYMIX']['keys'][$domain]['key1'];
|
||||
}
|
||||
$_SESSION['RHYMIX']['keys'][$domain]['key1'] = Security::getRandom(24, 'alnum');
|
||||
$_SESSION['RHYMIX']['keys'][$domain]['key1_time'] = time();
|
||||
|
||||
// Create or refresh the HTTPS-only key.
|
||||
if (\RX_SSL)
|
||||
{
|
||||
if (isset($_SESSION['RHYMIX']['keys'][$domain]['key2']))
|
||||
{
|
||||
$_SESSION['RHYMIX']['keys'][$domain]['key2_prev'] = $_SESSION['RHYMIX']['keys'][$domain]['key2'];
|
||||
}
|
||||
$_SESSION['RHYMIX']['keys'][$domain]['key2'] = Security::getRandom(24, 'alnum');
|
||||
$_SESSION['RHYMIX']['keys'][$domain]['key2_time'] = time();
|
||||
}
|
||||
|
||||
// Pass control to _setKeys() to send the keys to the client.
|
||||
return self::_setKeys();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the session and write its data.
|
||||
*
|
||||
* This method is called automatically at the end of a request, but you can
|
||||
* call it sooner if you don't plan to write any more data to the session.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function close()
|
||||
{
|
||||
self::$_started = false;
|
||||
session_write_close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the session.
|
||||
*
|
||||
* This method deletes all data associated with the current session.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function destroy()
|
||||
{
|
||||
unset($_SESSION['RHYMIX']);
|
||||
self::$_started = false;
|
||||
self::$_member_info = false;
|
||||
self::_setKeys();
|
||||
self::destroyAutologinKeys();
|
||||
@session_destroy();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log in.
|
||||
*
|
||||
* This method accepts either an integer or a member object.
|
||||
* It returns true on success and false on failure.
|
||||
*
|
||||
* @param int $member_srl
|
||||
* @param bool $refresh (optional)
|
||||
* @return bool
|
||||
*/
|
||||
public static function login($member_srl, $refresh = true)
|
||||
{
|
||||
// Check the validity of member_srl.
|
||||
if (is_object($member_srl) && isset($member_srl->member_srl))
|
||||
{
|
||||
$member_srl = $member_srl->member_srl;
|
||||
}
|
||||
if ($member_srl < 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set member_srl to session.
|
||||
$_SESSION['RHYMIX']['login'] = $_SESSION['member_srl'] = $member_srl;
|
||||
$_SESSION['RHYMIX']['last_login'] = time();
|
||||
$_SESSION['is_logged'] = (bool)$member_srl;
|
||||
self::$_member_info = false;
|
||||
|
||||
// Refresh the session keys.
|
||||
if ($refresh)
|
||||
{
|
||||
return self::refresh();
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log out.
|
||||
*
|
||||
* This method returns true on success and false on failure.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function logout()
|
||||
{
|
||||
$_SESSION['RHYMIX']['login'] = $_SESSION['member_srl'] = false;
|
||||
$_SESSION['RHYMIX']['last_login'] = false;
|
||||
$_SESSION['is_logged'] = false;
|
||||
self::$_member_info = false;
|
||||
return self::destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the session has been started.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isStarted()
|
||||
{
|
||||
return self::$_started;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a member has logged in with this session.
|
||||
*
|
||||
* This method returns true or false, not 'Y' or 'N'.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isMember()
|
||||
{
|
||||
return ($_SESSION['member_srl'] > 0 && $_SESSION['RHYMIX']['login'] > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an administrator is logged in with this session.
|
||||
*
|
||||
* This method returns true or false, not 'Y' or 'N'.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isAdmin()
|
||||
{
|
||||
$member_info = self::getMemberInfo();
|
||||
return ($member_info && $member_info->is_admin === 'Y');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current session is trusted.
|
||||
*
|
||||
* This can be useful if you want to force a password check before granting
|
||||
* access to certain pages. The duration of trust can be set by calling
|
||||
* the Session::setTrusted() method.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isTrusted()
|
||||
{
|
||||
// Get session parameters.
|
||||
list($lifetime, $refresh_interval, $domain, $path) = self::_getParams();
|
||||
|
||||
// Check the 'trusted' parameter.
|
||||
if ($_SESSION['RHYMIX']['keys'][$domain]['trusted'] > time())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current session is valid for a given member_srl.
|
||||
*
|
||||
* The session can be invalidated by password changes and other user action.
|
||||
*
|
||||
* @param int $member_srl (optional)
|
||||
* @return bool
|
||||
*/
|
||||
public static function isValid($member_srl = null)
|
||||
{
|
||||
// If no member_srl is given, the session is always valid.
|
||||
$member_srl = intval($member_srl) ?: (isset($_SESSION['RHYMIX']['login']) ? $_SESSION['RHYMIX']['login'] : 0);
|
||||
if (!$member_srl)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the invalidation timestamp.
|
||||
$invalid_before = Cache::get(sprintf('session:invalid_before:%d', $member_srl));
|
||||
if (!$invalid_before)
|
||||
{
|
||||
$filename = \RX_BASEDIR . sprintf('files/member_extra_info/invalid_before/%s%d.txt', getNumberingPath($member_srl), $member_srl);
|
||||
$invalid_before = intval(Storage::read($filename, $invalid_before));
|
||||
}
|
||||
|
||||
// Check the invalidation timestamp against the current session.
|
||||
if ($invalid_before && self::isStarted() && $_SESSION['RHYMIX']['last_login'] && $_SESSION['RHYMIX']['last_login'] < $invalid_before)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check member information to see if denied or limited.
|
||||
$member_info = getModel('member')->getMemberInfoByMemberSrl($member_srl);
|
||||
if ($member_info->denied === 'Y')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ($member_info->limit_date && substr($member_info->limit_date, 0, 8) >= date('Ymd'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return true if all checks have passed.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the member_srl of the currently logged in member.
|
||||
*
|
||||
* This method returns an integer, or false if nobody is logged in.
|
||||
*
|
||||
* @return int|false
|
||||
*/
|
||||
public static function getMemberSrl()
|
||||
{
|
||||
return $_SESSION['member_srl'] ?: ($_SESSION['RHYMIX']['login'] ?: false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get information about the currently logged in member.
|
||||
*
|
||||
* This method returns an object, or false if nobody is logged in.
|
||||
*
|
||||
* @return object|false
|
||||
*/
|
||||
public static function getMemberInfo()
|
||||
{
|
||||
// Return false if the current user is not logged in.
|
||||
$member_srl = self::getMemberSrl();
|
||||
if (!$member_srl)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create a member info object.
|
||||
if (!self::$_member_info || self::$_member_info->member_srl != $member_srl)
|
||||
{
|
||||
self::$_member_info = new Helpers\SessionHelper($member_srl);
|
||||
}
|
||||
|
||||
// Return the member info object.
|
||||
return self::$_member_info->member_srl ? self::$_member_info : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the member info.
|
||||
*
|
||||
* This method is for debugging and testing purposes only.
|
||||
*
|
||||
* @param object $member_info
|
||||
* @return void
|
||||
*/
|
||||
public static function setMemberInfo($member_info)
|
||||
{
|
||||
self::$_member_info = $member_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current user's preferred language.
|
||||
*
|
||||
* If the current user does not have a preferred language, this method
|
||||
* will return the default language.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getLanguage()
|
||||
{
|
||||
return isset($_SESSION['RHYMIX']['language']) ? $_SESSION['RHYMIX']['language'] : \Context::getLangType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current user's preferred language.
|
||||
*
|
||||
* @param string $language
|
||||
* @return bool
|
||||
*/
|
||||
public static function setLanguage($language)
|
||||
{
|
||||
$_SESSION['RHYMIX']['language'] = $language;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current user's preferred time zone.
|
||||
*
|
||||
* If the current user does not have a preferred time zone, this method
|
||||
* will return the default time zone for display.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getTimezone()
|
||||
{
|
||||
return DateTime::getTimezoneForCurrentUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current user's preferred time zone.
|
||||
*
|
||||
* @param string $timezone
|
||||
* @return bool
|
||||
*/
|
||||
public static function setTimezone($timezone)
|
||||
{
|
||||
$_SESSION['RHYMIX']['timezone'] = $timezone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the current session as trusted for a given duration.
|
||||
*
|
||||
* See isTrusted() for description.
|
||||
*
|
||||
* @param int $duration (optional, default is 300 seconds)
|
||||
* @return bool
|
||||
*/
|
||||
public static function setTrusted($duration = 300)
|
||||
{
|
||||
// Get session parameters.
|
||||
list($lifetime, $refresh_interval, $domain, $path) = self::_getParams();
|
||||
|
||||
// Update the 'trusted' parameter if the current user is logged in.
|
||||
if (isset($_SESSION['RHYMIX']['keys'][$domain]) && $_SESSION['RHYMIX']['login'])
|
||||
{
|
||||
$_SESSION['RHYMIX']['keys'][$domain]['trusted'] = time() + $duration;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a token that can only be verified in the same session.
|
||||
*
|
||||
* This can be used to create CSRF tokens, etc.
|
||||
* If you specify a key, the same key must be used to verify the token.
|
||||
*
|
||||
* @param string $key (optional)
|
||||
* @return string
|
||||
*/
|
||||
public static function createToken($key = null)
|
||||
{
|
||||
$token = Security::getRandom(16, 'alnum');
|
||||
$_SESSION['RHYMIX']['tokens'][$token] = strval($key);
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify a token.
|
||||
*
|
||||
* This method returns true if the token is valid, and false otherwise.
|
||||
*
|
||||
* @param string $token
|
||||
* @param string $key (optional)
|
||||
* @return bool
|
||||
*/
|
||||
public static function verifyToken($token, $key = null)
|
||||
{
|
||||
if (isset($_SESSION['RHYMIX']['tokens'][$token]) && $_SESSION['RHYMIX']['tokens'][$token] === strval($key))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate a token so that it cannot be verified.
|
||||
*
|
||||
* @param string $token
|
||||
* @param string $key (optional)
|
||||
* @return bool
|
||||
*/
|
||||
public static function invalidateToken($token)
|
||||
{
|
||||
if (isset($_SESSION['RHYMIX']['tokens'][$token]))
|
||||
{
|
||||
unset($_SESSION['RHYMIX']['tokens'][$token]);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt data so that it can only be decrypted in the same session.
|
||||
*
|
||||
* Arrays and objects can also be encrypted. (They will be serialized.)
|
||||
* Resources and the boolean false value will not be preserved.
|
||||
*
|
||||
* @param mixed $plaintext
|
||||
* @return string
|
||||
*/
|
||||
public static function encrypt($plaintext)
|
||||
{
|
||||
$key = $_SESSION['RHYMIX']['secret'] . Config::get('crypto.encryption_key');
|
||||
return Security::encrypt($plaintext, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt data that was encrypted in the same session.
|
||||
*
|
||||
* This method returns the decrypted data, or false on failure.
|
||||
* All users of this method must be designed to handle failures safely.
|
||||
*
|
||||
* @param string $ciphertext
|
||||
* @return mixed
|
||||
*/
|
||||
public static function decrypt($ciphertext)
|
||||
{
|
||||
$key = $_SESSION['RHYMIX']['secret'] . Config::get('crypto.encryption_key');
|
||||
return Security::decrypt($ciphertext, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get session parameters.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function _getParams()
|
||||
{
|
||||
$lifetime = Config::get('session.lifetime');
|
||||
$refresh = Config::get('session.refresh') ?: 300;
|
||||
$domain = Config::get('session.domain') ?: (ini_get('session.cookie_domain') ?: preg_replace('/:\\d+$/', '', $_SERVER['HTTP_HOST']));
|
||||
$path = Config::get('session.path') ?: ini_get('session.cookie_path');
|
||||
return array($lifetime, $refresh, $domain, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get session keys.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function _getKeys()
|
||||
{
|
||||
// Initialize keys.
|
||||
$key1 = $key2 = $key3 = null;
|
||||
|
||||
// Fetch and validate the HTTP-only key.
|
||||
if (isset($_COOKIE['rx_sesskey1']) && ctype_alnum($_COOKIE['rx_sesskey1']) && strlen($_COOKIE['rx_sesskey1']) === 24)
|
||||
{
|
||||
$key1 = $_COOKIE['rx_sesskey1'];
|
||||
}
|
||||
|
||||
// Fetch and validate the HTTPS-only key.
|
||||
if (isset($_COOKIE['rx_sesskey2']) && ctype_alnum($_COOKIE['rx_sesskey2']) && strlen($_COOKIE['rx_sesskey2']) === 24)
|
||||
{
|
||||
$key2 = $_COOKIE['rx_sesskey2'];
|
||||
}
|
||||
|
||||
// Fetch and validate the autologin key.
|
||||
if (isset($_COOKIE['rx_autologin']) && ctype_alnum($_COOKIE['rx_autologin']) && strlen($_COOKIE['rx_autologin']) === 48)
|
||||
{
|
||||
$key3 = $_COOKIE['rx_autologin'];
|
||||
}
|
||||
|
||||
return array($key1, $key1 === null ? null : $key2, $key3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set session keys.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function _setKeys()
|
||||
{
|
||||
// Get session parameters.
|
||||
list($lifetime, $refresh_interval, $domain, $path) = self::_getParams();
|
||||
$lifetime = $lifetime ? ($lifetime + time()) : 0;
|
||||
|
||||
// Set or destroy the HTTP-only key.
|
||||
if (isset($_SESSION['RHYMIX']['keys'][$domain]['key1']))
|
||||
{
|
||||
setcookie('rx_sesskey1', $_SESSION['RHYMIX']['keys'][$domain]['key1'], $lifetime, $path, $domain, false, true);
|
||||
$_COOKIE['rx_sesskey1'] = $_SESSION['RHYMIX']['keys'][$domain]['key1'];
|
||||
}
|
||||
else
|
||||
{
|
||||
setcookie('rx_sesskey1', 'deleted', time() - 86400, $path, $domain, false, true);
|
||||
unset($_COOKIE['rx_sesskey1']);
|
||||
}
|
||||
|
||||
// Set or delete the HTTPS-only key.
|
||||
if (\RX_SSL && isset($_SESSION['RHYMIX']['keys'][$domain]['key2']))
|
||||
{
|
||||
setcookie('rx_sesskey2', $_SESSION['RHYMIX']['keys'][$domain]['key2'], $lifetime, $path, $domain, true, true);
|
||||
$_COOKIE['rx_sesskey2'] = $_SESSION['RHYMIX']['keys'][$domain]['key2'];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set autologin key.
|
||||
*
|
||||
* @param string $autologin_key
|
||||
* @param string $security_key
|
||||
* @return bool
|
||||
*/
|
||||
public static function setAutologinKeys($autologin_key, $security_key)
|
||||
{
|
||||
// Get session parameters.
|
||||
list($lifetime, $refresh_interval, $domain, $path) = self::_getParams();
|
||||
$lifetime = time() + (86400 * 365);
|
||||
|
||||
// Set or destroy the HTTP-only key.
|
||||
if ($autologin_key && $security_key)
|
||||
{
|
||||
setcookie('rx_autologin', $autologin_key . $security_key, $lifetime, $path, $domain, false, true);
|
||||
$_COOKIE['rx_autologin'] = $autologin_key . $security_key;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy autologin keys.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function destroyAutologinKeys()
|
||||
{
|
||||
if (self::$_autologin_key)
|
||||
{
|
||||
executeQuery('member.deleteAutologin', (object)array('autologin_key' => substr(self::$_autologin_key, 0, 24)));
|
||||
self::$_autologin_key = false;
|
||||
$result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$result = false;
|
||||
}
|
||||
|
||||
setcookie('rx_autologin', 'deleted', time() - 86400, $path, $domain, false, true);
|
||||
unset($_COOKIE['rx_autologin']);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy all other autologin keys (except the current session).
|
||||
*
|
||||
* @param int $member_srl
|
||||
* @return bool
|
||||
*/
|
||||
public static function destroyOtherSessions($member_srl)
|
||||
{
|
||||
// Check the validity of member_srl.
|
||||
$member_srl = intval($member_srl);
|
||||
if (!$member_srl)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Invalidate all sessions that were logged in before the current timestamp.
|
||||
if (self::isStarted())
|
||||
{
|
||||
$invalid_before = time();
|
||||
$filename = \RX_BASEDIR . sprintf('files/member_extra_info/invalid_before/%s%d.txt', getNumberingPath($member_srl), $member_srl);
|
||||
Storage::write($filename, $invalid_before);
|
||||
Cache::set(sprintf('session:invalid_before:%d', $member_srl), $invalid_before);
|
||||
$_SESSION['RHYMIX']['last_login'] = $invalid_before;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Destroy all other autologin keys.
|
||||
if (self::$_autologin_key)
|
||||
{
|
||||
executeQuery('member.deleteAutologin', (object)array('member_srl' => $member_srl, 'not_autologin_key' => substr(self::$_autologin_key, 0, 24)));
|
||||
}
|
||||
else
|
||||
{
|
||||
executeQuery('member.deleteAutologin', (object)array('member_srl' => $member_srl));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -67,10 +67,12 @@ $lang->msg_blacklisted_addon = 'This addon has been disabled because it conflict
|
|||
$lang->msg_blacklisted_widget = 'This widget has been disabled because it conflicts with a feature that Rhymix supports by default, or is known to have other compatibility problems.';
|
||||
$lang->msg_blacklisted_layout = 'This layout has been disabled because it conflicts with a feature that Rhymix supports by default, or is known to have other compatibility problems.';
|
||||
$lang->msg_blacklisted_reason['autolang'] = 'Similar functionality can be configured in the <a href="./index.php?module=admin&act=dispAdminConfigGeneral">System Settings</a> page.';
|
||||
$lang->msg_blacklisted_reason['auto_login'] = 'The functionality that this module used to provide is included by default in Rhymix.';
|
||||
$lang->msg_blacklisted_reason['errorlogger'] = 'Similar functionality can be configured in the <a href="./index.php?module=admin&act=dispAdminConfigDebug">Debug Settings</a> page.';
|
||||
$lang->msg_blacklisted_reason['fix_mysql_utf8'] = 'The functionality that this addon used to provide is included by default in Rhymix.';
|
||||
$lang->msg_blacklisted_reason['member_communication'] = 'The functionality that this addon used to provide has been moved to the member and ncenterlite modules.';
|
||||
$lang->msg_blacklisted_reason['seo'] = 'Similar functionality can be configured in the <a href="./index.php?module=admin&act=dispAdminConfigSEO">SEO Settings</a> page.';
|
||||
$lang->msg_blacklisted_reason['session_shield'] = 'The functionality that this addon used to provide is included by default in Rhymix.';
|
||||
$lang->msg_blacklisted_reason['smartphone'] = 'This module was disabled in XE long before Rhymix even existed.';
|
||||
$lang->msg_blacklisted_reason['zipperupper'] = 'Similar functionality can be configured in the <a href="./index.php?module=admin&act=dispAdminConfigAdvanced">Advanced Settings</a> page.';
|
||||
$lang->msg_warning = 'Warning';
|
||||
|
|
|
|||
|
|
@ -67,10 +67,12 @@ $lang->msg_blacklisted_addon = '이 애드온은 Rhymix에서 기본 제공하
|
|||
$lang->msg_blacklisted_widget = '이 위젯은 Rhymix에서 기본 제공하는 기능과 충돌하거나 그 밖의 호환성 문제가 있으므로 사용이 중단되었습니다.';
|
||||
$lang->msg_blacklisted_layout = '이 레이아웃은 Rhymix에서 기본 제공하는 기능과 충돌하거나 그 밖의 호환성 문제가 있으므로 사용이 중단되었습니다.';
|
||||
$lang->msg_blacklisted_reason['autolang'] = '이 애드온에서 제공하던 기능은 <a href="./index.php?module=admin&act=dispAdminConfigGeneral">시스템 설정</a> 페이지에서 관리할 수 있습니다.';
|
||||
$lang->msg_blacklisted_reason['auto_login'] = '이 모듈에서 제공하던 기능은 Rhymix에 포함되어 있습니다.';
|
||||
$lang->msg_blacklisted_reason['errorlogger'] = '이 모듈에서 제공하던 기능은 <a href="./index.php?module=admin&act=dispAdminConfigDebug">디버그 설정</a> 페이지에서 관리할 수 있습니다.';
|
||||
$lang->msg_blacklisted_reason['fix_mysql_utf8'] = '이 애드온에서 제공하던 기능은 Rhymix에 포함되어 있습니다.';
|
||||
$lang->msg_blacklisted_reason['member_communication'] = '이 애드온에서 제공하던 기능은 알림센터 모듈에서 관리할 수 있습니다.';
|
||||
$lang->msg_blacklisted_reason['seo'] = '이 모듈에서 제공하던 기능은 <a href="./index.php?module=admin&act=dispAdminConfigSEO">SEO 설정</a> 페이지에서 관리할 수 있습니다.';
|
||||
$lang->msg_blacklisted_reason['session_shield'] = '이 애드온에서 제공하던 기능은 Rhymix에 포함되어 있습니다.';
|
||||
$lang->msg_blacklisted_reason['smartphone'] = '이 모듈은 XE에서도 사용되지 않고 있었습니다.';
|
||||
$lang->msg_blacklisted_reason['zipperupper'] = '이 애드온에서 제공하던 기능은 <a href="./index.php?module=admin&act=dispAdminConfigAdvanced">고급 설정</a> 페이지에서 관리할 수 있습니다.';
|
||||
$lang->msg_warning = '경고';
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
<action name="dispMemberOwnDocument" type="view" standalone="true" />
|
||||
<action name="dispMemberScrappedDocument" type="view" standalone="true" />
|
||||
<action name="dispMemberSavedDocument" type="view" standalone="true" />
|
||||
<action name="dispMemberActiveLogins" type="view" standalone="true" />
|
||||
<action name="dispMemberFindAccount" type="view" standalone="true" />
|
||||
<action name="dispMemberGetTempPassword" type="view" standalone="true" />
|
||||
<action name="dispMemberResendAuthMail" type="view" standalone="true" />
|
||||
|
|
@ -62,6 +63,7 @@
|
|||
<action name="procMemberDeleteScrap" type="controller" standalone="true" />
|
||||
<action name="procMemberSaveDocument" type="controller" standalone="true" />
|
||||
<action name="procMemberDeleteSavedDocument" type="controller" standalone="true" />
|
||||
<action name="procMemberDeleteAutologin" type="controller" standalone="true" />
|
||||
|
||||
<action name="procMemberFindAccount" type="controller" method="GET|POST" ruleset="findAccount" standalone="true" />
|
||||
<action name="procMemberFindAccountByQuestion" type="controller" method="GET|POST" standalone="true" />
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ $lang->cmd_manage_email_host = 'E-mail provider check';
|
|||
$lang->cmd_manage_nick_name = 'Prohibited NickNames';
|
||||
$lang->cmd_manage_form = 'Signup Form';
|
||||
$lang->cmd_view_own_document = 'Written Articles';
|
||||
$lang->cmd_view_active_logins = 'Active Logins';
|
||||
$lang->cmd_manage_member_info = 'Manage Member Info';
|
||||
$lang->cmd_trace_document = 'Trace Written Articles';
|
||||
$lang->cmd_trace_comment = 'Trace Written Comments';
|
||||
|
|
@ -160,6 +161,7 @@ $lang->cmd_config_password_strength = 'password strength';
|
|||
$lang->cmd_password_hashing_algorithm = 'Password Hashing Algorithm';
|
||||
$lang->cmd_password_hashing_work_factor = 'Password Hashing Work Factor';
|
||||
$lang->cmd_password_hashing_auto_upgrade = 'Auto-upgrade Hashing Algorithm';
|
||||
$lang->cmd_password_change_invalidate_other_sessions = 'Log out other devices on password change';
|
||||
$lang->password_strength_low = 'low';
|
||||
$lang->password_strength_normal = 'normal';
|
||||
$lang->password_strength_high = 'high';
|
||||
|
|
@ -167,6 +169,7 @@ $lang->about_password_strength_config = 'When members register or change the pas
|
|||
$lang->about_password_hashing_algorithm = 'You can choose how to encrypt (hash) members\' passwords stored in the database.';
|
||||
$lang->about_password_hashing_work_factor = 'Higher work factors are more secure, but logins may take a long time. This only applies to bcrypt and pbkdf2.';
|
||||
$lang->about_password_hashing_auto_upgrade = 'Passwords encrypted using different algorithms will be automatically converted to the configured algorithm at next login.';
|
||||
$lang->about_password_change_invalidate_other_sessions = 'Log out all other devices (browsers) when a member changes the password.';
|
||||
$lang->about_password_strength['low'] = 'the password must be at least 4';
|
||||
$lang->about_password_strength['normal'] = 'the password must be at least 6, and must have at least one alpha character and numeric characters';
|
||||
$lang->about_password_strength['high'] = 'the password must be at least 8, and must have at least one alpha character, numeric character and special character ';
|
||||
|
|
@ -297,3 +300,6 @@ $lang->spammer_description = '<p>Spam user management. This function denied user
|
|||
$lang->btn_spammer_delete_all = 'Delete all';
|
||||
$lang->spammer_move_to_trash = 'Move to trash';
|
||||
$lang->msg_spammer_complete = 'Completed.';
|
||||
$lang->cmd_login_browser_info = 'Browser Information';
|
||||
$lang->cmd_initial_login = 'First Login';
|
||||
$lang->cmd_recent_visit = 'Recent Visit';
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ $lang->cmd_manage_email_host = '이메일 제공자 관리';
|
|||
$lang->cmd_manage_nick_name = '금지 닉네임 관리';
|
||||
$lang->cmd_manage_form = '가입 폼 관리';
|
||||
$lang->cmd_view_own_document = '작성 글 보기';
|
||||
$lang->cmd_view_active_logins = '로그인 관리';
|
||||
$lang->cmd_manage_member_info = '회원 정보 관리';
|
||||
$lang->cmd_trace_document = '작성글 추적';
|
||||
$lang->cmd_trace_comment = '작성 댓글 추적';
|
||||
|
|
@ -169,6 +170,7 @@ $lang->cmd_config_password_strength = '비밀번호 보안수준';
|
|||
$lang->cmd_password_hashing_algorithm = '비밀번호 암호화 알고리듬';
|
||||
$lang->cmd_password_hashing_work_factor = '비밀번호 암호화 소요시간';
|
||||
$lang->cmd_password_hashing_auto_upgrade = '알고리듬 자동 업그레이드';
|
||||
$lang->cmd_password_change_invalidate_other_sessions = '비번 변경시 다른 기기 로그아웃';
|
||||
$lang->password_strength_low = '낮음';
|
||||
$lang->password_strength_normal = '보통';
|
||||
$lang->password_strength_high = '높음';
|
||||
|
|
@ -176,6 +178,7 @@ $lang->about_password_strength_config = '회원들이 비밀번호를 등록/변
|
|||
$lang->about_password_hashing_algorithm = '회원들의 비밀번호를 DB에 저장할 때 암호화(해싱)하는 방식을 지정할 수 있습니다.';
|
||||
$lang->about_password_hashing_work_factor = '시간이 오래 걸리는 알고리듬일수록 보안이 강하지만, 로그인이 오래 걸릴 수 있습니다. bcrypt 및 pbkdf2 알고리듬에만 적용됩니다.';
|
||||
$lang->about_password_hashing_auto_upgrade = '설정된 알고리듬과 다른 방법으로 암호화된 비밀번호가 있으면 다음 로그인시 설정된 알고리듬으로 자동 변환합니다.';
|
||||
$lang->about_password_change_invalidate_other_sessions = '비밀번호를 변경하면 현재 기기(브라우저)를 제외한 모든 로그인이 풀리도록 합니다.';
|
||||
$lang->about_password_strength['low'] = '비밀번호는 4자 이상이어야 합니다.';
|
||||
$lang->about_password_strength['normal'] = '비밀번호는 6자리 이상이어야 하며 영문과 숫자를 반드시 포함해야 합니다.';
|
||||
$lang->about_password_strength['high'] = '비밀번호는 8자리 이상이어야 하며 영문과 숫자, 특수문자를 반드시 포함해야 합니다.';
|
||||
|
|
@ -317,3 +320,6 @@ $lang->spammer_move_to_trash = '휴지통으로 이동';
|
|||
$lang->msg_spammer_complete = '완료되었습니다.';
|
||||
$lang->nick_name_before_changing = '닉네임 변경 전';
|
||||
$lang->nick_name_after_changing = '닉네임 변경 후';
|
||||
$lang->cmd_login_browser_info = '브라우저 정보';
|
||||
$lang->cmd_initial_login = '최초 로그인';
|
||||
$lang->cmd_recent_visit = '최근 방문';
|
||||
|
|
|
|||
|
|
@ -171,6 +171,7 @@ class memberAdminController extends member
|
|||
'password_hashing_algorithm',
|
||||
'password_hashing_work_factor',
|
||||
'password_hashing_auto_upgrade',
|
||||
'password_change_invalidate_other_sessions',
|
||||
'update_nickname_log',
|
||||
'member_allow_fileupload'
|
||||
);
|
||||
|
|
|
|||
|
|
@ -204,6 +204,9 @@ class member extends ModuleObject {
|
|||
|
||||
if(!$oDB->isColumnExists("member", "list_order")) return true;
|
||||
if(!$oDB->isIndexExists("member","idx_list_order")) return true;
|
||||
|
||||
// Check autologin table
|
||||
if(!$oDB->isColumnExists("member_autologin", "security_key")) return true;
|
||||
|
||||
$oModuleModel = getModel('module');
|
||||
$config = $oModuleModel->getModuleConfig('member');
|
||||
|
|
@ -314,6 +317,13 @@ class member extends ModuleObject {
|
|||
{
|
||||
$oDB->addIndex("member","idx_list_order", array("list_order"));
|
||||
}
|
||||
|
||||
// Check autologin table
|
||||
if(!$oDB->isColumnExists("member_autologin", "security_key"))
|
||||
{
|
||||
$oDB->dropTable('member_autologin');
|
||||
$oDB->createTableByXmlFile($this->module_path . '/schemas/member_autologin.xml');
|
||||
}
|
||||
|
||||
$oModuleModel = getModel('module');
|
||||
$config = $oModuleModel->getModuleConfig('member');
|
||||
|
|
|
|||
|
|
@ -101,7 +101,9 @@ class memberController extends member
|
|||
if(!$trigger_output->toBool()) return $trigger_output;
|
||||
|
||||
// Destroy session information
|
||||
Rhymix\Framework\Session::logout();
|
||||
$this->destroySessionInfo();
|
||||
$this->_clearMemberCache($logged_info->member_srl);
|
||||
|
||||
// Call a trigger after log-out (after)
|
||||
ModuleHandler::triggerCall('member.doLogout', 'after', $logged_info);
|
||||
|
|
@ -111,9 +113,9 @@ class memberController extends member
|
|||
$oModuleModel = getModel('module');
|
||||
$config = $oModuleModel->getModuleConfig('member');
|
||||
if($config->after_logout_url)
|
||||
{
|
||||
$output->redirect_url = $config->after_logout_url;
|
||||
|
||||
$this->_clearMemberCache($logged_info->member_srl);
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
|
@ -202,6 +204,52 @@ class memberController extends member
|
|||
$oDocumentController = getController('document');
|
||||
$oDocumentController->deleteDocument($document_srl, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an autologin
|
||||
*/
|
||||
function procMemberDeleteAutologin()
|
||||
{
|
||||
// Check login information
|
||||
if(!Context::get('is_logged')) return new Object(-1, 'msg_not_logged');
|
||||
$logged_info = Context::get('logged_info');
|
||||
|
||||
$autologin_id = intval(Context::get('autologin_id'));
|
||||
$autologin_key = Context::get('autologin_key');
|
||||
if (!$autologin_id || !$autologin_key)
|
||||
{
|
||||
return new Object(-1, 'msg_invalid_request');
|
||||
}
|
||||
|
||||
$args = new stdClass;
|
||||
$args->autologin_id = $autologin_id;
|
||||
$args->autologin_key = $autologin_key;
|
||||
$output = executeQueryArray('member.getAutologin', $args);
|
||||
if ($output->toBool() && $output->data)
|
||||
{
|
||||
$autologin_info = array_first($output->data);
|
||||
if ($autologin_info->member_srl == $logged_info->member_srl)
|
||||
{
|
||||
$output = executeQuery('member.deleteAutologin', $args);
|
||||
if ($output->toBool())
|
||||
{
|
||||
$this->add('deleted', 'Y');
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->add('deleted', 'N');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->add('deleted', 'N');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->add('deleted', 'N');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check values when member joining
|
||||
|
|
@ -687,6 +735,14 @@ class memberController extends member
|
|||
$args->password = $password;
|
||||
$output = $this->updateMemberPassword($args);
|
||||
if(!$output->toBool()) return $output;
|
||||
|
||||
// Log out all other sessions.
|
||||
$oModuleModel = getModel('module');
|
||||
$member_config = $oModuleModel->getModuleConfig('member');
|
||||
if ($member_config->password_change_invalidate_other_sessions === 'Y')
|
||||
{
|
||||
Rhymix\Framework\Session::destroyOtherSessions($member_srl);
|
||||
}
|
||||
|
||||
$this->add('member_srl', $args->member_srl);
|
||||
$this->setMessage('success_updated');
|
||||
|
|
@ -723,7 +779,8 @@ class memberController extends member
|
|||
$output = $this->deleteMember($member_srl);
|
||||
if(!$output->toBool()) return $output;
|
||||
// Destroy all session information
|
||||
$this->destroySessionInfo();
|
||||
executeQuery('member.deleteAutologin', (object)array('member_srl' => $member_srl));
|
||||
Rhymix\Framework\Session::logout();
|
||||
// Return success message
|
||||
$this->setMessage('success_leaved');
|
||||
|
||||
|
|
@ -1621,82 +1678,56 @@ class memberController extends member
|
|||
/**
|
||||
* Auto-login
|
||||
*
|
||||
* @return void
|
||||
* @param string $autologin_key
|
||||
* @return int|false
|
||||
*/
|
||||
function doAutologin()
|
||||
function doAutologin($autologin_key = null)
|
||||
{
|
||||
// Get a key value of auto log-in
|
||||
$args = new stdClass;
|
||||
$args->autologin_key = $_COOKIE['xeak'];
|
||||
// Get information of the key
|
||||
$output = executeQuery('member.getAutologin', $args);
|
||||
// If no information exists, delete a cookie
|
||||
if(!$output->toBool() || !$output->data)
|
||||
// Validate the key.
|
||||
if (strlen($autologin_key) == 48)
|
||||
{
|
||||
setCookie('xeak',null,$_SERVER['REQUEST_TIME']+60*60*24*365, '/');
|
||||
return;
|
||||
}
|
||||
|
||||
$oMemberModel = getModel('member');
|
||||
$config = $oMemberModel->getMemberConfig();
|
||||
|
||||
$user_id = ($config->identifier == 'user_id') ? $output->data->user_id : $output->data->email_address;
|
||||
$password = $output->data->password;
|
||||
|
||||
if(!$user_id || !$password)
|
||||
{
|
||||
setCookie('xeak',null,$_SERVER['REQUEST_TIME']+60*60*24*365, '/');
|
||||
return;
|
||||
}
|
||||
|
||||
$do_auto_login = false;
|
||||
|
||||
// Compare key values based on the information
|
||||
$check_key = strtolower($user_id).$password.$_SERVER['HTTP_USER_AGENT'];
|
||||
$check_key = substr(hash_hmac('sha256', $check_key, substr($args->autologin_key, 0, 32)), 0, 32);
|
||||
|
||||
if($check_key === substr($args->autologin_key, 32))
|
||||
{
|
||||
// Check change_password_date
|
||||
$oModuleModel = getModel('module');
|
||||
$member_config = $oModuleModel->getModuleConfig('member');
|
||||
$limit_date = $member_config->change_password_date;
|
||||
|
||||
// Check if change_password_date is set
|
||||
if($limit_date > 0)
|
||||
{
|
||||
$oMemberModel = getModel('member');
|
||||
$columnList = array('member_srl', 'change_password_date');
|
||||
|
||||
if($config->identifier == 'user_id')
|
||||
{
|
||||
$member_info = $oMemberModel->getMemberInfoByUserID($user_id, $columnList);
|
||||
}
|
||||
else
|
||||
{
|
||||
$member_info = $oMemberModel->getMemberInfoByEmailAddress($user_id, $columnList);
|
||||
}
|
||||
|
||||
if($member_info->change_password_date >= date('YmdHis', strtotime('-'.$limit_date.' day')) ){
|
||||
$do_auto_login = true;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
$do_auto_login = true;
|
||||
}
|
||||
}
|
||||
|
||||
if($do_auto_login)
|
||||
{
|
||||
$output = $this->doLogin($user_id);
|
||||
$security_key = substr($autologin_key, 24, 24);
|
||||
$autologin_key = substr($autologin_key, 0, 24);
|
||||
}
|
||||
else
|
||||
{
|
||||
executeQuery('member.deleteAutologin', $args);
|
||||
setCookie('xeak',null,$_SERVER['REQUEST_TIME']+60*60*24*365, '/');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fetch autologin information from DB.
|
||||
$args = new stdClass;
|
||||
$args->autologin_key = $autologin_key;
|
||||
$output = executeQuery('member.getAutologin', $args);
|
||||
if (!$output->toBool() || !$output->data)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (is_array($output->data))
|
||||
{
|
||||
$output->data = array_first($output->data);
|
||||
}
|
||||
|
||||
// Check the security key.
|
||||
if ($output->data->security_key !== $security_key || !$output->data->member_srl)
|
||||
{
|
||||
$args = new stdClass;
|
||||
$args->autologin_key = $autologin_key;
|
||||
executeQuery('member.deleteAutologin', $args);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update the security key.
|
||||
$new_security_key = Rhymix\Framework\Security::getRandom(24, 'alnum');
|
||||
$args = new stdClass;
|
||||
$args->security_key = $new_security_key;
|
||||
$update_output = executeQuery('member.updateAutologin', $args);
|
||||
if ($update_output->toBool())
|
||||
{
|
||||
Rhymix\Framework\Session::setAutologinKeys($autologin_key, $new_security_key);
|
||||
}
|
||||
|
||||
// Return the member_srl.
|
||||
return intval($output->data->member_srl);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1858,19 +1889,21 @@ class memberController extends member
|
|||
// When user checked to use auto-login
|
||||
if($keep_signed)
|
||||
{
|
||||
// Key generate for auto login
|
||||
$random_key = Rhymix\Framework\Security::getRandom(32, 'hex');
|
||||
$extra_key = strtolower($user_id).$this->memberInfo->password.$_SERVER['HTTP_USER_AGENT'];
|
||||
$extra_key = substr(hash_hmac('sha256', $extra_key, $random_key), 0, 32);
|
||||
$random_key = Rhymix\Framework\Security::getRandom(48, 'alnum');
|
||||
$autologin_args = new stdClass;
|
||||
$autologin_args->autologin_key = $random_key.$extra_key;
|
||||
$autologin_args->autologin_key = substr($random_key, 0, 24);
|
||||
$autologin_args->security_key = substr($random_key, 24, 24);
|
||||
$autologin_args->member_srl = $this->memberInfo->member_srl;
|
||||
executeQuery('member.deleteAutologin', $autologin_args);
|
||||
$autologin_args->user_agent = json_encode(Rhymix\Framework\UA::getBrowserInfo());
|
||||
$autologin_output = executeQuery('member.insertAutologin', $autologin_args);
|
||||
if($autologin_output->toBool()) setCookie('xeak',$autologin_args->autologin_key, $_SERVER['REQUEST_TIME']+31536000, '/');
|
||||
if ($autologin_output->toBool())
|
||||
{
|
||||
Rhymix\Framework\Session::setAutologinKeys(substr($random_key, 0, 24), substr($random_key, 24, 24));
|
||||
}
|
||||
}
|
||||
|
||||
$this->setSessionInfo();
|
||||
Rhymix\Framework\Session::login($this->memberInfo->member_srl);
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
|
@ -1881,29 +1914,23 @@ class memberController extends member
|
|||
{
|
||||
$oMemberModel = getModel('member');
|
||||
$config = $oMemberModel->getMemberConfig();
|
||||
|
||||
// If your information came through the current session information to extract information from the users
|
||||
if(!$this->memberInfo && $_SESSION['member_srl'] && $oMemberModel->isLogged() )
|
||||
if(!$this->memberInfo && Rhymix\Framework\Session::getMemberSrl())
|
||||
{
|
||||
$this->memberInfo = $oMemberModel->getMemberInfoByMemberSrl($_SESSION['member_srl']);
|
||||
// If you do not destroy the session Profile
|
||||
if($this->memberInfo->member_srl != $_SESSION['member_srl'])
|
||||
{
|
||||
$this->destroySessionInfo();
|
||||
return;
|
||||
}
|
||||
$this->memberInfo = Rhymix\Framework\Session::getMemberInfo();
|
||||
}
|
||||
// Stop using the session id is destroyed
|
||||
if($this->memberInfo->denied=='Y')
|
||||
if(!$this->memberInfo->member_srl)
|
||||
{
|
||||
$this->destroySessionInfo();
|
||||
return;
|
||||
}
|
||||
|
||||
// Log in for treatment sessions set
|
||||
/*
|
||||
$_SESSION['is_logged'] = true;
|
||||
$_SESSION['ipaddress'] = $_SERVER['REMOTE_ADDR'];
|
||||
$_SESSION['member_srl'] = $this->memberInfo->member_srl;
|
||||
$_SESSION['member_srl'] = $_SESSION['RHYMIX']['login'] = $this->memberInfo->member_srl;
|
||||
$_SESSION['is_admin'] = '';
|
||||
setcookie('xe_logged', 'true', 0, '/');
|
||||
*/
|
||||
// Do not save your password in the session jiwojum;;
|
||||
//unset($this->memberInfo->password);
|
||||
// User Group Settings
|
||||
|
|
@ -1927,6 +1954,7 @@ class memberController extends member
|
|||
$this->addMemberMenu( 'dispMemberScrappedDocument', 'cmd_view_scrapped_document');
|
||||
$this->addMemberMenu( 'dispMemberSavedDocument', 'cmd_view_saved_document');
|
||||
$this->addMemberMenu( 'dispMemberOwnDocument', 'cmd_view_own_document');
|
||||
$this->addMemberMenu( 'dispMemberActiveLogins', 'cmd_view_active_logins');
|
||||
if($config->update_nickname_log == 'Y')
|
||||
{
|
||||
$this->addMemberMenu( 'dispMemberModifyNicknameLog', 'cmd_modify_nickname_log');
|
||||
|
|
@ -2618,19 +2646,11 @@ class memberController extends member
|
|||
$_SESSION[$key] = '';
|
||||
}
|
||||
|
||||
session_destroy();
|
||||
Rhymix\Framework\Session::destroy();
|
||||
setcookie(session_name(), '', $_SERVER['REQUEST_TIME']-42000, '/');
|
||||
setcookie('sso','',$_SERVER['REQUEST_TIME']-42000, '/');
|
||||
setcookie('xeak','',$_SERVER['REQUEST_TIME']-42000, '/');
|
||||
setcookie('xe_logged', 'false', $_SERVER['REQUEST_TIME'] - 42000, '/');
|
||||
|
||||
if($memberSrl || $_COOKIE['xeak'])
|
||||
{
|
||||
$args = new stdClass();
|
||||
$args->member_srl = $memberSrl;
|
||||
$args->autologin_key = $_COOKIE['xeak'];
|
||||
$output = executeQuery('member.deleteAutologin', $args);
|
||||
}
|
||||
}
|
||||
|
||||
function _updatePointByGroup($memberSrl, $groupSrlList)
|
||||
|
|
|
|||
|
|
@ -231,36 +231,9 @@ class memberModel extends member
|
|||
/**
|
||||
* @brief Check if logged-in
|
||||
*/
|
||||
function isLogged() {
|
||||
if($_SESSION['is_logged'])
|
||||
{
|
||||
if(Mobile::isFromMobilePhone())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
elseif(filter_var($_SESSION['ipaddress'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6))
|
||||
{
|
||||
// IPv6: require same /48
|
||||
if(strncmp(inet_pton($_SESSION['ipaddress']), inet_pton($_SERVER['REMOTE_ADDR']), 6) == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// IPv4: require same /24
|
||||
if(ip2long($_SESSION['ipaddress']) >> 8 == ip2long($_SERVER['REMOTE_ADDR']) >> 8)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(Context::getSessionStatus())
|
||||
{
|
||||
$_SESSION['is_logged'] = false;
|
||||
}
|
||||
return false;
|
||||
function isLogged()
|
||||
{
|
||||
return Rhymix\Framework\Session::getMemberSrl() ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -268,39 +241,7 @@ class memberModel extends member
|
|||
*/
|
||||
function getLoggedInfo()
|
||||
{
|
||||
// Return session info if session info is requested and the user is logged-in
|
||||
if($this->isLogged())
|
||||
{
|
||||
$logged_info = Context::get('logged_info');
|
||||
// Admin/Group list defined depending on site_module_info
|
||||
$site_module_info = Context::get('site_module_info');
|
||||
if($site_module_info->site_srl)
|
||||
{
|
||||
$logged_info->group_list = $this->getMemberGroups($logged_info->member_srl, $site_module_info->site_srl);
|
||||
// Add is_site_admin bool variable into logged_info if site_administrator is
|
||||
$oModuleModel = getModel('module');
|
||||
if($oModuleModel->isSiteAdmin($logged_info)) $logged_info->is_site_admin = true;
|
||||
else $logged_info->is_site_admin = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Register a default group if the site doesn't have a member group
|
||||
if(count($logged_info->group_list) === 0)
|
||||
{
|
||||
$default_group = $this->getDefaultGroup(0);
|
||||
$oMemberController = getController('member');
|
||||
$oMemberController->addMemberToGroup($logged_info->member_srl, $default_group->group_srl, 0);
|
||||
$groups[$default_group->group_srl] = $default_group->title;
|
||||
$logged_info->group_list = $groups;
|
||||
}
|
||||
|
||||
$logged_info->is_site_admin = false;
|
||||
}
|
||||
Context::set('logged_info', $logged_info);
|
||||
|
||||
return $logged_info;
|
||||
}
|
||||
return new stdClass;
|
||||
return Context::get('logged_info');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -398,6 +339,7 @@ class memberModel extends member
|
|||
}
|
||||
$info->signature = $this->getSignature($info->member_srl);
|
||||
$info->group_list = $this->getMemberGroups($info->member_srl, $site_srl);
|
||||
$info->is_site_admin = $oModuleModel->isSiteAdmin($info) ? true : false;
|
||||
|
||||
$extra_vars = unserialize($info->extra_vars);
|
||||
unset($info->extra_vars);
|
||||
|
|
@ -493,8 +435,7 @@ class memberModel extends member
|
|||
*/
|
||||
function getLoggedMemberSrl()
|
||||
{
|
||||
if(!$this->isLogged()) return;
|
||||
return $_SESSION['member_srl'];
|
||||
return Rhymix\Framework\Session::getMemberSrl();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -527,6 +468,12 @@ class memberModel extends member
|
|||
$args->site_srl = $site_srl;
|
||||
$output = executeQueryArray('member.getMemberGroups', $args);
|
||||
$group_list = $output->data;
|
||||
if (!count($group_list))
|
||||
{
|
||||
$default_group = $this->getDefaultGroup($site_srl);
|
||||
getController('member')->addMemberToGroup($member_srl, $default_group->group_srl, $site_srl);
|
||||
$group_list[$default_group->group_srl] = $default_group->title;
|
||||
}
|
||||
//insert in cache
|
||||
Rhymix\Framework\Cache::set($cache_key, $group_list, 0, true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -430,6 +430,30 @@ class memberView extends member
|
|||
$this->setTemplateFile('saved_list');
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Display the login management page
|
||||
*/
|
||||
function dispMemberActiveLogins()
|
||||
{
|
||||
$logged_info = Context::get('logged_info');
|
||||
if (!$logged_info->member_srl)
|
||||
{
|
||||
return $this->stop('msg_not_logged');
|
||||
}
|
||||
|
||||
$args = new stdClass();
|
||||
$args->member_srl = $logged_info->member_srl;
|
||||
$args->page = (int)Context::get('page');
|
||||
$output = executeQueryArray('member.getAutologin', $args);
|
||||
Context::set('total_count', $output->total_count);
|
||||
Context::set('total_page', $output->total_page);
|
||||
Context::set('page', $output->page);
|
||||
Context::set('active_logins', $output->data);
|
||||
Context::set('page_navigation', $output->page_navigation);
|
||||
|
||||
$this->setTemplateFile('active_logins');
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Display the login form
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
<table name="member_autologin" />
|
||||
</tables>
|
||||
<conditions>
|
||||
<condition operation="equal" column="autologin_key" var="autologin_key" pipe="or" default='' />
|
||||
<condition operation="equal" column="member_srl" var="member_srl" pipe="or" />
|
||||
<condition operation="equal" column="autologin_key" var="autologin_key" />
|
||||
<condition operation="notequal" column="autologin_key" var="not_autologin_key" pipe="and" />
|
||||
<condition operation="equal" column="member_srl" var="member_srl" pipe="and" />
|
||||
</conditions>
|
||||
</query>
|
||||
|
|
|
|||
|
|
@ -4,13 +4,21 @@
|
|||
<table name="member_autologin" alias="member_autologin" />
|
||||
</tables>
|
||||
<columns>
|
||||
<column name="member_autologin.*" />
|
||||
<column name="member.email_address" alias="email_address" />
|
||||
<column name="member.user_id" alias="user_id" />
|
||||
<column name="member.password" alias="password" />
|
||||
<column name="member_autologin.autologin_key" alias="autologin_key" />
|
||||
</columns>
|
||||
<conditions>
|
||||
<condition operation="equal" column="member_autologin.autologin_key" var="autologin_key" notnull="notnull" />
|
||||
<condition operation="equal" column="member.member_srl" var="member_autologin.member_srl" notnull="notnull" pipe="and" />
|
||||
<condition operation="equal" column="member.member_srl" var="member_autologin.member_srl" />
|
||||
<condition operation="equal" column="member_autologin.id" var="autologin_id" pipe="and" />
|
||||
<condition operation="equal" column="member_autologin.autologin_key" var="autologin_key" pipe="and" />
|
||||
<condition operation="equal" column="member_autologin.member_srl" var="member_srl" pipe="and" />
|
||||
</conditions>
|
||||
<navigation>
|
||||
<index var="sort_index" default="member_autologin.id" order="asc" />
|
||||
<list_count var="list_count" default="20" />
|
||||
<page_count var="page_count" default="10" />
|
||||
<page var="page" default="1" />
|
||||
</navigation>
|
||||
</query>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,15 @@
|
|||
<query id="insertAutologin" action="insert">
|
||||
<tables>
|
||||
<table name="member_autologin" />
|
||||
</tables>
|
||||
<columns>
|
||||
<column name="autologin_key" var="autologin_key" notnull="notnull" minlength="1" maxlength="60" />
|
||||
<column name="member_srl" var="member_srl" filter="number" notnull="notnull" />
|
||||
</columns>
|
||||
<tables>
|
||||
<table name="member_autologin" />
|
||||
</tables>
|
||||
<columns>
|
||||
<column name="autologin_key" var="autologin_key" notnull="notnull" minlength="1" maxlength="80" />
|
||||
<column name="security_key" var="security_key" notnull="notnull" minlength="1" maxlength="80" />
|
||||
<column name="member_srl" var="member_srl" notnull="notnull" filter="number" />
|
||||
<column name="regdate" var="regdate" default="curdate()" />
|
||||
<column name="ipaddress" var="ipaddress" default="ipaddress()" />
|
||||
<column name="last_visit" var="last_visit" default="curdate()" />
|
||||
<column name="last_ipaddress" var="last_ipaddress" default="ipaddress()" />
|
||||
<column name="user_agent" var="user_agent" />
|
||||
</columns>
|
||||
</query>
|
||||
|
|
|
|||
12
modules/member/queries/updateAutologin.xml
Normal file
12
modules/member/queries/updateAutologin.xml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<query id="updateAutologin" action="update">
|
||||
<tables>
|
||||
<table name="member_autologin" />
|
||||
</tables>
|
||||
<columns>
|
||||
<column name="security_key" var="security_key" />
|
||||
<column name="member_srl" var="member_srl" filter="number" />
|
||||
<column name="last_visit" var="last_visit" default="curdate()" />
|
||||
<column name="last_ipaddress" var="last_ipaddress" default="ipaddress()" />
|
||||
<column name="user_agent" var="user_agent" />
|
||||
</columns>
|
||||
</query>
|
||||
|
|
@ -1,4 +1,11 @@
|
|||
<table name="member_autologin">
|
||||
<column name="autologin_key" type="varchar" size="80" notnull="notnull" unique="unique_key" />
|
||||
<column name="member_srl" type="number" size="11" notnull="notnull" unique="unique_key" />
|
||||
<column name="id" type="number" primary_key="primary_key" auto_increment="auto_increment" />
|
||||
<column name="autologin_key" type="varchar" size="80" notnull="notnull" unique="unique_autologin_key" />
|
||||
<column name="security_key" type="varchar" size="80" notnull="notnull" />
|
||||
<column name="member_srl" type="number" notnull="notnull" index="idx_member_srl" />
|
||||
<column name="regdate" type="date" index="idx_regdate" />
|
||||
<column name="ipaddress" type="varchar" size="80" />
|
||||
<column name="last_visit" type="date" index="idx_last_visited" />
|
||||
<column name="last_ipaddress" type="varchar" size="80" />
|
||||
<column name="user_agent" type="varchar" size="500" />
|
||||
</table>
|
||||
|
|
|
|||
46
modules/member/skins/default/active_logins.html
Normal file
46
modules/member/skins/default/active_logins.html
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<include target="./common_header.html" />
|
||||
<h1>{$member_title = $lang->cmd_view_active_logins }</h1>
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{$lang->no}</th>
|
||||
<th class="title">{$lang->cmd_login_browser_info}</th>
|
||||
<th>{$lang->cmd_initial_login}</th>
|
||||
<th>{$lang->cmd_recent_visit}</th>
|
||||
<th>{$lang->cmd_delete}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr loop="$active_logins => $no, $autologin_info">
|
||||
{@ $autologin_info->user_agent = @json_decode($autologin_info->user_agent) ?: new stdClass()}
|
||||
<td>{$no}</td>
|
||||
<td class="title">
|
||||
{escape($autologin_info->user_agent->browser)} {escape($autologin_info->user_agent->version)}<br />
|
||||
{escape($autologin_info->user_agent->os)} {$autologin_info->user_agent->is_tablet ? 'Tablet' : ($autologin_info->user_agent->is_mobile ? 'Mobile' : 'PC')}
|
||||
</td>
|
||||
<td>{zdate($autologin_info->regdate, 'Y-m-d H:i')}<br />{$autologin_info->ipaddress}</td>
|
||||
<td>{zdate($autologin_info->last_visit, 'Y-m-d H:i')}<br />{$autologin_info->last_ipaddress}</td>
|
||||
<td><button class="delele_autologin" data-autologin-id="{$autologin_info->id}" data-autologin-key="{$autologin_info->autologin_key}">{$lang->cmd_delete}</button></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="pagination pagination-centered">
|
||||
<ul>
|
||||
<li><a href="{getUrl('page','','module_srl','')}" class="direction">« {$lang->first_page}</a></li>
|
||||
<!--@while($page_no = $page_navigation->getNextPage())-->
|
||||
<li class="active"|cond="$page == $page_no"><a href="{getUrl('page',$page_no,'module_srl','')}">{$page_no}</a></li>
|
||||
<!--@end-->
|
||||
<li><a href="{getUrl('page',$page_navigation->last_page,'module_srl','')}" class="direction">{$lang->last_page} »</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<script>
|
||||
$(function() {
|
||||
$("button.delele_autologin").on("click", function(event) {
|
||||
event.preventDefault();
|
||||
exec_json('member.procMemberDeleteAutologin', { autologin_id: $(this).data("autologin-id"), autologin_key: $(this).data("autologin-key") }, function(data) {
|
||||
window.location.reload();
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<include target="./common_footer.html" />
|
||||
47
modules/member/skins/simple_world/active_logins.html
Normal file
47
modules/member/skins/simple_world/active_logins.html
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<include target="./common_header.html" />
|
||||
<section class="sw-body">
|
||||
<h1>{$member_title = lang('member.cmd_view_active_logins')}</h1>
|
||||
<div class="rx_member-notice">
|
||||
{lang('common.total')}: {number_format($total_count)}
|
||||
</div>
|
||||
<div>
|
||||
<ul class="rx_sw_list">
|
||||
<li loop="$active_logins => $no, $autologin_info">
|
||||
{@ $autologin_info->user_agent = @json_decode($autologin_info->user_agent) ?: new stdClass()}
|
||||
<span class="content_basic">
|
||||
<span class="content_title">
|
||||
{escape($autologin_info->user_agent->browser)} {escape($autologin_info->user_agent->version)} ({escape($autologin_info->user_agent->os)})
|
||||
</span>
|
||||
<span class="content_subinfo">
|
||||
{zdate($autologin_info->regdate, 'Y-m-d H:i')} ({$autologin_info->ipaddress})
|
||||
</span>
|
||||
<a class="delele_autologin" data-autologin-id="{$autologin_info->id}" data-autologin-key="{$autologin_info->autologin_key}" href="#">{$lang->cmd_delete}</a>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
<div class="pagination pagination-centered">
|
||||
<ul>
|
||||
<li><a href="{getUrl('page','','module_srl','')}" class="direction">‹ {lang('common.first_page')}</a></li>
|
||||
<!--@while($page_no = $page_navigation->getNextPage())-->
|
||||
<li class="active"|cond="$page == $page_no"><a href="{getUrl('page',$page_no,'module_srl','')}">{$page_no}</a></li>
|
||||
<!--@end-->
|
||||
<li><a href="{getUrl('page',$page_navigation->last_page,'module_srl','')}" class="direction">{lang('common.last_page')} ›</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sw-footer sw-anchor-buttons">
|
||||
<a href="{getUrl('','module','module','act','dispModuleSelectList','id','target_module','type','single')}" onclick="popopen(this.href,'ModuleSelect');return false;">{lang('module.cmd_find_module')}</a>
|
||||
<a href="{getUrl('selected_module_srl','')}" cond="$selected_module_srl">{lang('common.cmd_cancel')}</a>
|
||||
</div>
|
||||
<script>
|
||||
$(function() {
|
||||
$("a.delele_autologin").on("click", function(event) {
|
||||
event.preventDefault();
|
||||
exec_json('member.procMemberDeleteAutologin', { autologin_id: $(this).data("autologin-id"), autologin_key: $(this).data("autologin-key") }, function(data) {
|
||||
window.location.reload();
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<include target="./common_footer.html" />
|
||||
|
|
@ -71,6 +71,14 @@
|
|||
<p class="x_help-block">{$lang->about_password_hashing_auto_upgrade}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="x_control-group">
|
||||
<label class="x_control-label">{$lang->cmd_password_change_invalidate_other_sessions}</label>
|
||||
<div class="x_controls">
|
||||
<label for="password_change_invalidate_other_sessions_y" class="x_inline"><input type="radio" name="password_change_invalidate_other_sessions" id="password_change_invalidate_other_sessions_y" value="Y" checked="checked"|cond="$config->password_change_invalidate_other_sessions == 'Y'" /> {$lang->cmd_yes}</label>
|
||||
<label for="password_change_invalidate_other_sessions_n" class="x_inline"><input type="radio" name="password_change_invalidate_other_sessions" id="password_change_invalidate_other_sessions_n" value="N" checked="checked"|cond="$config->password_change_invalidate_other_sessions != 'Y'" /> {$lang->cmd_no}</label>
|
||||
<p class="x_help-block">{$lang->about_password_change_invalidate_other_sessions}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="x_control-group">
|
||||
<label class="x_control-label" for="webmaster_name">{$lang->webmaster_name}</label>
|
||||
<div class="x_controls">
|
||||
|
|
|
|||
|
|
@ -22,11 +22,11 @@ class DateTimeTest extends \Codeception\TestCase\Test
|
|||
public function testZgap()
|
||||
{
|
||||
// Test zgap() when the current user's time zone is different from the system default.
|
||||
$_SESSION['timezone'] = 'Etc/UTC';
|
||||
$_SESSION['RHYMIX']['timezone'] = 'Etc/UTC';
|
||||
$this->assertEquals(-10800, zgap());
|
||||
|
||||
// Test zgap() when the current user's time zone is the same as the system default.
|
||||
unset($_SESSION['timezone']);
|
||||
unset($_SESSION['RHYMIX']['timezone']);
|
||||
$this->assertEquals(21600, zgap());
|
||||
}
|
||||
|
||||
|
|
@ -80,11 +80,11 @@ class DateTimeTest extends \Codeception\TestCase\Test
|
|||
$timestamp = 1454000000;
|
||||
|
||||
// Test when the display time zone is different from the internal time zone.
|
||||
$_SESSION['timezone'] = 'America/Los_Angeles';
|
||||
$_SESSION['RHYMIX']['timezone'] = 'America/Los_Angeles';
|
||||
$this->assertEquals('20160128085320', getDisplayDateTime($timestamp));
|
||||
|
||||
// Test when the display time zone is the same as the internal time zone.
|
||||
$_SESSION['timezone'] = 'Etc/GMT-3';
|
||||
$_SESSION['RHYMIX']['timezone'] = 'Etc/GMT-3';
|
||||
$this->assertEquals('20160128195320', getDisplayDateTime($timestamp));
|
||||
}
|
||||
|
||||
|
|
@ -109,11 +109,11 @@ class DateTimeTest extends \Codeception\TestCase\Test
|
|||
public function testGetTimezoneForCurrentUser()
|
||||
{
|
||||
// Test when the current user's time zone is different from the system default.
|
||||
$_SESSION['timezone'] = 'Pacific/Auckland';
|
||||
$_SESSION['RHYMIX']['timezone'] = 'Pacific/Auckland';
|
||||
$this->assertEquals('Pacific/Auckland', Rhymix\Framework\DateTime::getTimezoneForCurrentUser());
|
||||
|
||||
// Test when the current user's time zone is the same as the system default.
|
||||
unset($_SESSION['timezone']);
|
||||
unset($_SESSION['RHYMIX']['timezone']);
|
||||
$this->assertEquals('Asia/Seoul', Rhymix\Framework\DateTime::getTimezoneForCurrentUser());
|
||||
}
|
||||
|
||||
|
|
@ -123,19 +123,19 @@ class DateTimeTest extends \Codeception\TestCase\Test
|
|||
$timestamp_summer = $timestamp_winter - (86400 * 184);
|
||||
|
||||
// Test when the current user's time zone is in the Northern hemisphere with DST.
|
||||
$_SESSION['timezone'] = 'America/Chicago';
|
||||
$_SESSION['RHYMIX']['timezone'] = 'America/Chicago';
|
||||
$this->assertEquals('20160128 105320', Rhymix\Framework\DateTime::formatTimestampForCurrentUser('Ymd His', $timestamp_winter));
|
||||
$this->assertEquals('20150728 115320', Rhymix\Framework\DateTime::formatTimestampForCurrentUser('Ymd His', $timestamp_summer));
|
||||
$this->assertEquals('20150728 115320', getDisplayDateTime($timestamp_summer, 'Ymd His'));
|
||||
|
||||
// Test when the current user's time zone is in the Southern hemisphere with DST.
|
||||
$_SESSION['timezone'] = 'Pacific/Auckland';
|
||||
$_SESSION['RHYMIX']['timezone'] = 'Pacific/Auckland';
|
||||
$this->assertEquals('20160129 055320', Rhymix\Framework\DateTime::formatTimestampForCurrentUser('Ymd His', $timestamp_winter));
|
||||
$this->assertEquals('20150729 045320', Rhymix\Framework\DateTime::formatTimestampForCurrentUser('Ymd His', $timestamp_summer));
|
||||
$this->assertEquals('20150729 045320', getDisplayDateTime($timestamp_summer, 'Ymd His'));
|
||||
|
||||
// Test when the current user's time zone is the same as the system default without DST.
|
||||
unset($_SESSION['timezone']);
|
||||
unset($_SESSION['RHYMIX']['timezone']);
|
||||
$this->assertEquals('20160129 015320', Rhymix\Framework\DateTime::formatTimestampForCurrentUser('Ymd His', $timestamp_winter));
|
||||
$this->assertEquals('20150729 015320', Rhymix\Framework\DateTime::formatTimestampForCurrentUser('Ymd His', $timestamp_summer));
|
||||
$this->assertEquals('20150729 015320', getDisplayDateTime($timestamp_summer, 'Ymd His'));
|
||||
|
|
|
|||
357
tests/unit/framework/SessionTest.php
Normal file
357
tests/unit/framework/SessionTest.php
Normal file
|
|
@ -0,0 +1,357 @@
|
|||
<?php
|
||||
|
||||
class SessionTest extends \Codeception\TestCase\Test
|
||||
{
|
||||
public function _before()
|
||||
{
|
||||
Rhymix\Framework\Config::set('session.delay', false);
|
||||
Rhymix\Framework\Session::close();
|
||||
session_id('rhymix-test-session');
|
||||
$_SESSION = array();
|
||||
$_COOKIE = array();
|
||||
}
|
||||
|
||||
public function _after()
|
||||
{
|
||||
Rhymix\Framework\Config::set('session.delay', false);
|
||||
Rhymix\Framework\Session::close();
|
||||
session_id('rhymix-test-session');
|
||||
$_SESSION = array();
|
||||
$_COOKIE = array();
|
||||
}
|
||||
|
||||
public function _failed()
|
||||
{
|
||||
Rhymix\Framework\Config::set('session.delay', false);
|
||||
Rhymix\Framework\Session::close();
|
||||
session_id('rhymix-test-session');
|
||||
$_SESSION = array();
|
||||
$_COOKIE = array();
|
||||
}
|
||||
|
||||
public function testGetSet()
|
||||
{
|
||||
$this->assertFalse(isset($_SESSION['foo']['bar']));
|
||||
$this->assertNull(Rhymix\Framework\Session::get('foo.bar'));
|
||||
Rhymix\Framework\Session::set('foo.bar', 'bazz');
|
||||
$this->assertTrue(isset($_SESSION['foo']['bar']));
|
||||
$this->assertEquals('bazz', Rhymix\Framework\Session::get('foo.bar'));
|
||||
Rhymix\Framework\Session::set('foo.baz', 'bazzzz');
|
||||
$this->assertEquals(array('bar' => 'bazz', 'baz' => 'bazzzz'), Rhymix\Framework\Session::get('foo'));
|
||||
$this->assertEquals(array('bar' => 'bazz', 'baz' => 'bazzzz'), $_SESSION['foo']);
|
||||
}
|
||||
|
||||
public function testStart()
|
||||
{
|
||||
// Test normal start.
|
||||
$this->assertTrue(Rhymix\Framework\Session::start());
|
||||
$this->assertTrue(isset($_COOKIE['rx_sesskey1']));
|
||||
$this->assertTrue(isset($_COOKIE['rx_sesskey2']));
|
||||
$this->assertNotEmpty($_SESSION['RHYMIX']['secret']);
|
||||
$this->assertEquals($_SESSION['RHYMIX']['keys']['www.rhymix.org']['key1'], $_COOKIE['rx_sesskey1']);
|
||||
$this->assertEquals($_SESSION['RHYMIX']['keys']['www.rhymix.org']['key2'], $_COOKIE['rx_sesskey2']);
|
||||
$this->assertEquals(0, $_SESSION['RHYMIX']['keys']['www.rhymix.org']['trusted']);
|
||||
$session_secret = $_SESSION['RHYMIX']['secret'];
|
||||
Rhymix\Framework\Session::close();
|
||||
|
||||
// Test normal restart.
|
||||
$this->assertTrue(Rhymix\Framework\Session::start());
|
||||
$this->assertEquals($session_secret, $_SESSION['RHYMIX']['secret']);
|
||||
$session_secret = $_SESSION['RHYMIX']['secret'];
|
||||
Rhymix\Framework\Session::close();
|
||||
|
||||
// Test missing HTTP key.
|
||||
unset($_COOKIE['rx_sesskey1']);
|
||||
$this->assertTrue(Rhymix\Framework\Session::start());
|
||||
$this->assertNotEquals($session_secret, $_SESSION['RHYMIX']['secret']);
|
||||
$session_secret = $_SESSION['RHYMIX']['secret'];
|
||||
Rhymix\Framework\Session::close();
|
||||
|
||||
// Test missing HTTPS key.
|
||||
unset($_COOKIE['rx_sesskey2']);
|
||||
$this->assertTrue(Rhymix\Framework\Session::start());
|
||||
$this->assertNotEquals($session_secret, $_SESSION['RHYMIX']['secret']);
|
||||
$session_secret = $_SESSION['RHYMIX']['secret'];
|
||||
Rhymix\Framework\Session::close();
|
||||
|
||||
// Test invalid HTTP key.
|
||||
$_COOKIE['rx_sesskey1'] = substr(md5(mt_rand()), 0, 24);
|
||||
$this->assertTrue(Rhymix\Framework\Session::start());
|
||||
$this->assertNotEquals($session_secret, $_SESSION['RHYMIX']['secret']);
|
||||
$session_secret = $_SESSION['RHYMIX']['secret'];
|
||||
Rhymix\Framework\Session::close();
|
||||
|
||||
// Test invalid HTTPS key.
|
||||
$_COOKIE['rx_sesskey2'] = substr(md5(mt_rand()), 0, 24);
|
||||
$this->assertTrue(Rhymix\Framework\Session::start());
|
||||
$this->assertNotEquals($session_secret, $_SESSION['RHYMIX']['secret']);
|
||||
$session_secret = $_SESSION['RHYMIX']['secret'];
|
||||
Rhymix\Framework\Session::close();
|
||||
|
||||
// Test initial transition from HTTP to HTTPS.
|
||||
session_start();
|
||||
unset($_SESSION['RHYMIX']['keys']['www.rhymix.org']['key2']);
|
||||
unset($_COOKIE['rx_sesskey2']);
|
||||
session_write_close();
|
||||
$this->assertTrue(Rhymix\Framework\Session::start());
|
||||
$this->assertEquals($session_secret, $_SESSION['RHYMIX']['secret']);
|
||||
$session_secret = $_SESSION['RHYMIX']['secret'];
|
||||
Rhymix\Framework\Session::close();
|
||||
}
|
||||
|
||||
public function testCheckStart()
|
||||
{
|
||||
Rhymix\Framework\Config::set('session.delay', true);
|
||||
|
||||
$_SESSION = array();
|
||||
unset($_COOKIE['PHPSESSID']);
|
||||
$this->assertFalse(Rhymix\Framework\Session::start());
|
||||
$this->assertFalse(Rhymix\Framework\Session::isStarted());
|
||||
$this->assertFalse(Rhymix\Framework\Session::checkStart());
|
||||
$this->assertFalse(Rhymix\Framework\Session::isStarted());
|
||||
|
||||
$_SESSION['foo'] = 'bar';
|
||||
$this->assertTrue(Rhymix\Framework\Session::checkStart());
|
||||
$this->assertTrue(Rhymix\Framework\Session::isStarted());
|
||||
$this->assertEquals('bar', $_SESSION['foo']);
|
||||
$this->assertEquals('bar', Rhymix\Framework\Session::get('foo'));
|
||||
Rhymix\Framework\Session::close();
|
||||
|
||||
$_SESSION = array();
|
||||
unset($_COOKIE['PHPSESSID']);
|
||||
$this->assertTrue(Rhymix\Framework\Session::checkStart(true));
|
||||
$this->assertTrue(Rhymix\Framework\Session::isStarted());
|
||||
Rhymix\Framework\Session::close();
|
||||
|
||||
$_SESSION = array();
|
||||
unset($_COOKIE['PHPSESSID']);
|
||||
$this->assertTrue(Rhymix\Framework\Session::start(true));
|
||||
$this->assertTrue(Rhymix\Framework\Session::isStarted());
|
||||
}
|
||||
|
||||
public function testCheckSSO()
|
||||
{
|
||||
$this->assertFalse(Rhymix\Framework\Session::checkSSO());
|
||||
}
|
||||
|
||||
public function testRefresh()
|
||||
{
|
||||
Rhymix\Framework\Session::start();
|
||||
$session_secret = $_SESSION['RHYMIX']['secret'];
|
||||
$key1 = $_SESSION['RHYMIX']['keys']['www.rhymix.org']['key1'];
|
||||
$key2 = $_SESSION['RHYMIX']['keys']['www.rhymix.org']['key2'];
|
||||
$_SESSION['RHYMIX']['keys']['www.rhymix.org']['key1_time'] = time() - 3600;
|
||||
$_SESSION['RHYMIX']['keys']['www.rhymix.org']['key2_time'] = time() - 3600;
|
||||
Rhymix\Framework\Session::close();
|
||||
|
||||
Rhymix\Framework\Session::start();
|
||||
$this->assertNotEquals($key1, $_SESSION['RHYMIX']['keys']['www.rhymix.org']['key1']);
|
||||
$this->assertNotEquals($key2, $_SESSION['RHYMIX']['keys']['www.rhymix.org']['key2']);
|
||||
$this->assertEquals($key1, $_SESSION['RHYMIX']['keys']['www.rhymix.org']['key1_prev']);
|
||||
$this->assertEquals($key2, $_SESSION['RHYMIX']['keys']['www.rhymix.org']['key2_prev']);
|
||||
$this->assertEquals($session_secret, $_SESSION['RHYMIX']['secret']);
|
||||
Rhymix\Framework\Session::close();
|
||||
}
|
||||
|
||||
public function testClose()
|
||||
{
|
||||
Rhymix\Framework\Session::start();
|
||||
$this->assertEquals(\PHP_SESSION_ACTIVE, session_status());
|
||||
Rhymix\Framework\Session::close();
|
||||
$this->assertEquals(\PHP_SESSION_NONE, session_status());
|
||||
}
|
||||
|
||||
public function testDestroy()
|
||||
{
|
||||
Rhymix\Framework\Session::start();
|
||||
$this->assertTrue(isset($_SESSION['RHYMIX']));
|
||||
Rhymix\Framework\Session::destroy();
|
||||
$this->assertFalse(isset($_SESSION['RHYMIX']));
|
||||
}
|
||||
|
||||
public function testLoginLogout()
|
||||
{
|
||||
Rhymix\Framework\Session::start();
|
||||
$this->assertFalse($_SESSION['RHYMIX']['login']);
|
||||
$this->assertFalse($_SESSION['member_srl']);
|
||||
$this->assertFalse($_SESSION['is_logged']);
|
||||
|
||||
Rhymix\Framework\Session::login(42);
|
||||
$this->assertEquals(42, $_SESSION['RHYMIX']['login']);
|
||||
$this->assertEquals(42, $_SESSION['member_srl']);
|
||||
$this->assertTrue($_SESSION['is_logged']);
|
||||
|
||||
Rhymix\Framework\Session::logout();
|
||||
$this->assertFalse(isset($_SESSION['RHYMIX']['login']));
|
||||
$this->assertFalse($_SESSION['member_srl']);
|
||||
$this->assertFalse($_SESSION['is_logged']);
|
||||
|
||||
Rhymix\Framework\Session::close();
|
||||
}
|
||||
|
||||
public function testIsStarted()
|
||||
{
|
||||
$this->assertFalse(Rhymix\Framework\Session::isStarted());
|
||||
Rhymix\Framework\Session::start();
|
||||
$this->assertTrue(Rhymix\Framework\Session::isStarted());
|
||||
Rhymix\Framework\Session::close();
|
||||
$this->assertFalse(Rhymix\Framework\Session::isStarted());
|
||||
}
|
||||
|
||||
public function testIsMember()
|
||||
{
|
||||
Rhymix\Framework\Session::start();
|
||||
$this->assertFalse(Rhymix\Framework\Session::isMember());
|
||||
|
||||
Rhymix\Framework\Session::login(42);
|
||||
$this->assertTrue(Rhymix\Framework\Session::isMember());
|
||||
|
||||
Rhymix\Framework\Session::close();
|
||||
}
|
||||
|
||||
public function testIsAdmin()
|
||||
{
|
||||
Rhymix\Framework\Session::start();
|
||||
$this->assertFalse(Rhymix\Framework\Session::isAdmin());
|
||||
|
||||
Rhymix\Framework\Session::login(42);
|
||||
$this->assertFalse(Rhymix\Framework\Session::isAdmin());
|
||||
|
||||
Rhymix\Framework\Session::setMemberInfo((object)array('member_srl' => 42, 'is_admin' => 'Y'));
|
||||
$this->assertTrue(Rhymix\Framework\Session::isAdmin());
|
||||
|
||||
Rhymix\Framework\Session::setMemberInfo((object)array('member_srl' => 99, 'is_admin' => 'Y'));
|
||||
$this->assertFalse(Rhymix\Framework\Session::isAdmin());
|
||||
|
||||
Rhymix\Framework\Session::close();
|
||||
}
|
||||
|
||||
public function testIsTrusted()
|
||||
{
|
||||
Rhymix\Framework\Session::start();
|
||||
|
||||
$_SESSION['RHYMIX']['keys']['www.rhymix.org']['trusted'] = 0;
|
||||
$this->assertFalse(Rhymix\Framework\Session::isTrusted());
|
||||
$_SESSION['RHYMIX']['keys']['www.rhymix.org']['trusted'] = time() + 300;
|
||||
$this->assertTrue(Rhymix\Framework\Session::isTrusted());
|
||||
|
||||
Rhymix\Framework\Session::close();
|
||||
}
|
||||
|
||||
public function testIsValid()
|
||||
{
|
||||
Rhymix\Framework\Session::start();
|
||||
|
||||
$member_srl = 4;
|
||||
Rhymix\Framework\Session::login($member_srl);
|
||||
|
||||
$invalid_before = time() - 300;
|
||||
$filename = \RX_BASEDIR . sprintf('files/member_extra_info/invalid_before/%s%d.txt', getNumberingPath($member_srl), $member_srl);
|
||||
Rhymix\Framework\Storage::write($filename, $invalid_before);
|
||||
Rhymix\Framework\Cache::set(sprintf('session:invalid_before:%d', $member_srl), $invalid_before);
|
||||
$this->assertTrue(Rhymix\Framework\Session::isValid());
|
||||
|
||||
$invalid_before = time() + 300;
|
||||
$filename = \RX_BASEDIR . sprintf('files/member_extra_info/invalid_before/%s%d.txt', getNumberingPath($member_srl), $member_srl);
|
||||
Rhymix\Framework\Storage::write($filename, $invalid_before);
|
||||
Rhymix\Framework\Cache::set(sprintf('session:invalid_before:%d', $member_srl), $invalid_before);
|
||||
$this->assertFalse(Rhymix\Framework\Session::isValid());
|
||||
|
||||
$invalid_before = time();
|
||||
$filename = \RX_BASEDIR . sprintf('files/member_extra_info/invalid_before/%s%d.txt', getNumberingPath($member_srl), $member_srl);
|
||||
Rhymix\Framework\Storage::write($filename, $invalid_before);
|
||||
Rhymix\Framework\Cache::set(sprintf('session:invalid_before:%d', $member_srl), $invalid_before);
|
||||
$this->assertTrue(Rhymix\Framework\Session::isValid());
|
||||
|
||||
Rhymix\Framework\Session::close();
|
||||
}
|
||||
|
||||
public function testGetMemberSrl()
|
||||
{
|
||||
Rhymix\Framework\Session::start();
|
||||
$this->assertEquals(false, Rhymix\Framework\Session::getMemberSrl());
|
||||
|
||||
Rhymix\Framework\Session::login(42);
|
||||
$this->assertEquals(42, Rhymix\Framework\Session::getMemberSrl());
|
||||
|
||||
Rhymix\Framework\Session::close();
|
||||
}
|
||||
|
||||
public function testGetMemberInfo()
|
||||
{
|
||||
Rhymix\Framework\Session::start();
|
||||
$this->assertEquals(false, Rhymix\Framework\Session::getMemberInfo());
|
||||
|
||||
Rhymix\Framework\Session::login(42);
|
||||
$this->assertEquals(false, Rhymix\Framework\Session::getMemberInfo());
|
||||
|
||||
Rhymix\Framework\Session::setMemberInfo((object)array('member_srl' => 42));
|
||||
$this->assertEquals((object)array('member_srl' => 42), Rhymix\Framework\Session::getMemberInfo());
|
||||
|
||||
Rhymix\Framework\Session::setMemberInfo((object)array('member_srl' => 99, 'is_admin' => 'Y'));
|
||||
$this->assertEquals(false, Rhymix\Framework\Session::getMemberInfo());
|
||||
|
||||
Rhymix\Framework\Session::close();
|
||||
}
|
||||
|
||||
public function testGetSetLanguage()
|
||||
{
|
||||
Rhymix\Framework\Session::start();
|
||||
$this->assertEquals(\Context::getLangType(), Rhymix\Framework\Session::getLanguage());
|
||||
|
||||
Rhymix\Framework\Session::setLanguage('ja');
|
||||
$this->assertEquals('ja', Rhymix\Framework\Session::getLanguage());
|
||||
|
||||
Rhymix\Framework\Session::close();
|
||||
}
|
||||
|
||||
public function testGetSetTimezone()
|
||||
{
|
||||
Rhymix\Framework\Session::start();
|
||||
$this->assertEquals(config('locale.default_timezone'), Rhymix\Framework\Session::getTimezone());
|
||||
|
||||
Rhymix\Framework\Session::setTimezone('Asia/Beijing');
|
||||
$this->assertEquals('Asia/Beijing', Rhymix\Framework\Session::getTimezone());
|
||||
|
||||
Rhymix\Framework\Session::close();
|
||||
}
|
||||
|
||||
public function testTokens()
|
||||
{
|
||||
Rhymix\Framework\Session::start();
|
||||
|
||||
$token1 = Rhymix\Framework\Session::createToken();
|
||||
$this->assertTrue(ctype_alnum($token1));
|
||||
$this->assertEquals(16, strlen($token1));
|
||||
$this->assertTrue(Rhymix\Framework\Session::verifyToken($token1));
|
||||
$this->assertFalse(Rhymix\Framework\Session::verifyToken(strrev($token1)));
|
||||
|
||||
$token2 = Rhymix\Framework\Session::createToken('/my/key');
|
||||
$this->assertTrue(Rhymix\Framework\Session::verifyToken($token2, '/my/key'));
|
||||
$this->assertFalse(Rhymix\Framework\Session::verifyToken($token2));
|
||||
$this->assertFalse(Rhymix\Framework\Session::verifyToken($token2, '/wrong/key'));
|
||||
$this->assertFalse(Rhymix\Framework\Session::verifyToken(strrev($token2)));
|
||||
|
||||
Rhymix\Framework\Session::destroy();
|
||||
$this->assertFalse(Rhymix\Framework\Session::verifyToken($token1));
|
||||
$this->assertFalse(Rhymix\Framework\Session::verifyToken($token, '/my/key'));
|
||||
}
|
||||
|
||||
public function testEncryption()
|
||||
{
|
||||
Rhymix\Framework\Session::start();
|
||||
|
||||
$plaintext = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.';
|
||||
$ciphertext = Rhymix\Framework\Session::encrypt($plaintext);
|
||||
$this->assertNotEquals(false, $ciphertext);
|
||||
$this->assertEquals($plaintext, Rhymix\Framework\Session::decrypt($ciphertext));
|
||||
|
||||
Rhymix\Framework\Session::destroy();
|
||||
$this->assertFalse(Rhymix\Framework\Session::decrypt($ciphertext));
|
||||
|
||||
Rhymix\Framework\Session::start();
|
||||
$this->assertFalse(Rhymix\Framework\Session::decrypt($ciphertext));
|
||||
|
||||
Rhymix\Framework\Session::close();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue