Require signed PWA auth for findmydevice
This commit is contained in:
1 parent
1ba8c257a3
commit
76f9c7c549
3 files changed
+346
-56
No files matched your search
+91
-28
@@ -18,33 +18,24 @@ if (function_exists('set_time_limit')) {
|
||||
@set_time_limit(0);
|
||||
}
|
||||
|
||||
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_block_login_denied')) {
|
||||
custom_block_login_denied(true);
|
||||
}
|
||||
|
||||
if (function_exists('custom_has_auth_cookie') && custom_has_auth_cookie()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
($_SERVER['HTTP_X_CUSTOM_PWA'] ?? '') === 'findmydevice'
|
||||
&& function_exists('custom_has_pwa_auth_cookie')
|
||||
&& custom_has_pwa_auth_cookie('findmydevice')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (function_exists('custom_is_site_admin') && custom_is_site_admin()) {
|
||||
if (function_exists('custom_issue_auth_cookie')) {
|
||||
custom_issue_auth_cookie(true);
|
||||
@@ -52,10 +43,6 @@ function findmydevice_require_auth(): void
|
||||
return;
|
||||
}
|
||||
|
||||
if (findmydevice_is_pwa_request()) {
|
||||
return;
|
||||
}
|
||||
|
||||
custom_json(['result' => 'unauthorized'], 401);
|
||||
}
|
||||
|
||||
@@ -503,8 +490,6 @@ if ($startParam && $endParam) {
|
||||
$endTime = (new DateTime())->setTimezone(new DateTimeZone('UTC'))->format($haFormat);
|
||||
}
|
||||
|
||||
// API URL 생성
|
||||
$historyEndpoint = "/history/period/{$startTime}?filter_entity_id=" . rawurlencode($entities['device']) . "&end_time={$endTime}";
|
||||
$includeHistory = isset($_GET['history']) && $_GET['history'] === '1' && !isset($_GET['hashonly']);
|
||||
|
||||
// 공통 요청 함수
|
||||
@@ -545,6 +530,39 @@ function findmydevice_starts_with(string $value, string $prefix): bool
|
||||
{
|
||||
return strncmp($value, $prefix, strlen($prefix)) === 0;
|
||||
}
|
||||
function findmydevice_watch_pair_key(string $key): ?string
|
||||
{
|
||||
if (!findmydevice_starts_with($key, 'watch') || strlen($key) <= 5) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return lcfirst(substr($key, 5));
|
||||
}
|
||||
|
||||
function findmydevice_pair_watch_sensor_rows(array $rows): array
|
||||
{
|
||||
$ordered = [];
|
||||
foreach ($rows as $key => $value) {
|
||||
if (findmydevice_watch_pair_key((string)$key) !== null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$ordered[$key] = $value;
|
||||
$watchKey = 'watch' . ucfirst((string)$key);
|
||||
if (array_key_exists($watchKey, $rows)) {
|
||||
$ordered[$watchKey] = $rows[$watchKey];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($rows as $key => $value) {
|
||||
if (!array_key_exists($key, $ordered)) {
|
||||
$ordered[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $ordered;
|
||||
}
|
||||
|
||||
|
||||
function readableTriggerCode(string $value, string $lang): string
|
||||
{
|
||||
@@ -674,11 +692,39 @@ function formatSensorValue($value, $definition, $lang, $maps) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
function findmydevice_history_endpoints(string $startTime, string $endTime, string $entityId): array
|
||||
{
|
||||
$start = DateTimeImmutable::createFromFormat('!Y-m-d\TH:i:s\Z', $startTime, new DateTimeZone('UTC'));
|
||||
$end = DateTimeImmutable::createFromFormat('!Y-m-d\TH:i:s\Z', $endTime, new DateTimeZone('UTC'));
|
||||
if (!$start || !$end || $end <= $start) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$endpoints = [];
|
||||
$cursor = $start;
|
||||
$chunkInterval = new DateInterval('P1D');
|
||||
while ($cursor < $end) {
|
||||
$chunkEnd = $cursor->add($chunkInterval);
|
||||
if ($chunkEnd > $end) {
|
||||
$chunkEnd = $end;
|
||||
}
|
||||
|
||||
$chunkStartText = $cursor->format('Y-m-d\TH:i:s\Z');
|
||||
$chunkEndText = $chunkEnd->format('Y-m-d\TH:i:s\Z');
|
||||
$endpoints[] = "/history/period/{$chunkStartText}?filter_entity_id=" . rawurlencode($entityId) . "&end_time={$chunkEndText}";
|
||||
$cursor = $chunkEnd;
|
||||
}
|
||||
|
||||
return $endpoints;
|
||||
}
|
||||
|
||||
// 데이터 불러오기
|
||||
$deviceData = getData($deviceUrl);
|
||||
$geoData = getData($geoUrl);
|
||||
$batteryStateData = getData($batteryStateUrl);
|
||||
$batteryLevelData = getData($batteryLevelUrl);
|
||||
$watchBatteryStateData = getEntityData($entities, 'watch_battery_state');
|
||||
$watchBatteryLevelData = getEntityData($entities, 'watch_battery_level');
|
||||
$activityData = getData($activityUrl);
|
||||
$connectionData = getData($connectionUrl);
|
||||
$ascendedData = getData($fascendedUrl);
|
||||
@@ -688,8 +734,16 @@ $distanceData = getData($distanceUrl);
|
||||
$highAccuracyModeData = getData($highAccuracyModeUrl);
|
||||
$historySets = [];
|
||||
if ($includeHistory) {
|
||||
$historyEndpoints = findmydevice_history_endpoints($startTime, $endTime, $entities['device']);
|
||||
foreach ($findmydeviceHaProfiles as $profile) {
|
||||
$historySets[(string)$profile] = custom_ha_request((string)$profile, 'GET', $historyEndpoint, null, 0) ?? [];
|
||||
$profileHistory = [[]];
|
||||
foreach ($historyEndpoints as $historyEndpoint) {
|
||||
$historyData = custom_ha_request((string)$profile, 'GET', $historyEndpoint, null, 0) ?? [];
|
||||
if (isset($historyData[0]) && is_array($historyData[0])) {
|
||||
$profileHistory[0] = array_merge($profileHistory[0], $historyData[0]);
|
||||
}
|
||||
}
|
||||
$historySets[(string)$profile] = $profileHistory;
|
||||
}
|
||||
}
|
||||
$triggerData = getData($triggerUrl);
|
||||
@@ -1240,6 +1294,9 @@ $activityState = $activityData['state'] ?? null;
|
||||
$aaccuracyState = $activityData['attributes']['Confidence'] ?? $activityData['attributes']['confidence'] ?? null;
|
||||
$connectionState = $connectionData['state'] ?? null;
|
||||
$batteryState = $batteryStateData['state'] ?? null;
|
||||
$watchBatteryState = stateValue($watchBatteryStateData);
|
||||
$watchBatteryLevel = stateValue($watchBatteryLevelData);
|
||||
$watchBatteryText = $batteryStateMap[$lang][$watchBatteryState] ?? $watchBatteryState ?? null;
|
||||
$highAccuracyMode = strtolower((string)($highAccuracyModeData['state'] ?? '')) === 'on';
|
||||
|
||||
$address = null;
|
||||
@@ -1277,6 +1334,8 @@ foreach (($config['findmydevice_sensor_sections'] ?? []) as $sectionKey => $defi
|
||||
}
|
||||
if (!$sensorSections[$sectionKey]) {
|
||||
unset($sensorSections[$sectionKey]);
|
||||
} else {
|
||||
$sensorSections[$sectionKey] = findmydevice_pair_watch_sensor_rows($sensorSections[$sectionKey]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1291,6 +1350,8 @@ if (isset($_GET['hashonly']) && $_GET['hashonly'] == '1') {
|
||||
'address' => $address,
|
||||
'state' => $batteryStateMap[$lang][$batteryState] ?? $batteryState ?? null,
|
||||
'level' => $batteryLevelData['state'] ?? null,
|
||||
'wstate' => $watchBatteryText,
|
||||
'wlevel' => $watchBatteryLevel,
|
||||
'ascended' => $ascendedData['state'] ?? null,
|
||||
'descended' => $descendedData['state'] ?? null,
|
||||
'steps' => $stepsData['state'] ?? null,
|
||||
@@ -1317,6 +1378,8 @@ echo json_encode([
|
||||
'address' => $address,
|
||||
'state' => $batteryStateMap[$lang][$batteryState] ?? $batteryState ?? null,
|
||||
'level' => $batteryLevelData['state'] ?? null,
|
||||
'wstate' => $watchBatteryText,
|
||||
'wlevel' => $watchBatteryLevel,
|
||||
'ascended' => $ascendedData['state'] ?? null,
|
||||
'descended' => $descendedData['state'] ?? null,
|
||||
'steps' => $stepsData['state'] ?? null,
|
||||
|
||||
Reference in new issue
Block a user