From 9d1738e21dcec2680a9dee3c01f2afa1e60e737e Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Thu, 5 Feb 2026 22:13:50 +0900 Subject: [PATCH 1/6] Add trigger before auto-login #2665 #2666 --- common/framework/Session.php | 2 +- modules/member/member.controller.php | 54 +++++++++++++++++++++------- 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/common/framework/Session.php b/common/framework/Session.php index 52027e80e..1a6e7242d 100644 --- a/common/framework/Session.php +++ b/common/framework/Session.php @@ -380,7 +380,7 @@ class Session self::$_autologin_key = self::_getAutologinKey(); if (!$member_srl && self::$_autologin_key) { - $member_srl = \MemberController::getInstance()->doAutologin(self::$_autologin_key); + $member_srl = \MemberController::doAutoLogin(self::$_autologin_key); if ($member_srl && self::isValid($member_srl)) { self::login($member_srl, false); diff --git a/modules/member/member.controller.php b/modules/member/member.controller.php index f5f972cdf..6a9e8b401 100644 --- a/modules/member/member.controller.php +++ b/modules/member/member.controller.php @@ -2387,7 +2387,7 @@ class MemberController extends Member * @param string $autologin_key * @return int|false */ - function doAutologin($autologin_key = null) + public static function doAutoLogin($autologin_key = null) { // Validate the key. if (strlen($autologin_key) == 48) @@ -2430,6 +2430,28 @@ class MemberController extends Member return false; } + // Get the member info and check it. + $member_info = MemberModel::getMemberInfo($output->data->member_srl); + if (!$member_info) + { + return false; + } + if (!empty($member_info->denied) && $member_info->denied === 'Y') + { + return false; + } + if (!empty($member_info->limit_date) && substr($member_info->limit_date, 0, 8) >= date('Ymd')) + { + return false; + } + + // Call a trigger before auto-login. + $trigger_output = ModuleHandler::triggerCall('member.doAutoLogin', 'before', $member_info); + if (!$trigger_output->toBool()) + { + return false; + } + // If the current security key matches, generate a new key. // If the previous key matches, don't update until the client has the current key. // Resending the current key in this case will be handled by the Session class. @@ -2462,13 +2484,10 @@ class MemberController extends Member } // Update the last login time. - executeQuery('member.updateLastLogin', (object)['member_srl' => $output->data->member_srl]); - self::clearMemberCache($output->data->member_srl); + self::updateLastLogin($output->data->member_srl); - // Call a trigger after validate security key (after) - $trigger_obj = new stdClass(); - $trigger_obj->member_srl = $output->data->member_srl; - ModuleHandler::triggerCall('member.doAutoLogin', 'after', $trigger_obj); + // Call a trigger after validate security key. + ModuleHandler::triggerCall('member.doAutoLogin', 'after', $member_info); // Return the member_srl. return intval($output->data->member_srl); @@ -2640,11 +2659,6 @@ class MemberController extends Member } } - // Update the latest login time - $args->member_srl = $member_info->member_srl; - $output = executeQuery('member.updateLastLogin', $args); - self::clearMemberCache($args->member_srl); - // Check if there is recoding table. $oDB = DB::getInstance(); if($oDB->isTableExists('member_count_history') && $config->enable_login_fail_report != 'N') @@ -2702,6 +2716,7 @@ class MemberController extends Member // Log in! Rhymix\Framework\Session::login($member_info->member_srl); + self::updateLastLogin($member_info->member_srl); $this->setSessionInfo(); // Log out all other sessions if so configured. @@ -2716,10 +2731,23 @@ class MemberController extends Member return $output; } + /** + * Update the last login timestamp of a member. + * + * @param int $member_srl + * @return object + */ + public static function updateLastLogin(int $member_srl) + { + $output = executeQuery('member.updateLastLogin', ['member_srl' => $member_srl]); + self::clearMemberCache($member_srl); + return $output; + } + /** * Update or create session information */ - function setSessionInfo() + public function setSessionInfo() { // If your information came through the current session information to extract information from the users $member_info = Rhymix\Framework\Session::getMemberInfo(true); From d9a6c577fde190b8b64674d8a137b7380073bb0b Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Thu, 5 Feb 2026 22:26:24 +0900 Subject: [PATCH 2/6] Restore available fields in password reset email #2663 --- modules/member/member.controller.php | 16 ++++++++++++++++ .../skins/default/find_member_account_mail.html | 8 +++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/modules/member/member.controller.php b/modules/member/member.controller.php index 6a9e8b401..0bdfceb13 100644 --- a/modules/member/member.controller.php +++ b/modules/member/member.controller.php @@ -1841,6 +1841,7 @@ class MemberController extends Member } Context::set('auth_args', $args); + // Prepare member information to be included in the email #2594 #2663 $memberInfo = array(); if (in_array('user_id', $member_config->identifiers)) { @@ -1850,6 +1851,21 @@ class MemberController extends Member { $memberInfo[$lang->email_address] = $member_info->email_address; } + if (in_array('phone_number', $member_config->identifiers)) + { + $phone_number = $member_info->phone_number; + if($member_config->phone_number_hide_country !== 'Y') + { + $phone_number = Rhymix\Framework\i18n::formatPhoneNumber($phone_number, $member_info->phone_country); + } + elseif($member_config->phone_number_default_country === 'KOR' && ($member_info->phone_country === 'KOR' || $member_info->phone_country == '82')) + { + $phone_number = Rhymix\Framework\Korea::formatPhoneNumber($phone_number); + } + $memberInfo[$lang->phone_number] = $phone_number; + } + $memberInfo[$lang->user_name] = $member_info->user_name; + $memberInfo[$lang->nick_name] = $member_info->nick_name; Context::set('memberInfo', $memberInfo); if(!$member_config->skin) $member_config->skin = "default"; diff --git a/modules/member/skins/default/find_member_account_mail.html b/modules/member/skins/default/find_member_account_mail.html index 36ace04da..151368fa4 100644 --- a/modules/member/skins/default/find_member_account_mail.html +++ b/modules/member/skins/default/find_member_account_mail.html @@ -2,7 +2,13 @@

From d824bc9da378f0d8425bf9f615dae2790c53938c Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Thu, 5 Feb 2026 22:36:31 +0900 Subject: [PATCH 3/6] Clean up method of loading default sender info #2661 --- .../admin/controllers/systemconfig/Notification.php | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/modules/admin/controllers/systemconfig/Notification.php b/modules/admin/controllers/systemconfig/Notification.php index 0068d6a5a..79a8eaec2 100644 --- a/modules/admin/controllers/systemconfig/Notification.php +++ b/modules/admin/controllers/systemconfig/Notification.php @@ -20,17 +20,16 @@ class Notification extends Base public function dispAdminConfigNotification() { // Load advanced mailer module (for lang). - $oAdvancedMailerAdminView = \Advanced_mailerAdminView::getInstance(); + $oAdvancedMailerController = \Advanced_mailerController::getInstance(); // Load advanced mailer config. - $advanced_mailer_config = $oAdvancedMailerAdminView->getConfig(); + $advanced_mailer_config = $oAdvancedMailerController->getConfig(); Context::set('advanced_mailer_config', $advanced_mailer_config); // Load member config. - $member_config = ModuleModel::getModuleConfig('member'); - Context::set('member_config', $member_config); - Context::set('webmaster_name', !empty($member_config->webmaster_name) ? $member_config->webmaster_name : 'webmaster'); - Context::set('webmaster_email', $member_config->webmaster_email ?? ''); + $default_identity = $oAdvancedMailerController->getDefaultEmailIdentity(); + Context::set('webmaster_name', $default_identity[1]); + Context::set('webmaster_email', $default_identity[0]); // Load module config. $module_config = ModuleModel::getModuleConfig('module'); @@ -89,7 +88,7 @@ class Notification extends Base $vars = Context::getRequestVars(); // Load advanced mailer module (for lang). - $oAdvancedMailerAdminView = \Advanced_mailerAdminView::getInstance(); + $oAdvancedMailerController = \Advanced_mailerController::getInstance(); // Validate the mail sender's information. if (!$vars->mail_default_name) From 8920cb74912868fa0d2aa6b5266ffcd6b87338d5 Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Thu, 5 Feb 2026 22:39:33 +0900 Subject: [PATCH 4/6] Fix incorrect path conversion on Windows #2667 --- modules/module/module.model.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/module/module.model.php b/modules/module/module.model.php index 3c4182a46..02c1a8e72 100644 --- a/modules/module/module.model.php +++ b/modules/module/module.model.php @@ -1012,7 +1012,7 @@ class ModuleModel extends Module $skin_list[$skin_name] = $skin_info; } - $tmpPath = strtr($path, array('/' => ' ')); + $tmpPath = strtr($path, array('/' => ' ', '\\' => ' ')); $tmpPath = trim($tmpPath); $module = array_last(explode(' ', $tmpPath)); From 26c59c251cac78c5420065042994297ba6a342ff Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Thu, 5 Feb 2026 23:05:19 +0900 Subject: [PATCH 5/6] Fix incorrect conversion of JS template variable containing path #2657 --- common/framework/Template.php | 2 +- tests/unit/framework/parsers/TemplateParserV2Test.php | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/common/framework/Template.php b/common/framework/Template.php index 387c3ba6a..bd7d9165d 100644 --- a/common/framework/Template.php +++ b/common/framework/Template.php @@ -528,7 +528,7 @@ class Template */ public function isRelativePath(string $path): bool { - return !preg_match('#^((?:https?|file|data):|[\/\{<])#i', $path); + return !preg_match('#^((?:https?|file|data):|[\/\{\\\\<$\#@]|&\#x1B;)#i', $path); } /** diff --git a/tests/unit/framework/parsers/TemplateParserV2Test.php b/tests/unit/framework/parsers/TemplateParserV2Test.php index 9754800cf..0257ae05f 100644 --- a/tests/unit/framework/parsers/TemplateParserV2Test.php +++ b/tests/unit/framework/parsers/TemplateParserV2Test.php @@ -676,6 +676,16 @@ class TemplateParserV2Test extends \Codeception\Test\Unit $source = '

url(img/foo.jpg); }

'; $target = '

url(img/foo.jpg); }

'; $this->assertEquals($target, $this->_parse($source)); + + // No conversion if it's a template variable + $source = ''; + $target = ''; + $this->assertEquals($target, $this->_parse($source)); + + // No conversion if it's a JS template variable + $source = '@verbatim let src = `` @endverbatim'; + $target = ' let src = `` '; + $this->assertEquals($target, $this->_parse($source)); } public function testBlockConditions() From 5a8c669c421c82becfd66eb06773c59ad6ac4874 Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Thu, 5 Feb 2026 23:16:38 +0900 Subject: [PATCH 6/6] Fix duplicated layout info when layout.html (or layout.blade.php) does not exist #2132 #2670 --- modules/layout/layout.model.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/layout/layout.model.php b/modules/layout/layout.model.php index 402f8b348..b12e80112 100644 --- a/modules/layout/layout.model.php +++ b/modules/layout/layout.model.php @@ -167,7 +167,7 @@ class LayoutModel extends Layout if($layout) { - if(count($instanceList) < 1 && $downloadedList[$layout]) + if(count($instanceList) < 1 && isset($downloadedList[$layout])) { $insertArgs = new stdClass(); $insertArgs->layout_srl = getNextSequence(); @@ -383,7 +383,7 @@ class LayoutModel extends Layout // Get information of the layout $layout_info = self::getLayoutInfo($layout, null, $layout_type); - if(!$layout_info) + if (!$layout_info || !self::isExistsLayoutFile($layout, $layout_type)) { continue; }