차량 모니터 관리자 쿠키 승격 처리
This commit is contained in:
1 parent
ce9fe85934
commit
f69b9febf4
1 file changed
+90
-13
+90
-13
@@ -888,6 +888,18 @@ function car_monitor_cookie_secret(): string
|
|||||||
return $secret;
|
return $secret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function car_monitor_admin_assertion_secret(): string
|
||||||
|
{
|
||||||
|
global $carSecretConfig;
|
||||||
|
|
||||||
|
$secret = (string)($carSecretConfig['monitor_auth']['admin_assertion_secret'] ?? '');
|
||||||
|
if ($secret === '') {
|
||||||
|
throw new RuntimeException('Car monitor admin assertion secret is missing.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $secret;
|
||||||
|
}
|
||||||
|
|
||||||
function car_monitor_cookie_options(int $expires): array
|
function car_monitor_cookie_options(int $expires): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
@@ -899,47 +911,76 @@ function car_monitor_cookie_options(int $expires): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
function car_monitor_cookie_value(int $expires): string
|
function car_monitor_cookie_value(int $expires, bool $admin = false): string
|
||||||
{
|
{
|
||||||
$body = base64_encode(json_encode([
|
$body = base64_encode(json_encode([
|
||||||
'exp' => $expires,
|
'exp' => $expires,
|
||||||
'iat' => time(),
|
'iat' => time(),
|
||||||
|
'admin' => $admin,
|
||||||
], JSON_UNESCAPED_SLASHES));
|
], JSON_UNESCAPED_SLASHES));
|
||||||
$sig = hash_hmac('sha256', $body, car_monitor_cookie_secret());
|
$sig = hash_hmac('sha256', $body, car_monitor_cookie_secret());
|
||||||
|
|
||||||
return $body . '.' . $sig;
|
return $body . '.' . $sig;
|
||||||
}
|
}
|
||||||
|
|
||||||
function car_monitor_issue_cookie(): void
|
function car_monitor_issue_cookie(bool $admin = false): void
|
||||||
{
|
{
|
||||||
$expires = time() + CAR_MONITOR_AUTH_TTL;
|
$expires = time() + CAR_MONITOR_AUTH_TTL;
|
||||||
setcookie(CAR_MONITOR_COOKIE, car_monitor_cookie_value($expires), car_monitor_cookie_options($expires));
|
setcookie(CAR_MONITOR_COOKIE, car_monitor_cookie_value($expires, $admin), car_monitor_cookie_options($expires));
|
||||||
}
|
}
|
||||||
|
|
||||||
function car_monitor_has_cookie(): bool
|
function car_monitor_cookie_payload(): ?array
|
||||||
{
|
{
|
||||||
$cookie = $_COOKIE[CAR_MONITOR_COOKIE] ?? '';
|
$cookie = $_COOKIE[CAR_MONITOR_COOKIE] ?? '';
|
||||||
if (!is_string($cookie) || strpos($cookie, '.') === false) {
|
if (!is_string($cookie) || strpos($cookie, '.') === false) {
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
[$body, $sig] = explode('.', $cookie, 2);
|
[$body, $sig] = explode('.', $cookie, 2);
|
||||||
$expected = hash_hmac('sha256', $body, car_monitor_cookie_secret());
|
$expected = hash_hmac('sha256', $body, car_monitor_cookie_secret());
|
||||||
if (!hash_equals($expected, $sig)) {
|
if (!hash_equals($expected, $sig)) {
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$decoded = base64_decode($body, true);
|
$decoded = base64_decode($body, true);
|
||||||
if ($decoded === false) {
|
if ($decoded === false) {
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$payload = json_decode($decoded, true);
|
$payload = json_decode($decoded, true);
|
||||||
if (!is_array($payload)) {
|
if (!is_array($payload)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int)($payload['exp'] ?? 0) >= time() ? $payload : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function car_monitor_has_cookie(): bool
|
||||||
|
{
|
||||||
|
return is_array(car_monitor_cookie_payload());
|
||||||
|
}
|
||||||
|
|
||||||
|
function car_monitor_verify_admin_assertion(string $assertion): bool
|
||||||
|
{
|
||||||
|
if (strpos($assertion, '.') === false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (int)($payload['exp'] ?? 0) >= time();
|
[$body, $sig] = explode('.', $assertion, 2);
|
||||||
|
$expected = hash_hmac('sha256', $body, car_monitor_admin_assertion_secret());
|
||||||
|
if (!hash_equals($expected, $sig)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$decoded = base64_decode($body, true);
|
||||||
|
$payload = $decoded !== false ? json_decode($decoded, true) : null;
|
||||||
|
if (!is_array($payload)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($payload['aud'] ?? '') === 'car-monitor'
|
||||||
|
&& !empty($payload['admin'])
|
||||||
|
&& (int)($payload['exp'] ?? 0) >= time();
|
||||||
}
|
}
|
||||||
|
|
||||||
function car_monitor_launcher_session(): array
|
function car_monitor_launcher_session(): array
|
||||||
@@ -954,21 +995,22 @@ function car_monitor_launcher_session(): array
|
|||||||
if ($cookieHeader !== '') {
|
if ($cookieHeader !== '') {
|
||||||
$adminSession = car_monitor_launcher_api_request('GET', 'https://chaegeon.com/custom/launcher/api.php?adminSession=1', null, $cookieHeader);
|
$adminSession = car_monitor_launcher_api_request('GET', 'https://chaegeon.com/custom/launcher/api.php?adminSession=1', null, $cookieHeader);
|
||||||
if (is_array($adminSession) && !empty($adminSession['authenticated']) && !empty($adminSession['admin'])) {
|
if (is_array($adminSession) && !empty($adminSession['authenticated']) && !empty($adminSession['admin'])) {
|
||||||
car_monitor_issue_cookie();
|
car_monitor_issue_cookie(true);
|
||||||
$session = ['authenticated' => true, 'admin' => true];
|
$session = ['authenticated' => true, 'admin' => true];
|
||||||
return $session;
|
return $session;
|
||||||
}
|
}
|
||||||
|
|
||||||
$remoteSession = car_monitor_launcher_api_request('GET', 'https://chaegeon.com/custom/launcher/api.php?session=1', null, $cookieHeader);
|
$remoteSession = car_monitor_launcher_api_request('GET', 'https://chaegeon.com/custom/launcher/api.php?session=1', null, $cookieHeader);
|
||||||
if (is_array($remoteSession) && !empty($remoteSession['authenticated'])) {
|
if (is_array($remoteSession) && !empty($remoteSession['authenticated'])) {
|
||||||
car_monitor_issue_cookie();
|
car_monitor_issue_cookie(!empty($remoteSession['admin']));
|
||||||
$session = $remoteSession;
|
$session = $remoteSession;
|
||||||
return $session;
|
return $session;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (car_monitor_has_cookie()) {
|
$cookiePayload = car_monitor_cookie_payload();
|
||||||
$session = ['authenticated' => true, 'admin' => false];
|
if (is_array($cookiePayload)) {
|
||||||
|
$session = ['authenticated' => true, 'admin' => !empty($cookiePayload['admin'])];
|
||||||
return $session;
|
return $session;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1132,10 +1174,37 @@ function car_monitor_auth_api(): void
|
|||||||
json_response(['result' => 'fail'], 401);
|
json_response(['result' => 'fail'], 401);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function car_monitor_admin_assert_api(): void
|
||||||
|
{
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
|
json_response(['error' => 'method_not_allowed'], 405);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = request_payload();
|
||||||
|
$assertion = (string)($data['assertion'] ?? '');
|
||||||
|
if (!car_monitor_verify_admin_assertion($assertion)) {
|
||||||
|
json_response([
|
||||||
|
'status' => 'forbidden',
|
||||||
|
'message' => '관리자 권한이 필요합니다.',
|
||||||
|
], 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
car_monitor_issue_cookie(true);
|
||||||
|
json_response([
|
||||||
|
'status' => 'success',
|
||||||
|
'authenticated' => true,
|
||||||
|
'admin' => true,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($_GET['mode']) && $_GET['mode'] === 'auth-login') {
|
if (isset($_GET['mode']) && $_GET['mode'] === 'auth-login') {
|
||||||
car_monitor_auth_api();
|
car_monitor_auth_api();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($_GET['mode']) && $_GET['mode'] === 'admin-assert') {
|
||||||
|
car_monitor_admin_assert_api();
|
||||||
|
}
|
||||||
|
|
||||||
car_monitor_issue_pwa_cookie_if_requested();
|
car_monitor_issue_pwa_cookie_if_requested();
|
||||||
|
|
||||||
if (isset($_GET['mode']) && $_GET['mode'] === 'ajax') {
|
if (isset($_GET['mode']) && $_GET['mode'] === 'ajax') {
|
||||||
@@ -2954,7 +3023,15 @@ $carMonitorSession = car_monitor_launcher_session();
|
|||||||
cache: 'no-store',
|
cache: 'no-store',
|
||||||
});
|
});
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
if (res.ok && data?.authenticated && data?.admin) {
|
if (res.ok && data?.authenticated && data?.admin && data?.assertion) {
|
||||||
|
const localRes = await fetch('?mode=admin-assert', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
cache: 'no-store',
|
||||||
|
body: JSON.stringify({ assertion: data.assertion }),
|
||||||
|
});
|
||||||
|
if (!localRes.ok) return;
|
||||||
|
|
||||||
CAR_MONITOR_SESSION = { ...CAR_MONITOR_SESSION, authenticated: true, admin: true };
|
CAR_MONITOR_SESSION = { ...CAR_MONITOR_SESSION, authenticated: true, admin: true };
|
||||||
showCalibrationSettings();
|
showCalibrationSettings();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user