fix(vikon): DNS bypass, OAuth callback, ABITUR init, token cache, ZIP security

- Add CURLOPT_RESOLVE DNS bypass for db-nica.ru / file.db-nica.ru
- Add OAuth callback route with CSRF state validation
- Add /authorize endpoint to generate OAuth URL with state
- Add ABITUR special case: init empty module core without ZIP download
- Add token validation caching (150s) to reduce API calls
- Block PHP/PHTML/PHAR files inside ZIP before extraction
- Add VikonTokenRefresh middleware for auto token refresh
- Add vikon.refresh middleware alias to Kernel
This commit is contained in:
F4ilji
2026-07-04 17:44:50 +05:00
parent 93721fc5ae
commit 3dc29d44d8
8 changed files with 159 additions and 3 deletions
@@ -29,6 +29,11 @@ class UpdateCoreAction
try {
Log::info('Vikon: downloading module core', ['module' => $moduleId]);
if ($moduleId === 2) {
return $this->initAbiturModule($modulePath, $accessToken);
}
$zipContent = $this->http->downloadWithToken(
'pull_updates/generateEmptyModuleCore/' . $moduleId,
$accessToken
@@ -79,12 +84,22 @@ class UpdateCoreAction
}
$realDest = realpath($destination);
$blocked = ['php', 'phtml', 'php5', 'php7', 'php8', 'phar'];
for ($i = 0; $i < $zip->numFiles; $i++) {
$name = $zip->getNameIndex($i);
if (str_contains($name, '..')) {
$zip->close();
throw new \RuntimeException("Zip Slip: {$name}");
}
$ext = strtolower(pathinfo($name, PATHINFO_EXTENSION));
if (in_array($ext, $blocked, true)) {
$zip->close();
throw new \RuntimeException("Blocked executable: {$name}");
}
$full = realpath($realDest . '/' . $name);
if ($full !== false && !str_starts_with($full, $realDest)) {
$zip->close();
@@ -157,4 +172,28 @@ class UpdateCoreAction
}
}
}
private function initAbiturModule(string $modulePath, string $accessToken): string
{
$response = $this->http->getWithToken(
'pull_updates/generateEmptyModuleCore/2',
$accessToken
);
$body = $response->json();
if (!isset($body['success']) || $body['success'] !== true) {
throw new \RuntimeException('ABITUR init failed: ' . ($body['message'] ?? 'Unknown error'));
}
if (!File::isDirectory($modulePath)) {
File::makeDirectory($modulePath, 0755, true, true);
}
if (!File::isDirectory($modulePath . '/files')) {
File::makeDirectory($modulePath . '/files', 0755, true, true);
}
File::put($modulePath . '/.vikon', date('Y-m-d H:i:s'));
Log::info('Vikon: ABITUR module initialized');
return 'Модуль "Абитуриент" инициализирован.';
}
}