| Server IP : 188.114.96.3 / Your IP : 216.73.216.143 Web Server : Apache System : Linux sv058.home.net.pl 6.8.2 husak_dirty_pages_fix #1 SMP PREEMPT_DYNAMIC Tue Apr 2 22:06:51 CEST 2024 x86_64 User : ( 3194769) PHP Version : 8.5.12 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /polana/admin/ |
Upload File : |
<?php
declare(strict_types=1);
/**
* POLANA / Google Calendar OAuth diagnostic R1
* Read-only: no OAuth refresh, no schema mutation, no file write.
* Deploy to /admin/ and delete after diagnosis.
*/
require_once dirname(__DIR__) . '/includes/functions.php';
require_once dirname(__DIR__) . '/includes/polana_gcal.php';
require_admin_role();
header('Content-Type: text/html; charset=UTF-8');
header('Cache-Control: no-store, private, max-age=0');
header('X-Robots-Tag: noindex, nofollow');
header('Referrer-Policy: no-referrer');
header('X-Content-Type-Options: nosniff');
function gc_d_h($val): string { return htmlspecialchars((string)$val, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); }
function gc_d_yes(bool $b): string { return $b ? 'TAK' : 'NIE'; }
$checks = [];
$diagnosis = 'Nie ustalono.';
$fields = ['client_id'=>false, 'client_secret'=>false, 'refresh_token'=>false, 'access_token'=>false];
$expiresAt = 0;
$dir = function_exists('pg173_private_dir') ? pg173_private_dir() : dirname(__DIR__, 2) . '/.polana_gcal_private';
$file = $dir . '/oauth.enc';
$keyFile = $dir . '/encryption.key';
$dirOk = is_dir($dir);
$fileOk = is_file($file);
$keyOk = is_file($keyFile);
$checks['Katalog konfiguracji OAuth istnieje'] = gc_d_yes($dirOk);
$checks['Plik zaszyfrowanej konfiguracji istnieje'] = gc_d_yes($fileOk);
$checks['Plik klucza szyfrowania istnieje'] = gc_d_yes($keyOk);
$checks['Klucz i konfiguracja są czytelne dla PHP'] = gc_d_yes(is_readable($file) && is_readable($keyFile));
$checks['OpenSSL dostępny'] = gc_d_yes(function_exists('openssl_decrypt'));
$decrypted = false;
if (!$dirOk) {
$diagnosis = 'Brak katalogu prywatnego dla Google Calendar (nie jest to katalog backupu).';
} elseif (!$fileOk) {
$diagnosis = 'Brakuje oauth.enc — panel nie ma zapisanej konfiguracji Kalendarza.';
} elseif (!$keyOk) {
$diagnosis = 'Brakuje encryption.key — nie twórz nowego klucza, najpierw odtwórz oryginalny.';
} elseif (!is_readable($file) || !is_readable($keyFile)) {
$diagnosis = 'PHP nie ma dostępu do zaszyfrowanej konfiguracji lub klucza.';
} elseif (!function_exists('openssl_decrypt')) {
$diagnosis = 'Brak OpenSSL do odczytu konfiguracji.';
} else {
$key = @file_get_contents($keyFile);
$raw = @file_get_contents($file);
$blob = is_string($raw) ? json_decode($raw, true) : null;
if (!is_string($key) || strlen($key) !== 32) {
$diagnosis = 'Nieprawidłowy rozmiar klucza encryption.key.';
} elseif (!is_array($blob) || !isset($blob['nonce'], $blob['tag'], $blob['cipher'])) {
$diagnosis = 'Nieprawidłowy format oauth.enc.';
} else {
$nonce = base64_decode((string)$blob['nonce'], true);
$tag = base64_decode((string)$blob['tag'], true);
$cipher = base64_decode((string)$blob['cipher'], true);
if ($nonce === false || $tag === false || $cipher === false) {
$diagnosis = 'Błędne kodowanie zaszyfrowanego oauth.enc.';
} else {
// Same authenticated encryption used by includes/polana_gcal.php.
$plaintext = @openssl_decrypt($cipher, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $nonce, $tag, 'polana-gcal-v173');
$data = is_string($plaintext) ? json_decode($plaintext, true) : null;
if (!is_array($data)) {
$diagnosis = 'Konfiguracji nie można odszyfrować. Możliwa zmiana klucza lub uszkodzenie oauth.enc.';
} else {
$decrypted = true;
foreach ($fields as $k=>$_) $fields[$k] = isset($data[$k]) && is_string($data[$k]) && trim($data[$k]) !== '';
$expiresAt = (int)($data['expires_at'] ?? 0);
if (!$fields['client_id'] || !$fields['client_secret']) {
$diagnosis = 'Brakuje Client ID lub Client Secret w zapisanej konfiguracji Kalendarza.';
} elseif (!$fields['refresh_token']) {
$diagnosis = 'Brakuje refresh_token. Panel prawidłowo pokazuje Nie połączono mimo wcześniejszych wydarzeń.';
} else {
$diagnosis = 'Zapis OAuth jest kompletny. Jeśli główny panel pokazuje Nie połączono, porównaj wersję biblioteki i sprawdź cache PHP/OPcache. Nie potwierdzono odpowiedzi API Google.';
}
}
}
}
unset($key, $raw, $blob, $nonce, $tag, $cipher, $plaintext, $data);
}
$checks['Konfiguracja została odszyfrowana'] = gc_d_yes($decrypted);
if ($decrypted) {
foreach ($fields as $k=>$v) $checks['Pole ' . $k . ' jest zapisane (wartość ukryta)'] = gc_d_yes($v);
$checks['Access token ma ważność wg zapisu lokalnego'] = $expiresAt ? ($expiresAt > time() ? 'TAK' : 'WYGASŁ / wygasa') : 'BRAK DATY';
}
try { $checks['Synchronizacja włączona w ustawieniach'] = setting('pg173_enabled','1') === '1' ? 'TAK':'NIE'; }
catch (Throwable $e) { $checks['Synchronizacja włączona w ustawieniach'] = 'Nie udało się odczytać'; }
$events = ['synced'=>0,'error'=>0, 'latest'=>null, 'recent'=>0];
$dbMessage='OK';
try {
$stmt = db()->query("SELECT SUM(CASE WHEN sync_status='synced' THEN 1 ELSE 0 END) AS synced, SUM(CASE WHEN sync_status='error' THEN 1 ELSE 0 END) AS errors, MAX(last_synced_at) AS latest, SUM(CASE WHEN last_synced_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR) THEN 1 ELSE 0 END) AS recent FROM polana_calendar_events");
$row = $stmt->fetch(PDO::FETCH_ASSOC) ?: [];
$events['synced']=(int)($row['synced'] ?? 0);
$events['error']=(int)($row['errors'] ?? 0);
$events['latest']=(string)($row['latest'] ?? '');
$events['recent']=(int)($row['recent'] ?? 0);
} catch (Throwable $e) { $dbMessage = 'Nie można odczytać historii kalendarza (bez zmian w bazie).'; }
?><!doctype html><html lang="pl"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>POLANA — diagnostyka Google Calendar</title><style>body{font:16px/1.55 system-ui,sans-serif;background:#f3f5f0;color:#243629;margin:0;padding:24px}main{max-width:850px;margin:auto;background:#fff;border:1px solid #d5e2d6;border-radius:16px;padding:24px}h1{margin-top:0;font-size:26px}table{width:100%;border-collapse:collapse}td{padding:10px;border-bottom:1px solid #e4e9e4;vertical-align:top}td:last-child{text-align:right;font-weight:650}p.notice{background:#eef4ec;padding:12px;border-radius:10px}small{color:#58695d}a{color:#165f3c}@media(max-width:600px){main{padding:15px}body{padding:10px}td{padding:8px 4px;font-size:13px}}</style></head><body><main><h1>POLANA — diagnostyka połączenia Google Calendar</h1><p>Wyłącznie odczyt. Nie odświeża tokenu, nie zapisuje danych i nie wysyła rezerwacji. Nie wyświetla haseł, tokenów, ścieżek prywatnych ani danych klientów.</p><p class="notice"><strong>Wniosek:</strong> <?=gc_d_h($diagnosis)?></p><h2>Konfiguracja</h2><table><?php foreach($checks as $label=>$value):?><tr><td><?=gc_d_h($label)?></td><td><?=gc_d_h($value)?></td></tr><?php endforeach;?></table><h2>Zapisana historia wydarzeń</h2><table><tr><td>Wcześniej oznaczone jako zsynchronizowane</td><td><?=gc_d_h($events['synced'])?></td></tr><tr><td>Błędy zapisane w tabeli</td><td><?=gc_d_h($events['error'])?></td></tr><tr><td>Ostatnia synchronizacja wg bazy</td><td><?=gc_d_h($events['latest'] ?: 'brak')?></td></tr><tr><td>Wpisy synchronizowane w ciągu ostatnich 24 godzin</td><td><?=gc_d_h($events['recent'])?></td></tr><tr><td>Odczyt bazy</td><td><?=gc_d_h($dbMessage)?></td></tr></table><p><strong>Ważne:</strong> liczba „zsynchronizowane” pochodzi z bazy i nie jest testem aktualnego połączenia Google. Sam obecny refresh token również nie potwierdza, że Google go akceptuje.</p><p><a href="/admin/polana-kalendarz.php">← Powrót do kalendarza</a></p><small>Po skopiowaniu wyników usuń ten jednorazowy plik przez FileZilla.</small></main></body></html>