From 0afee4a018e826bbea3df7f2f26252c607fa6af5 Mon Sep 17 00:00:00 2001 From: seo Date: Thu, 2 Jul 2026 13:13:53 +0900 Subject: [PATCH] =?UTF-8?q?=EC=A7=81=EC=A0=91=20=EC=A0=91=EA=B7=BC=20PIN?= =?UTF-8?q?=20=EC=9D=B8=EC=A6=9D=20=ED=99=94=EB=A9=B4=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 ++ monitor.php | 62 +++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 53 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index e635713..bc0febb 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ Car는 차량 모뎀/게이트웨이에서 받은 상태를 수집해 DB에 저 - `monitor.php?mode=ajax`: monitor 상태 AJAX - `monitor.php?mode=usage`: 데이터 사용량 AJAX - `monitor.php?mode=usage-calibration`: 관리자 전용 데이터 사용량 보정 기준점 조회/저장 +- `monitor.php?mode=auth-login`: 브라우저 직접 접근 비밀번호 화면용 공통 암호 검증 ## Monitor 경과 시간 @@ -120,6 +121,7 @@ Worker 교체나 예외 종료로 `processing`, `ui_timeout_pending` 상태가 - 차량 모니터 화면과 `monitor.php?mode=ajax`, `monitor.php?mode=usage`는 런처 공통 인증 쿠키 또는 사이트 관리자 세션이 유효할 때만 응답합니다. - 공통 암호로 로그인한 일반 인증은 30분 유지하고, 사이트 관리자 세션이 확인되면 관리자 장기 쿠키를 발급해 PWA에서 반복 인증이 뜨는 일을 줄입니다. - 런처 공통 인증은 우선 공통 인증 모듈로 직접 확인합니다. 공통 모듈을 사용할 수 없는 경우에만 `https://chaegeon.com/custom/launcher/api.php?session=1` 응답으로 확인합니다. +- 브라우저로 직접 접근했는데 인증이 없으면 채건닷컴으로 보내지 않고 `/custom/common/js/auth-pin.js`의 4자리 숫자 PIN 화면을 표시합니다. 차량 모니터는 `seo.chaegeon.com`에서 동작하므로 화면 입력값을 `monitor.php?mode=auth-login`으로 보내 공통 암호를 검증하고, 인증이 끝나면 차량 모니터를 다시 불러옵니다. - 차량 모니터의 브라우저 화면 인증은 런처/나의 찾기와 같은 공통 쿠키를 사용하지만, 차량 단말이 호출하는 `api.php` 인증은 API token과 허용 IP 정책을 사용하는 별도 경로입니다. - 차량 제어 명령은 허용된 명령 코드로 제한합니다. - Secret 파일은 저장소 밖에서 제한된 권한으로 유지합니다. diff --git a/monitor.php b/monitor.php index 68a0d38..0c6d480 100644 --- a/monitor.php +++ b/monitor.php @@ -956,26 +956,66 @@ function car_monitor_require_access(bool $json = false): void 차량 모니터 인증 - + -
-

인증이 필요합니다

- +
+
+ + 'fail', 'message' => 'auth_module_missing'], 500); + } + require_once $commonAuth; + + if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['failMessages'])) { + json_response(['failMessages' => ['비밀번호가 틀립니다.']]); + } + + if ($_SERVER['REQUEST_METHOD'] !== 'POST') { + json_response(['error' => 'method_not_allowed'], 405); + } + + $data = request_payload(); + $password = (string)($data['password'] ?? ''); + if (preg_match('/^\d{4}$/', $password) !== 1) { + json_response(['result' => 'fail', 'message' => 'password_digits_only'], 401); + } + + if (function_exists('custom_verify_password') && custom_verify_password($password)) { + custom_issue_auth_cookie(false); + json_response(['result' => 'ok']); + } + + json_response(['result' => 'fail'], 401); +} + +if (isset($_GET['mode']) && $_GET['mode'] === 'auth-login') { + car_monitor_auth_api(); +} + if (isset($_GET['mode']) && $_GET['mode'] === 'ajax') { car_monitor_require_access(true);