PWA 나의 찾기 인증 흐름 정리
This commit is contained in:
@@ -38,7 +38,9 @@ Home Assistant에 기록된 Galaxy Z Fold7의 위치, 배터리, 활동 상태,
|
|||||||
|
|
||||||
인증과 Home Assistant 호출은 `/custom/common`을 사용합니다. 브라우저 JS에는 더 이상 API Bearer 토큰이나 Home Assistant 웹훅 식별자를 직접 넣지 않습니다.
|
인증과 Home Assistant 호출은 `/custom/common`을 사용합니다. 브라우저 JS에는 더 이상 API Bearer 토큰이나 Home Assistant 웹훅 식별자를 직접 넣지 않습니다.
|
||||||
|
|
||||||
접근 확인은 JS에서 읽을 수 있는 레거시 쿠키가 아니라 `/custom/launcher/api.php?session=1` 서버 응답으로 처리합니다. 공통 인증 쿠키는 `HttpOnly`이므로 브라우저 스크립트가 직접 읽지 않습니다. 공통 암호로 인증한 일반 쿠키는 30분 유지하고, 사이트 관리자 세션이 확인되면 관리자 장기 쿠키를 발급합니다. 미인증 접근은 현재 화면 안에 `/custom/common/js/auth-pin.js`의 4자리 숫자 PIN 화면을 표시하고, 인증이 끝나면 같은 페이지를 다시 불러옵니다. PWA standalone 여부와 관계없이 같은 세션 확인을 수행합니다.
|
접근 확인은 JS에서 읽을 수 있는 레거시 쿠키가 아니라 `/custom/launcher/api.php?session=1` 서버 응답으로 처리합니다. 공통 인증 쿠키는 `HttpOnly`이므로 브라우저 스크립트가 직접 읽지 않습니다. 공통 암호로 인증한 일반 쿠키는 30분 유지하고, 사이트 관리자 세션이 확인되면 관리자 장기 쿠키를 발급합니다. 미인증 접근은 현재 화면 안에 `/custom/common/js/auth-pin.js`의 4자리 숫자 PIN 화면을 표시하고, 인증이 끝나면 같은 페이지를 다시 불러옵니다.
|
||||||
|
|
||||||
|
PWA standalone으로 진입한 경우에는 설치형 앱 사용성을 우선해 JS 단계의 런처 세션 확인을 생략합니다. API 호출에는 `X-Custom-PWA: findmydevice` 헤더를 붙이고, 서버는 요청 출처가 `chaegeon.com` 계열일 때만 이를 받아들입니다. 일반 브라우저 직접 접근은 기존처럼 공통 인증 또는 PIN 인증을 거쳐야 합니다.
|
||||||
|
|
||||||
표시할 모바일 앱 센서 목록은 `/custom/common/config.php`의 `findmydevice_sensor_sections`에서 섹션 단위로 관리합니다. 화면 CSS 원본은 `/custom/common/css/findmydevice.css`를 사용합니다. 기존 운영 HTML이 `/custom/findmydevice/css/style.css`를 참조해도 호환 파일이 공용 CSS를 import합니다.
|
표시할 모바일 앱 센서 목록은 `/custom/common/config.php`의 `findmydevice_sensor_sections`에서 섹션 단위로 관리합니다. 화면 CSS 원본은 `/custom/common/css/findmydevice.css`를 사용합니다. 기존 운영 HTML이 `/custom/findmydevice/css/style.css`를 참조해도 호환 파일이 공용 CSS를 import합니다.
|
||||||
|
|
||||||
|
|||||||
+11
-3
@@ -466,7 +466,10 @@ const BACK_LINK_PATH_TITLE = {
|
|||||||
'/blog': '블로그',
|
'/blog': '블로그',
|
||||||
};
|
};
|
||||||
const FINDMYDEVICE_AUTH_REQUIRED = location.pathname.startsWith('/findmydevice');
|
const FINDMYDEVICE_AUTH_REQUIRED = location.pathname.startsWith('/findmydevice');
|
||||||
let findmydeviceAuthenticated = !FINDMYDEVICE_AUTH_REQUIRED;
|
function isStandalonePwa() {
|
||||||
|
return window.navigator.standalone || window.matchMedia('(display-mode: standalone)').matches;
|
||||||
|
}
|
||||||
|
let findmydeviceAuthenticated = !FINDMYDEVICE_AUTH_REQUIRED || isStandalonePwa();
|
||||||
|
|
||||||
function renderAuthErrorPage() {
|
function renderAuthErrorPage() {
|
||||||
document.body.innerHTML = `
|
document.body.innerHTML = `
|
||||||
@@ -493,6 +496,7 @@ function renderAuthErrorPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const findmydeviceAuthPromise = FINDMYDEVICE_AUTH_REQUIRED
|
const findmydeviceAuthPromise = FINDMYDEVICE_AUTH_REQUIRED
|
||||||
|
&& !isStandalonePwa()
|
||||||
? fetch('/custom/launcher/api.php?session=1', { credentials: 'same-origin' })
|
? fetch('/custom/launcher/api.php?session=1', { credentials: 'same-origin' })
|
||||||
.then(res => res.ok ? res.json() : Promise.reject())
|
.then(res => res.ok ? res.json() : Promise.reject())
|
||||||
.then(session => {
|
.then(session => {
|
||||||
@@ -2448,7 +2452,8 @@ function fetchDeviceData(includeLang = true, range = null) {
|
|||||||
return fetch(url, {
|
return fetch(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json',
|
||||||
|
...(isStandalonePwa() ? { 'X-Custom-PWA': 'findmydevice' } : {})
|
||||||
},
|
},
|
||||||
credentials: 'same-origin',
|
credentials: 'same-origin',
|
||||||
body: JSON.stringify({})
|
body: JSON.stringify({})
|
||||||
@@ -2508,7 +2513,10 @@ function hasValidCoords(lat, lng) {
|
|||||||
function callDeviceWebhook(name, keepalive = false) {
|
function callDeviceWebhook(name, keepalive = false) {
|
||||||
return fetch('https://chaegeon.com/custom/findmydevice/php/api.php?action=webhook', {
|
return fetch('https://chaegeon.com/custom/findmydevice/php/api.php?action=webhook', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
...(isStandalonePwa() ? { 'X-Custom-PWA': 'findmydevice' } : {})
|
||||||
|
},
|
||||||
credentials: 'same-origin',
|
credentials: 'same-origin',
|
||||||
keepalive,
|
keepalive,
|
||||||
body: JSON.stringify({ name })
|
body: JSON.stringify({ name })
|
||||||
|
|||||||
+42
-1
@@ -18,7 +18,48 @@ if (function_exists('set_time_limit')) {
|
|||||||
@set_time_limit(0);
|
@set_time_limit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
custom_require_auth();
|
function findmydevice_is_pwa_request(): bool
|
||||||
|
{
|
||||||
|
if (($_SERVER['HTTP_X_CUSTOM_PWA'] ?? '') !== 'findmydevice') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$allowedHosts = ['chaegeon.com', 'www.chaegeon.com'];
|
||||||
|
foreach (['HTTP_ORIGIN', 'HTTP_REFERER'] as $key) {
|
||||||
|
$value = (string)($_SERVER[$key] ?? '');
|
||||||
|
if ($value === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$host = parse_url($value, PHP_URL_HOST);
|
||||||
|
if ($host !== null && $host !== false && !in_array(strtolower($host), $allowedHosts, true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findmydevice_require_auth(): void
|
||||||
|
{
|
||||||
|
if (function_exists('custom_has_auth_cookie') && custom_has_auth_cookie()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function_exists('custom_is_site_admin') && custom_is_site_admin()) {
|
||||||
|
if (function_exists('custom_issue_auth_cookie')) {
|
||||||
|
custom_issue_auth_cookie(true);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (findmydevice_is_pwa_request()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
custom_json(['result' => 'unauthorized'], 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
findmydevice_require_auth();
|
||||||
|
|
||||||
$requestData = custom_read_request_data();
|
$requestData = custom_read_request_data();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user