Update launcher session handling
This commit is contained in:
1 parent
21486b606b
commit
f8da17b9db
2 files changed
+132
-15
No files matched your search
@@ -52,7 +52,14 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($action === 'logout') {
|
if ($action === 'logout') {
|
||||||
|
$scope = (string)($data['scope'] ?? '');
|
||||||
|
if ($scope === 'admin') {
|
||||||
custom_clear_auth_cookie();
|
custom_clear_auth_cookie();
|
||||||
|
} elseif (function_exists('custom_clear_non_admin_auth_cookie')) {
|
||||||
|
custom_clear_non_admin_auth_cookie(false);
|
||||||
|
} else {
|
||||||
|
custom_clear_auth_cookie();
|
||||||
|
}
|
||||||
custom_json(['result' => 'ok']);
|
custom_json(['result' => 'ok']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,12 +100,20 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||||
if (isset($_GET['session'])) {
|
if (isset($_GET['session'])) {
|
||||||
$denied = custom_login_denied_state();
|
$denied = custom_login_denied_state();
|
||||||
if (!empty($denied['denied'])) {
|
$blockedType = (string)($denied['type'] ?? '');
|
||||||
|
if (!empty($denied['denied']) && !($blockedType !== 'ip' && custom_is_site_admin())) {
|
||||||
|
if ($blockedType === 'ip') {
|
||||||
|
custom_clear_auth_cookie();
|
||||||
|
} elseif (function_exists('custom_clear_non_admin_auth_cookie')) {
|
||||||
|
custom_clear_non_admin_auth_cookie(true);
|
||||||
|
} else {
|
||||||
|
custom_clear_auth_cookie();
|
||||||
|
}
|
||||||
custom_json([
|
custom_json([
|
||||||
'authenticated' => false,
|
'authenticated' => false,
|
||||||
'admin' => false,
|
'admin' => false,
|
||||||
'loginBlocked' => true,
|
'loginBlocked' => true,
|
||||||
'blockedType' => $denied['type'] ?? '',
|
'blockedType' => $blockedType,
|
||||||
'blockedMessage' => $denied['message'] ?? '현재 로그인할 수 없는 상태입니다.',
|
'blockedMessage' => $denied['message'] ?? '현재 로그인할 수 없는 상태입니다.',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
+115
-13
@@ -5,12 +5,91 @@ let lastRenderedAdmin = null;
|
|||||||
const apiUrl = '/custom/launcher/api.php';
|
const apiUrl = '/custom/launcher/api.php';
|
||||||
const PIN_LENGTH = 4;
|
const PIN_LENGTH = 4;
|
||||||
|
|
||||||
|
function isClientLoginBlocked() {
|
||||||
|
try {
|
||||||
|
return sessionStorage.getItem('login_blocked') === '1';
|
||||||
|
} catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const LAUNCHER_LOGIN_BLOCKED_COOKIE_NAMES = {
|
||||||
|
member: 'chaegeon_member_blocked',
|
||||||
|
ip: 'chaegeon_ip_blocked',
|
||||||
|
login_fail: 'chaegeon_login_fail_blocked',
|
||||||
|
sms_verify_fail: 'chaegeon_sms_verify_blocked',
|
||||||
|
client: 'chaegeon_member_blocked'
|
||||||
|
};
|
||||||
|
const LAUNCHER_LOGIN_BLOCKED_LEGACY_COOKIE = 'chaegeon_login_blocked';
|
||||||
|
|
||||||
|
function clientLoginBlockedCookieName(type) {
|
||||||
|
return LAUNCHER_LOGIN_BLOCKED_COOKIE_NAMES[type || 'member'] || LAUNCHER_LOGIN_BLOCKED_COOKIE_NAMES.member;
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeClientLoginBlockedCookie(name, blocked) {
|
||||||
|
const secure = location.protocol === 'https:' ? '; Secure' : '';
|
||||||
|
document.cookie = `${name}=${blocked ? '1' : ''}; path=/; max-age=${blocked ? '1800' : '0'}; SameSite=Strict${secure}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearClientLoginBlockedCookies(exceptName) {
|
||||||
|
[
|
||||||
|
LAUNCHER_LOGIN_BLOCKED_LEGACY_COOKIE,
|
||||||
|
LAUNCHER_LOGIN_BLOCKED_COOKIE_NAMES.member,
|
||||||
|
LAUNCHER_LOGIN_BLOCKED_COOKIE_NAMES.ip,
|
||||||
|
LAUNCHER_LOGIN_BLOCKED_COOKIE_NAMES.login_fail,
|
||||||
|
LAUNCHER_LOGIN_BLOCKED_COOKIE_NAMES.sms_verify_fail
|
||||||
|
].forEach(name => {
|
||||||
|
if (name !== exceptName) writeClientLoginBlockedCookie(name, false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setClientLoginBlockedCookie(type = 'member') {
|
||||||
|
const name = clientLoginBlockedCookieName(type);
|
||||||
|
clearClientLoginBlockedCookies(name);
|
||||||
|
writeClientLoginBlockedCookie(name, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function rememberClientLoginBlocked(type, message) {
|
||||||
|
try {
|
||||||
|
sessionStorage.setItem('login_blocked', '1');
|
||||||
|
sessionStorage.setItem('login_blocked_type', type || 'member');
|
||||||
|
if (message) sessionStorage.setItem('login_blocked_reason', message);
|
||||||
|
} catch (_) {}
|
||||||
|
setClientLoginBlockedCookie(type || 'member');
|
||||||
|
}
|
||||||
|
|
||||||
|
function isLauncherLoginBlockedAllowedHomePage() {
|
||||||
|
const path = location.pathname.toLowerCase();
|
||||||
|
return location.protocol === 'https:' && location.hostname === 'chaegeon.com' && (path === '/' || path === '/home' || path.startsWith('/home/'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function replaceLauncherToChaegeonHome() {
|
||||||
|
if (isLauncherLoginBlockedAllowedHomePage()) return false;
|
||||||
|
location.replace('https://chaegeon.com/');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function redirectIfClientLoginBlocked() {
|
||||||
|
if (!isClientLoginBlocked()) return false;
|
||||||
|
let type = 'member';
|
||||||
|
try {
|
||||||
|
type = sessionStorage.getItem('login_blocked_type') || 'member';
|
||||||
|
} catch (_) {}
|
||||||
|
setClientLoginBlockedCookie(type);
|
||||||
|
replaceLauncherToChaegeonHome();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function openLauncherTarget(url) {
|
||||||
|
window.open(url, '_blank', 'noopener');
|
||||||
|
}
|
||||||
|
|
||||||
const userIconItems = [
|
const userIconItems = [
|
||||||
{
|
{
|
||||||
id: 'findmydevice',
|
id: 'findmydevice',
|
||||||
img: '/custom/launcher/img/find-my.svg',
|
img: '/custom/launcher/img/find-my.svg',
|
||||||
label: '나의 찾기',
|
label: '나의 찾기',
|
||||||
onclick: () => requireAccess(() => location.href = '/findmydevice')
|
onclick: () => requireAccess(() => openLauncherTarget('/findmydevice'))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'poke',
|
id: 'poke',
|
||||||
@@ -22,13 +101,13 @@ const userIconItems = [
|
|||||||
id: 'car',
|
id: 'car',
|
||||||
img: '/custom/launcher/img/car.png',
|
img: '/custom/launcher/img/car.png',
|
||||||
label: '니모',
|
label: '니모',
|
||||||
onclick: () => requireAccess(() => location.href = 'https://seo.chaegeon.com/car/monitor.php')
|
onclick: () => requireAccess(() => openLauncherTarget('https://chaegeon.com/custom/car/monitor.php'))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'project',
|
id: 'project',
|
||||||
img: 'https://git.chaegeon.com/assets/img/favicon.svg',
|
img: 'https://git.chaegeon.com/assets/img/favicon.svg',
|
||||||
label: '프로젝트',
|
label: '프로젝트',
|
||||||
onclick: () => location.href = 'https://git.chaegeon.com/explore/repos'
|
onclick: () => openLauncherTarget('https://git.chaegeon.com/explore/repos')
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -47,26 +126,29 @@ const adminIconItems = [
|
|||||||
id: 'block',
|
id: 'block',
|
||||||
img: '/admin/favicon/block/favicon.svg',
|
img: '/admin/favicon/block/favicon.svg',
|
||||||
label: 'Block',
|
label: 'Block',
|
||||||
onclick: () => requireAccess(() => location.href = 'https://chaegeon.com/admin/index.php')
|
onclick: () => requireAccess(() => openLauncherTarget('https://chaegeon.com/admin/index.php'))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'notice',
|
id: 'notice',
|
||||||
img: '/admin/favicon/notice/favicon.svg',
|
img: '/admin/favicon/notice/favicon.svg',
|
||||||
label: 'Notice',
|
label: 'Notice',
|
||||||
onclick: () => requireAccess(() => location.href = 'https://chaegeon.com/admin/notice.php')
|
onclick: () => requireAccess(() => openLauncherTarget('https://chaegeon.com/admin/notice.php'))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'speedstats',
|
id: 'speedstats',
|
||||||
img: '/custom/speedtest/favicon.ico',
|
img: '/custom/speedtest/favicon.ico',
|
||||||
label: 'Speed Stats',
|
label: 'Speed Stats',
|
||||||
onclick: () => requireAccess(() => location.href = 'https://chaegeon.com/custom/speedtest/results/stats.php')
|
onclick: () => requireAccess(() => openLauncherTarget('https://chaegeon.com/custom/speedtest/results/stats.php'))
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
async function renderIcons() {
|
async function renderIcons() {
|
||||||
|
if (redirectIfClientLoginBlocked()) return;
|
||||||
|
|
||||||
const session = await getSession();
|
const session = await getSession();
|
||||||
if (session.loginBlocked) {
|
if (session.loginBlocked) {
|
||||||
renderLoginBlocked(session);
|
rememberClientLoginBlocked(session.blockedType, session.blockedMessage);
|
||||||
|
replaceLauncherToChaegeonHome();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,10 +207,13 @@ async function getSession() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function requireAccess(nextAction) {
|
async function requireAccess(nextAction) {
|
||||||
|
if (redirectIfClientLoginBlocked()) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const session = await getSession();
|
const session = await getSession();
|
||||||
if (session.loginBlocked) {
|
if (session.loginBlocked) {
|
||||||
renderLoginBlocked(session);
|
rememberClientLoginBlocked(session.blockedType, session.blockedMessage);
|
||||||
|
replaceLauncherToChaegeonHome();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,6 +227,13 @@ async function requireAccess(nextAction) {
|
|||||||
showPasswordForm(nextAction);
|
showPasswordForm(nextAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function finishPasswordSuccess(onSuccess) {
|
||||||
|
if (typeof onSuccess === 'function') {
|
||||||
|
onSuccess();
|
||||||
|
}
|
||||||
|
await renderIcons();
|
||||||
|
}
|
||||||
|
|
||||||
async function refreshAdminModeIfNeeded() {
|
async function refreshAdminModeIfNeeded() {
|
||||||
if (lastRenderedAdmin !== true) return;
|
if (lastRenderedAdmin !== true) return;
|
||||||
const isAdmin = await hasAdminSession();
|
const isAdmin = await hasAdminSession();
|
||||||
@@ -172,6 +264,8 @@ function renderLoginBlocked(session = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function showPasswordForm(onSuccess) {
|
function showPasswordForm(onSuccess) {
|
||||||
|
if (redirectIfClientLoginBlocked()) return;
|
||||||
|
|
||||||
shortcut.className = 'password-container';
|
shortcut.className = 'password-container';
|
||||||
shortcut.innerHTML = '';
|
shortcut.innerHTML = '';
|
||||||
|
|
||||||
@@ -190,12 +284,16 @@ function showPasswordForm(onSuccess) {
|
|||||||
column.appendChild(inputRow);
|
column.appendChild(inputRow);
|
||||||
shortcut.appendChild(column);
|
shortcut.appendChild(column);
|
||||||
|
|
||||||
|
let submitting = false;
|
||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
|
if (redirectIfClientLoginBlocked()) return;
|
||||||
|
if (submitting) return;
|
||||||
const password = onlyDigits(input.value);
|
const password = onlyDigits(input.value);
|
||||||
input.value = password;
|
input.value = password;
|
||||||
if (password.length !== PIN_LENGTH) return;
|
if (password.length !== PIN_LENGTH) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
submitting = true;
|
||||||
const messageRes = await fetch(`${apiUrl}?failMessages=1`);
|
const messageRes = await fetch(`${apiUrl}?failMessages=1`);
|
||||||
const messagesJson = await messageRes.json();
|
const messagesJson = await messageRes.json();
|
||||||
const failMessages = messagesJson.failMessages || [];
|
const failMessages = messagesJson.failMessages || [];
|
||||||
@@ -208,12 +306,14 @@ function showPasswordForm(onSuccess) {
|
|||||||
});
|
});
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
|
|
||||||
if (res.ok && data.result === 'ok') {
|
if (data.loginBlocked) {
|
||||||
if (typeof onSuccess === 'function') {
|
rememberClientLoginBlocked(data.blockedType, data.blockedMessage);
|
||||||
onSuccess();
|
replaceLauncherToChaegeonHome();
|
||||||
} else {
|
return;
|
||||||
renderIcons();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (res.ok && data.result === 'ok') {
|
||||||
|
await finishPasswordSuccess(onSuccess);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,9 +322,11 @@ function showPasswordForm(onSuccess) {
|
|||||||
failIndex = (failIndex + 1) % Math.max(1, failMessages.length);
|
failIndex = (failIndex + 1) % Math.max(1, failMessages.length);
|
||||||
input.value = '';
|
input.value = '';
|
||||||
input.focus();
|
input.focus();
|
||||||
|
submitting = false;
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
column.appendChild(msg);
|
column.appendChild(msg);
|
||||||
msg.textContent = '요청을 처리하지 못했습니다.';
|
msg.textContent = '요청을 처리하지 못했습니다.';
|
||||||
|
submitting = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user