- index.php: schimb code->token cu tratare completa erori, sesiune PHP pentru legare state (CSRF), stocare atomica tokenuri in fisier - pick.php: endpoint polling pentru ROACONT (preluare automata token) - oauth2_tokens mutat in oauth2/tokens/ + .htaccess Require all denied (locatia initiala "extra-docroot" era de fapt in interiorul public_html, deci web-accesibila fara aceasta protectie) - index1.php/index2.php/info.php (versiuni vechi) arhivate in _arhiva_oauth2/ cu .htaccess care blocheaza accesul HTTP Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
63 lines
2.3 KiB
PHP
63 lines
2.3 KiB
PHP
<?php
|
|
// pick.php — Endpoint polling preluare automata token OAuth2 ANAF eFactura
|
|
// Apelat de ROACONT cu POST state=<64 hex>; raspunde JSON:
|
|
// {"status":"pending"} cat timp tokenul nu a sosit (intotdeauna HTTP 200, nu 404),
|
|
// continutul fisierului de token (succes sau eroare ANAF) o SINGURA data, apoi il sterge.
|
|
// Fara session_start() — evita serializarea pe lock-ul de sesiune PHP.
|
|
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
|
|
// Director tokenuri (acelasi ca in index.php) — protejat cu .htaccess
|
|
$tokens_dir = __DIR__ . '/tokens';
|
|
if (!is_dir($tokens_dir)) {
|
|
@mkdir($tokens_dir, 0700, true);
|
|
}
|
|
$tokens_htaccess = $tokens_dir . '/.htaccess';
|
|
if (!file_exists($tokens_htaccess)) {
|
|
@file_put_contents($tokens_htaccess, "Require all denied\n");
|
|
}
|
|
|
|
// Validare stricta format state: 64 caractere [A-Za-z0-9] (protectie path traversal)
|
|
$state = isset($_POST['state']) ? (string)$_POST['state'] : '';
|
|
if (strlen($state) !== 64 || !preg_match('/^[A-Za-z0-9]+$/', $state)) {
|
|
http_response_code(400);
|
|
echo json_encode(['error' => 'invalid_state']);
|
|
exit();
|
|
}
|
|
|
|
// TTL: sterge fisierele de tokenuri (si .tmp orfane) mai vechi de 10 minute
|
|
// (aliniat cu timeout-ul de polling din ROACONT)
|
|
$now = time();
|
|
foreach (array_merge((array)glob($tokens_dir . '/*.json'), (array)glob($tokens_dir . '/*.tmp')) as $f) {
|
|
if (($now - filemtime($f)) > 600) {
|
|
@unlink($f);
|
|
}
|
|
}
|
|
|
|
// Numele fisierului = SHA-256(state): secretul nu apare in listinguri de directoare
|
|
$token_file = $tokens_dir . '/' . hash('sha256', $state) . '.json';
|
|
|
|
if (!file_exists($token_file)) {
|
|
echo json_encode(['status' => 'pending']);
|
|
exit();
|
|
}
|
|
|
|
// Claim atomic prin rename: din doua cereri concurente una singura primeste tokenul,
|
|
// cealalta "pending"; previne si citirea unui JSON partial (index.php scrie .tmp + rename)
|
|
$claim_file = $tokens_dir . '/' . hash('sha256', $state) . '_claim_' . getmypid() . '.json';
|
|
if (!@rename($token_file, $claim_file)) {
|
|
echo json_encode(['status' => 'pending']);
|
|
exit();
|
|
}
|
|
|
|
// Citire INAINTE de stergere; la esec nu stergem (TTL curata fisierul claim ramas)
|
|
$content = file_get_contents($claim_file);
|
|
if ($content === false || $content === '') {
|
|
echo json_encode(['error' => 'read_error']);
|
|
exit();
|
|
}
|
|
@unlink($claim_file);
|
|
|
|
// Continutul JSON exact cum a fost salvat de index.php (tokenuri sau eroare ANAF)
|
|
echo $content;
|