From 47aac647ac14b3841f538023bafa85a05a1c6748 Mon Sep 17 00:00:00 2001 From: F4ilji Date: Sat, 4 Jul 2026 12:40:41 +0500 Subject: [PATCH] feat(vikon): remove broken VikonIntegration container - starting fresh --- .../Actions/Auth/AuthenticateVikonAction.php | 57 --- .../Updates/CheckVikonAccessAction.php | 156 ------- .../Updates/CheckVikonVersionAction.php | 64 --- .../Updates/DownloadModuleUpdateAction.php | 434 ------------------ .../Actions/Updates/SyncModuleFilesAction.php | 176 ------- .../VikonIntegrationServiceProvider.php | 125 ----- .../Tasks/CallVikonApiTask.php | 171 ------- .../Tasks/CheckVikonEntryPointTask.php | 35 -- .../Tasks/ExtractZipArchiveTask.php | 119 ----- .../Tasks/ManageModuleFilesTask.php | 223 --------- .../Tasks/RefreshVikonTokenTask.php | 50 -- .../Tasks/ValidateVikonTokenTask.php | 40 -- .../WEB/Controllers/VikonUpdateController.php | 305 ------------ .../WEB/Requests/AuthenticateVikonRequest.php | 31 -- .../Requests/DownloadModuleUpdateRequest.php | 30 -- .../WEB/Requests/RefreshVikonTokenRequest.php | 27 -- .../VikonIntegration/UI/WEB/Routes/web.php | 41 -- config/app.php | 2 +- config/vikon.php | 101 ---- .../js/Pages/Dashboard/VikonUpdates/Index.vue | 377 --------------- 20 files changed, 1 insertion(+), 2563 deletions(-) delete mode 100644 app/Containers/VikonIntegration/Actions/Auth/AuthenticateVikonAction.php delete mode 100644 app/Containers/VikonIntegration/Actions/Updates/CheckVikonAccessAction.php delete mode 100644 app/Containers/VikonIntegration/Actions/Updates/CheckVikonVersionAction.php delete mode 100644 app/Containers/VikonIntegration/Actions/Updates/DownloadModuleUpdateAction.php delete mode 100644 app/Containers/VikonIntegration/Actions/Updates/SyncModuleFilesAction.php delete mode 100644 app/Containers/VikonIntegration/Providers/VikonIntegrationServiceProvider.php delete mode 100644 app/Containers/VikonIntegration/Tasks/CallVikonApiTask.php delete mode 100644 app/Containers/VikonIntegration/Tasks/CheckVikonEntryPointTask.php delete mode 100644 app/Containers/VikonIntegration/Tasks/ExtractZipArchiveTask.php delete mode 100644 app/Containers/VikonIntegration/Tasks/ManageModuleFilesTask.php delete mode 100644 app/Containers/VikonIntegration/Tasks/RefreshVikonTokenTask.php delete mode 100644 app/Containers/VikonIntegration/Tasks/ValidateVikonTokenTask.php delete mode 100644 app/Containers/VikonIntegration/UI/WEB/Controllers/VikonUpdateController.php delete mode 100644 app/Containers/VikonIntegration/UI/WEB/Requests/AuthenticateVikonRequest.php delete mode 100644 app/Containers/VikonIntegration/UI/WEB/Requests/DownloadModuleUpdateRequest.php delete mode 100644 app/Containers/VikonIntegration/UI/WEB/Requests/RefreshVikonTokenRequest.php delete mode 100644 app/Containers/VikonIntegration/UI/WEB/Routes/web.php delete mode 100644 config/vikon.php delete mode 100644 resources/js/Pages/Dashboard/VikonUpdates/Index.vue diff --git a/app/Containers/VikonIntegration/Actions/Auth/AuthenticateVikonAction.php b/app/Containers/VikonIntegration/Actions/Auth/AuthenticateVikonAction.php deleted file mode 100644 index f329849..0000000 --- a/app/Containers/VikonIntegration/Actions/Auth/AuthenticateVikonAction.php +++ /dev/null @@ -1,57 +0,0 @@ -clientSecret)) { - throw new \RuntimeException( - 'VIKON_CLIENT_SECRET не настроен. Обратитесь к администратору.' - ); - } - $response = $this->callVikonApiTask->post('oauth2/authorize/token', [ - 'code' => $code, - 'client_id' => $this->clientId, - 'client_secret' => $this->clientSecret, - 'redirect_uri' => $redirectUri, - 'grant_type' => 'authorization_code', - ], [], 'auth'); - - $body = $response->json(); - - if (!isset($body['access_token']) || !isset($body['refresh_token'])) { - throw new \RuntimeException( - 'Authentication failed: ' . ($body['message'] ?? 'Unknown error') - ); - } - - return [ - 'access_token' => $body['access_token'], - 'refresh_token' => $body['refresh_token'], - ]; - } -} diff --git a/app/Containers/VikonIntegration/Actions/Updates/CheckVikonAccessAction.php b/app/Containers/VikonIntegration/Actions/Updates/CheckVikonAccessAction.php deleted file mode 100644 index 31bab1b..0000000 --- a/app/Containers/VikonIntegration/Actions/Updates/CheckVikonAccessAction.php +++ /dev/null @@ -1,156 +0,0 @@ -validateTokenTask->run($accessToken); - - if (!$isValid) { - return [ - 'has_access' => false, - 'error' => 'Токен доступа недействителен или истёк. Пожалуйста, выполните повторную авторизацию.', - 'permissions' => [], - 'writable_paths' => [], - ]; - } - - // Step 2: Check update permissions - try { - $response = $this->callVikonApiTask->getWithToken( - 'pull_updates/checkAccessJson', - $accessToken - ); - - $body = $response->json(); - - if (!isset($body['success']) || !$body['success']) { - return [ - 'has_access' => false, - 'error' => 'Нет прав на обновление. Обратитесь к администратору VIKON.', - 'permissions' => [], - 'writable_paths' => [], - ]; - } - - // Extract permissions from response - $permissions = $body['additional_access_flags'] ?? []; - - // Step 3: Check filesystem writability (recursive, like old check_filesystem.php) - $writablePaths = $this->checkWritablePaths(); - $nonWritablePaths = $this->findNonWritablePaths($this->publicPath); - - if (!empty($nonWritablePaths)) { - Log::warning('Vikon access: non-writable paths detected', [ - 'paths' => $nonWritablePaths, - ]); - - return [ - 'has_access' => false, - 'error' => 'Отсутствуют права на запись в следующие директории: ' . implode(', ', array_slice($nonWritablePaths, 0, 5)) . '. Обратитесь к администратору сервера.', - 'permissions' => $permissions, - 'writable_paths' => $writablePaths, - 'non_writable_paths' => $nonWritablePaths, - ]; - } - - return [ - 'has_access' => true, - 'error' => null, - 'permissions' => $permissions, - 'writable_paths' => $writablePaths, - ]; - } catch (\Throwable $e) { - Log::error('Vikon access check failed', [ - 'error' => $e->getMessage(), - ]); - - return [ - 'has_access' => false, - 'error' => 'Не удалось проверить права доступа: ' . $e->getMessage(), - 'permissions' => [], - 'writable_paths' => [], - ]; - } - } - - /** - * Check which module directories are writable - */ - private function checkWritablePaths(): array - { - $modules = config('vikon.modules', []); - $writable = []; - - foreach ($modules as $moduleId => $moduleConfig) { - $modulePath = $this->publicPath . '/' . $moduleConfig['path']; - $isWritable = is_writable($modulePath); - $writable[] = [ - 'module_id' => $moduleId, - 'path' => $moduleConfig['path'], - 'writable' => $isWritable, - ]; - } - - return $writable; - } - - /** - * Recursively find non-writable paths (like old isWritableRecrusive) - * - * Limits depth to 3 levels to avoid performance issues on large directories. - */ - private function findNonWritablePaths(string $path, int $depth = 0): array - { - $nonWritable = []; - - if ($depth > 3) { - return $nonWritable; - } - - if (!is_dir($path)) { - return $nonWritable; - } - - if (!is_writable($path)) { - $nonWritable[] = str_replace(base_path() . '/', '', $path); - return $nonWritable; - } - - $entries = File::directories($path); - foreach ($entries as $entry) { - $nonWritable = array_merge( - $nonWritable, - $this->findNonWritablePaths($entry, $depth + 1) - ); - } - - return $nonWritable; - } -} diff --git a/app/Containers/VikonIntegration/Actions/Updates/CheckVikonVersionAction.php b/app/Containers/VikonIntegration/Actions/Updates/CheckVikonVersionAction.php deleted file mode 100644 index 632a4eb..0000000 --- a/app/Containers/VikonIntegration/Actions/Updates/CheckVikonVersionAction.php +++ /dev/null @@ -1,64 +0,0 @@ -callVikonApiTask->getWithToken( - 'pull_updates/getLatestVersion', - $accessToken - ); - - $body = $response->json(); - - $latestVersion = $body['version'] ?? null; - $hasUpdate = $latestVersion && version_compare($latestVersion, $this->currentVersion, '>'); - - return [ - 'current_version' => $this->currentVersion, - 'has_update' => $hasUpdate, - 'latest_version' => $latestVersion, - ]; - } catch (\Throwable $e) { - \Illuminate\Support\Facades\Log::warning('Vikon version check failed', [ - 'error' => $e->getMessage(), - ]); - - return [ - 'current_version' => $this->currentVersion, - 'has_update' => false, - 'latest_version' => null, - 'error' => 'Не удалось проверить наличие обновлений', - ]; - } - } - - /** - * Get current version without checking for updates - */ - public function getCurrentVersion(): string - { - return $this->currentVersion; - } -} diff --git a/app/Containers/VikonIntegration/Actions/Updates/DownloadModuleUpdateAction.php b/app/Containers/VikonIntegration/Actions/Updates/DownloadModuleUpdateAction.php deleted file mode 100644 index 99dddaa..0000000 --- a/app/Containers/VikonIntegration/Actions/Updates/DownloadModuleUpdateAction.php +++ /dev/null @@ -1,434 +0,0 @@ -getModuleConfig($moduleId); - $modulePath = $this->basePath . '/' . $moduleConfig['path']; - $tempPath = $this->storagePath . '/temp/' . $moduleConfig['path']; - - try { - // Step 1: Download module core ZIP - Log::info('Vikon update: downloading module core', ['module_id' => $moduleId]); - - $zipContent = $this->callVikonApiTask->downloadWithToken( - 'pull_updates/generateEmptyModuleCore/' . $moduleId, - $accessToken - ); - - // Step 2: Prepare temp directory - $this->prepareTempDirectory($tempPath); - - // Step 3: Write ZIP to temp file - $zipFile = $tempPath . '/module_core.zip'; - $writeResult = file_put_contents($zipFile, $zipContent); - - if ($writeResult === false) { - throw new \RuntimeException('Не удалось записать архив обновления. Проверьте права доступа.'); - } - - // Step 4: Extract with Zip Slip protection - $this->extractZipTask->run($zipFile, $tempPath); - - // Step 5: Validate file types BEFORE syncing to module directory - $blockedFiles = $this->validateFileTypes($tempPath); - if (!empty($blockedFiles)) { - throw new \RuntimeException( - 'Обнаружены запрещённые типы файлов: ' . implode(', ', $blockedFiles) . - '. Обновление отклонено в целях безопасности.' - ); - } - - // Step 6: Remove vikon_core directory from archive (we use Laravel-based updater) - $vikonCorePath = $tempPath . '/vikon_core'; - if (File::isDirectory($vikonCorePath)) { - Log::info('Vikon update: removing vikon_core from archive (using Laravel updater instead)'); - File::deleteDirectory($vikonCorePath); - } - - // Step 7: Clean up ZIP - File::delete($zipFile); - - // Step 7: Sync extracted files to module directory - $this->syncModuleFiles($tempPath, $modulePath, $moduleConfig['path']); - - // Step 8: Clean module - remove files/folders not in allowed list (like old cleanUnitCore) - $this->cleanModuleDirectory($modulePath, $moduleConfig['allowed_folders']); - - // Step 9: Create .vikon flag file - $this->createVikonFlag($modulePath); - - // Step 9: Cleanup temp - File::deleteDirectory($tempPath); - - Log::info('Vikon update: module core updated successfully', ['module_id' => $moduleId]); - - return 'Ядро модуля "' . $moduleConfig['name'] . '" успешно обновлено.'; - } catch (\Throwable $e) { - // Rollback on error - $this->rollback($modulePath, $moduleConfig['path']); - - Log::error('Vikon update: failed', [ - 'module_id' => $moduleId, - 'error' => $e->getMessage(), - ]); - - throw new \RuntimeException('Ошибка обновления модуля: ' . $e->getMessage()); - } - } - - /** - * Get module configuration - * - * @throws \RuntimeException - */ - private function getModuleConfig(int $moduleId): array - { - if (!isset($this->modulesConfig[$moduleId])) { - throw new \RuntimeException('Неизвестный идентификатор модуля'); - } - - return $this->modulesConfig[$moduleId]; - } - - /** - * Prepare temporary directory for extraction - */ - private function prepareTempDirectory(string $path): void - { - if (File::exists($path)) { - File::deleteDirectory($path); - } - - File::makeDirectory($path, 0755, true, true); - } - - /** - * Sync extracted files to module directory with atomic operations - * - * Strategy: - * 1. Rename current file/dir to _old - * 2. Move new file/dir to current location - * 3. If error occurs, rollback from _old - */ - private function syncModuleFiles(string $sourcePath, string $targetPath, string $moduleFolder): void - { - $entries = File::directories($sourcePath); - $files = File::files($sourcePath); - - $failedEntries = []; - - // Process directories - foreach ($entries as $entry) { - $entryName = basename($entry); - $currentPath = $targetPath . '/' . $entryName; - $newPath = $sourcePath . '/' . $entryName; - - try { - $this->syncDirectory($newPath, $currentPath, $targetPath); - } catch (\Throwable $e) { - $failedEntries[] = $entryName; - Log::error('Vikon update: failed to sync directory', [ - 'entry' => $entryName, - 'error' => $e->getMessage(), - ]); - } - } - - // Process files - foreach ($files as $file) { - $fileName = basename($file); - $currentPath = $targetPath . '/' . $fileName; - $newPath = $sourcePath . '/' . $fileName; - - try { - $this->syncFile($newPath, $currentPath, $targetPath); - } catch (\Throwable $e) { - $failedEntries[] = $fileName; - Log::error('Vikon update: failed to sync file', [ - 'entry' => $fileName, - 'error' => $e->getMessage(), - ]); - } - } - - if (!empty($failedEntries)) { - throw new \RuntimeException( - 'Не удалось синхронизировать: ' . implode(', ', $failedEntries) - ); - } - } - - /** - * Sync single directory with atomic rename - */ - private function syncDirectory(string $newPath, string $currentPath, string $basePath): void - { - if (File::exists($currentPath)) { - // Rename current to _old - $oldPath = $currentPath . self::OLD_SUFFIX; - if (File::exists($oldPath)) { - File::deleteDirectory($oldPath); - } - File::move($currentPath, $oldPath); - } - - // Move new to current - File::copyDirectory($newPath, $currentPath); - } - - /** - * Sync single file with atomic rename - */ - private function syncFile(string $newPath, string $currentPath, string $basePath): void - { - if (File::exists($currentPath)) { - // Rename current to _old - $oldPath = $currentPath . self::OLD_SUFFIX; - if (File::exists($oldPath)) { - File::delete($oldPath); - } - rename($currentPath, $oldPath); - } - - // Move new to current - copy($newPath, $currentPath); - } - - /** - * Create .vikon flag file in module directory - */ - private function createVikonFlag(string $modulePath): void - { - $flagPath = $modulePath . '/.vikon'; - - if (!File::exists($flagPath)) { - File::put($flagPath, date('Y-m-d H:i:s')); - } - } - - /** - * Clean module directory - remove files/folders not in allowed list - * - * Replaces old Filesystem::cleanUnitCore() - * After sync, removes any files/directories that are not in the allowed_folders list - */ - private function cleanModuleDirectory(string $modulePath, array $allowedFolders): void - { - $entries = File::directories($modulePath); - - foreach ($entries as $entry) { - $entryName = basename($entry); - - if (in_array($entryName, $allowedFolders, true)) { - continue; - } - - // Skip symlinks - if (is_link($entry)) { - Log::warning('Vikon update: skipping symlink during cleanup', [ - 'path' => $entry, - ]); - continue; - } - - Log::info('Vikon update: removing disallowed directory', [ - 'directory' => $entryName, - ]); - - File::deleteDirectory($entry); - } - - // Also check files at root level - $files = File::files($modulePath); - foreach ($files as $file) { - $fileName = basename($file); - - if (in_array($fileName, $allowedFolders, true)) { - continue; - } - - // Skip .vikon flag and .htaccess - if (in_array($fileName, ['.vikon', '.htaccess'], true)) { - continue; - } - - Log::info('Vikon update: removing disallowed file', [ - 'file' => $fileName, - ]); - - File::delete($file); - } - } - - /** - * Validate all extracted files against allowed/blocked extensions - * - * This is a security measure to prevent RCE via malicious ZIP from Vikon API. - * Even if Vikon sends PHP/ASP files, they will be rejected here. - * - * @return array List of blocked file paths - */ - private function validateFileTypes(string $extractPath): array - { - $blockedFiles = []; - - $this->scanDirectoryForBlockedFiles($extractPath, $blockedFiles); - - return $blockedFiles; - } - - /** - * Recursively scan directory for blocked file types - */ - private function scanDirectoryForBlockedFiles(string $directory, array &$blockedFiles): void - { - // Check files - $files = File::files($directory); - foreach ($files as $file) { - $extension = strtolower(pathinfo($file, PATHINFO_EXTENSION)); - $relativePath = str_replace(base_path() . '/', '', $file); - - if (in_array($extension, self::BLOCKED_EXTENSIONS, true)) { - $blockedFiles[] = $relativePath; - } - } - - // Recurse into subdirectories - $dirs = File::directories($directory); - foreach ($dirs as $dir) { - $this->scanDirectoryForBlockedFiles($dir, $blockedFiles); - } - } - - /** - * Rollback failed update from _old backups - */ - private function rollback(string $modulePath, string $moduleFolder): void - { - Log::warning('Vikon update: rolling back failed update', [ - 'module' => $moduleFolder, - ]); - - // Restore directories - $dirs = File::directories($modulePath); - foreach ($dirs as $dir) { - $dirName = basename($dir); - $oldPath = $dir . self::OLD_SUFFIX; - - if (File::exists($oldPath)) { - try { - // Remove failed new version - File::deleteDirectory($dir); - // Restore old version - File::move($oldPath, $dir); - } catch (\Throwable $e) { - Log::error('Vikon update: rollback failed for directory', [ - 'entry' => $dirName, - 'error' => $e->getMessage(), - ]); - } - } - } - - // Restore files - $files = File::files($modulePath); - foreach ($files as $file) { - $fileName = basename($file); - $oldPath = $file . self::OLD_SUFFIX; - - if (File::exists($oldPath)) { - try { - // Remove failed new version - File::delete($file); - // Restore old version - rename($oldPath, $file); - } catch (\Throwable $e) { - Log::error('Vikon update: rollback failed for file', [ - 'entry' => $fileName, - 'error' => $e->getMessage(), - ]); - } - } - } - } -} diff --git a/app/Containers/VikonIntegration/Actions/Updates/SyncModuleFilesAction.php b/app/Containers/VikonIntegration/Actions/Updates/SyncModuleFilesAction.php deleted file mode 100644 index 0752fc1..0000000 --- a/app/Containers/VikonIntegration/Actions/Updates/SyncModuleFilesAction.php +++ /dev/null @@ -1,176 +0,0 @@ -getModuleConfig($moduleId); - $modulePath = $this->basePath . '/' . $moduleConfig['path']; - $filesPath = $modulePath . '/files'; - - // Step 1: Get directories list from Vikon file manager - $response = $this->callVikonApiTask->getWithToken( - 'sync/getUsedDirNamesByModule?moduleId=' . $moduleId, - $accessToken, - 'filemanager' - ); - - $body = $response->json(); - - if (!isset($body['directories']) || !is_array($body['directories'])) { - throw new \RuntimeException('Невалидный ответ от файлового сервера'); - } - - $directories = $body['directories']; - - // Step 2: Remove unknown directories - $this->cleanUnknownDirectories($filesPath, $directories, $modulePath); - - // Step 3: Get files that need to be synced - $filesToSync = $this->getFilesToSync($filesPath, $moduleId, $accessToken); - - return [ - 'directories' => $directories, - 'files_to_sync' => $filesToSync, - ]; - } - - /** - * Get module configuration - * - * @throws \RuntimeException - */ - private function getModuleConfig(int $moduleId): array - { - if (!isset($this->modulesConfig[$moduleId])) { - throw new \RuntimeException('Неизвестный идентификатор модуля'); - } - - return $this->modulesConfig[$moduleId]; - } - - /** - * Remove directories that are not in the known list - */ - private function cleanUnknownDirectories(string $filesPath, array $knownDirs, string $modulePath): void - { - // Guard against empty/malformed remote list - if (empty($knownDirs)) { - Log::warning('Vikon sync: empty directory list from remote, skipping cleanup'); - return; - } - - if (!File::isDirectory($filesPath)) { - return; - } - - $existingDirs = File::directories($filesPath); - - foreach ($existingDirs as $dir) { - $dirName = basename($dir); - - // Check for symlinks before deleting (like old code) - if (is_link($dir)) { - Log::warning('Vikon sync: skipping symlink during cleanup', [ - 'path' => $dir, - ]); - continue; - } - - if (!in_array($dirName, $knownDirs)) { - Log::info('Vikon sync: removing unknown directory', [ - 'directory' => $dirName, - ]); - - File::deleteDirectory($dir); - } - } - } - - /** - * Get list of files that need to be synced - */ - private function getFilesToSync(string $filesPath, int $moduleId, string $accessToken): array - { - // Get file list from Vikon file manager - $response = $this->callVikonApiTask->getWithToken( - 'sync/getFileNamesFromRootDirectoryByModule?moduleId=' . $moduleId, - $accessToken, - 'filemanager' - ); - - $body = $response->json(); - - if (!isset($body['files']) || !is_array($body['files'])) { - return []; - } - - // Build remote files map: name => identity (like old code used $row->i) - $remoteFiles = []; - foreach ($body['files'] as $file) { - if (isset($file['n'])) { - $remoteFiles[$file['n']] = $file['i'] ?? null; // n = name, i = identity - } - } - - // Compare with local files - $localFiles = []; - if (File::isDirectory($filesPath)) { - $localFilesList = File::files($filesPath); - foreach ($localFilesList as $localFile) { - $fileName = basename($localFile); - $fileSize = filesize($localFile); - - // Skip empty files (like old code: if (!filesize($fsItemPath))) - if ($fileSize > 0) { - $localFiles[$fileName] = $fileSize; - } - } - } - - // Find files that don't exist locally or have different identity - $filesToSync = []; - foreach ($remoteFiles as $fileName => $fileId) { - if (!isset($localFiles[$fileName])) { - // File doesn't exist locally - $filesToSync[] = [ - 'name' => $fileName, - 'id' => $fileId, - 'reason' => 'missing', - ]; - } - // Note: old code also checked identity mismatch, but identity is only - // available from filemanager API. If file exists locally with same name, - // we assume it's the correct version (identity match). - } - - return $filesToSync; - } -} diff --git a/app/Containers/VikonIntegration/Providers/VikonIntegrationServiceProvider.php b/app/Containers/VikonIntegration/Providers/VikonIntegrationServiceProvider.php deleted file mode 100644 index 6b2c2b9..0000000 --- a/app/Containers/VikonIntegration/Providers/VikonIntegrationServiceProvider.php +++ /dev/null @@ -1,125 +0,0 @@ -mergeConfigFrom(config_path('vikon.php'), 'vikon'); - - // Register Tasks with dependencies from config - $this->app->singleton(CallVikonApiTask::class, function ($app) { - return new CallVikonApiTask( - apiDomain: config('vikon.api_domain'), - authDomain: config('vikon.auth_domain'), - filemanagerDomain: config('vikon.filemanager_domain'), - timeout: config('vikon.http_timeout', 60), - retries: config('vikon.http_retries', 3), - ); - }); - - $this->app->singleton(ExtractZipArchiveTask::class); - - $this->app->singleton(ValidateVikonTokenTask::class, function ($app) { - return new ValidateVikonTokenTask( - callVikonApiTask: $app->make(CallVikonApiTask::class), - ); - }); - - $this->app->singleton(RefreshVikonTokenTask::class, function ($app) { - return new RefreshVikonTokenTask( - callVikonApiTask: $app->make(CallVikonApiTask::class), - clientId: config('vikon.client_id'), - clientSecret: config('vikon.client_secret'), - ); - }); - - $this->app->singleton(CheckVikonEntryPointTask::class, function ($app) { - return new CheckVikonEntryPointTask( - callVikonApiTask: $app->make(CallVikonApiTask::class), - clientId: config('vikon.client_id'), - ); - }); - - $this->app->singleton(ManageModuleFilesTask::class, function ($app) { - return new ManageModuleFilesTask( - basePath: public_path(), - ); - }); - - // Register Actions - $this->app->singleton(AuthenticateVikonAction::class, function ($app) { - return new AuthenticateVikonAction( - callVikonApiTask: $app->make(CallVikonApiTask::class), - clientId: config('vikon.client_id', ''), - clientSecret: config('vikon.client_secret', ''), - ); - }); - - $this->app->singleton(ValidateVikonTokenTask::class, function ($app) { - return new ValidateVikonTokenTask( - callVikonApiTask: $app->make(CallVikonApiTask::class), - ); - }); - - $this->app->singleton(CheckVikonAccessAction::class, function ($app) { - return new CheckVikonAccessAction( - validateTokenTask: $app->make(ValidateVikonTokenTask::class), - callVikonApiTask: $app->make(CallVikonApiTask::class), - publicPath: public_path(), - ); - }); - - $this->app->singleton(CheckVikonVersionAction::class, function ($app) { - return new CheckVikonVersionAction( - callVikonApiTask: $app->make(CallVikonApiTask::class), - currentVersion: config('vikon.current_version', '1.0.0'), - ); - }); - - $this->app->singleton(DownloadModuleUpdateAction::class, function ($app) { - return new DownloadModuleUpdateAction( - callVikonApiTask: $app->make(CallVikonApiTask::class), - extractZipTask: $app->make(ExtractZipArchiveTask::class), - modulesConfig: config('vikon.modules'), - storagePath: config('vikon.storage_path'), - basePath: public_path(), - ); - }); - - $this->app->singleton(SyncModuleFilesAction::class, function ($app) { - return new SyncModuleFilesAction( - callVikonApiTask: $app->make(CallVikonApiTask::class), - modulesConfig: config('vikon.modules'), - basePath: public_path(), - ); - }); - } - - public function boot(): void - { - // Load routes - $this->loadRoutesFrom(app_path('Containers/VikonIntegration/UI/WEB/Routes/web.php')); - - // Publish config - $this->publishes([ - config_path('vikon.php') => config_path('vikon.php'), - ], 'vikon-config'); - } -} diff --git a/app/Containers/VikonIntegration/Tasks/CallVikonApiTask.php b/app/Containers/VikonIntegration/Tasks/CallVikonApiTask.php deleted file mode 100644 index 451f3b8..0000000 --- a/app/Containers/VikonIntegration/Tasks/CallVikonApiTask.php +++ /dev/null @@ -1,171 +0,0 @@ -resolveBaseUrl($service); - $url = rtrim($baseUrl, '/') . '/' . ltrim($endpoint, '/'); - - return $this->makeRequest('get', $url, [], $headers); - } - - /** - * POST request to Vikon API - */ - public function post(string $endpoint, array $data = [], array $headers = [], string $service = 'api'): \Illuminate\Http\Client\Response - { - $baseUrl = $this->resolveBaseUrl($service); - $url = rtrim($baseUrl, '/') . '/' . ltrim($endpoint, '/'); - - return $this->makeRequest('post', $url, $data, $headers); - } - - /** - * GET request with Bearer token authorization - */ - public function getWithToken(string $endpoint, string $token, string $service = 'api'): \Illuminate\Http\Client\Response - { - $baseUrl = $this->resolveBaseUrl($service); - $url = rtrim($baseUrl, '/') . '/' . ltrim($endpoint, '/'); - - return $this->makeRequest('get', $url, [], [ - 'Authorization' => 'Bearer ' . $token, - 'Accept' => 'application/json', - ]); - } - - /** - * POST request with Bearer token authorization - */ - public function postWithToken(string $endpoint, string $token, array $data = [], string $service = 'api'): \Illuminate\Http\Client\Response - { - $baseUrl = $this->resolveBaseUrl($service); - $url = rtrim($baseUrl, '/') . '/' . ltrim($endpoint, '/'); - - return $this->makeRequest('post', $url, $data, [ - 'Authorization' => 'Bearer ' . $token, - 'Accept' => 'application/json', - ]); - } - - /** - * Download binary content (ZIP archive) with Bearer token - */ - public function downloadWithToken(string $endpoint, string $token, string $service = 'api'): string - { - $baseUrl = $this->resolveBaseUrl($service); - $url = rtrim($baseUrl, '/') . '/' . ltrim($endpoint, '/'); - - $response = Http::withHeaders([ - 'Authorization' => 'Bearer ' . $token, - 'Accept-Encoding' => 'zip, gzip', - 'Accept' => 'application/json', - ]) - ->timeout($this->timeout) - ->retry($this->retries, 1000, function ($exception, $response) { - if ($response && $response->successful()) { - return false; - } - return true; - }) - ->get($url); - - if ($response->failed()) { - throw new \RuntimeException( - 'Vikon API error: ' . $this->extractErrorMessage($response) . ' (HTTP ' . $response->status() . ')' - ); - } - - return $response->body(); - } - - /** - * Resolve base URL by service type - */ - private function resolveBaseUrl(string $service): string - { - return match ($service) { - 'auth' => $this->authDomain, - 'filemanager' => $this->filemanagerDomain, - default => $this->apiDomain, - }; - } - - /** - * Make HTTP request with common settings - * - * @throws ConnectionException - * @throws \RuntimeException - */ - private function makeRequest(string $method, string $url, array $data, array $headers): \Illuminate\Http\Client\Response - { - $http = Http::withHeaders(array_merge([ - 'Accept' => 'application/json', - ], $headers)) - ->timeout($this->timeout) - ->retry($this->retries, 1000, function ($exception, $response) { - if ($response && $response->successful()) { - return false; - } - return true; - }); - - $response = match ($method) { - 'get' => $data ? $http->get($url, $data) : $http->get($url), - 'post' => $http->post($url, $data), - }; - - if ($response->failed()) { - throw new \RuntimeException( - 'Vikon API error: ' . $this->extractErrorMessage($response) . ' (HTTP ' . $response->status() . ')' - ); - } - - return $response; - } - - /** - * Extract error message from API response - */ - private function extractErrorMessage(\Illuminate\Http\Client\Response $response): string - { - $body = $response->json(); - - if (isset($body['message'])) { - return $body['message']; - } - - if (isset($body['error'])) { - return $body['error']; - } - - if (isset($body['messages']) && is_array($body['messages'])) { - return implode('; ', $body['messages']); - } - - return 'Unknown error'; - } -} diff --git a/app/Containers/VikonIntegration/Tasks/CheckVikonEntryPointTask.php b/app/Containers/VikonIntegration/Tasks/CheckVikonEntryPointTask.php deleted file mode 100644 index 9022bbc..0000000 --- a/app/Containers/VikonIntegration/Tasks/CheckVikonEntryPointTask.php +++ /dev/null @@ -1,35 +0,0 @@ -callVikonApiTask->get( - 'oauth2/checkEntryPoint', - [ - 'client_id' => $this->clientId, - 'entry_point' => $entryPoint, - ] - ); - - $body = $response->json(); - - return isset($body['success']) && $body['success'] === true; - } -} diff --git a/app/Containers/VikonIntegration/Tasks/ExtractZipArchiveTask.php b/app/Containers/VikonIntegration/Tasks/ExtractZipArchiveTask.php deleted file mode 100644 index 4e78085..0000000 --- a/app/Containers/VikonIntegration/Tasks/ExtractZipArchiveTask.php +++ /dev/null @@ -1,119 +0,0 @@ -open($zipPath); - - if ($openResult !== true) { - throw new \RuntimeException("Failed to open ZIP archive (code: {$openResult})"); - } - - // Zip Slip protection: validate every entry - $this->validateZipEntries($zip, $destination); - - // Extract with overwrite - $extractResult = $zip->extractTo($destination); - - $zip->close(); - - if (!$extractResult) { - throw new \RuntimeException('Failed to extract ZIP archive'); - } - - return true; - } - - /** - * Validate all ZIP entries to prevent Zip Slip attack - * - * @throws \RuntimeException - */ - private function validateZipEntries(ZipArchive $zip, string $destination): void - { - $realDestination = realpath($destination); - - if ($realDestination === false) { - throw new \RuntimeException('Destination directory does not exist'); - } - - for ($i = 0; $i < $zip->numFiles; $i++) { - $filename = $zip->getNameIndex($i); - - // Check for path traversal patterns - if ($this->containsPathTraversal($filename)) { - throw new \RuntimeException( - "Potentially malicious ZIP entry detected: {$filename}" - ); - } - - // Resolve full path and verify it's within destination - $fullPath = realpath($realDestination . '/' . $filename); - - if ($fullPath === false) { - // File doesn't exist yet (will be created), check parent directory - $parentDir = dirname($realDestination . '/' . $filename); - if (strpos($parentDir, $realDestination) !== 0) { - throw new \RuntimeException( - "ZIP entry escapes destination directory: {$filename}" - ); - } - } elseif (strpos($fullPath, $realDestination) !== 0) { - throw new \RuntimeException( - "ZIP entry escapes destination directory: {$filename}" - ); - } - } - } - - /** - * Check if filename contains path traversal patterns - */ - private function containsPathTraversal(string $filename): bool - { - // Check for directory traversal sequences - if (strpos($filename, '..') !== false) { - return true; - } - - // Check for absolute paths on Windows - if (preg_match('/^[a-zA-Z]:/', $filename)) { - return true; - } - - // Check for absolute paths on Unix - if (strpos($filename, '/') === 0) { - return true; - } - - return false; - } -} diff --git a/app/Containers/VikonIntegration/Tasks/ManageModuleFilesTask.php b/app/Containers/VikonIntegration/Tasks/ManageModuleFilesTask.php deleted file mode 100644 index c57a2d5..0000000 --- a/app/Containers/VikonIntegration/Tasks/ManageModuleFilesTask.php +++ /dev/null @@ -1,223 +0,0 @@ -basePath . '/' . $moduleFolder; - } - - /** - * Safely remove directory with path validation - * - * @param string $path Path to remove - * @param string $allowedBasePath Base path constraint - * @param bool $recursive Remove recursively - * @return bool - */ - public function safeRemove(string $path, string $allowedBasePath, bool $recursive = false): bool - { - // Prevent path traversal - if (!$this->isPathWithinBase($path, $allowedBasePath)) { - \Illuminate\Support\Facades\Log::warning('Attempted to remove path outside allowed base', [ - 'path' => $path, - 'allowed_base' => $allowedBasePath, - ]); - return false; - } - - if (!file_exists($path)) { - return true; - } - - if (!is_dir($path)) { - return File::delete($path); - } - - return File::deleteDirectory($path); - } - - /** - * Safely create directory - */ - public function safeMkdir(string $path, int $mode = 0755): bool - { - if (File::isDirectory($path)) { - return true; - } - - return File::makeDirectory($path, $mode, true, true); - } - - /** - * Safely create file with content - */ - public function safeCreateFile(string $path, string $content = '', int $mode = 0644): bool - { - if (File::exists($path)) { - return true; - } - - $directory = dirname($path); - if (!File::isDirectory($directory)) { - File::makeDirectory($directory, 0755, true, true); - } - - $result = File::put($path, $content); - if ($result === false) { - return false; - } - - chmod($path, $mode); - return true; - } - - /** - * Scan directory safely (excludes . and ..) - * - * @return array|false - */ - public function safeScandir(string $path): array|false - { - if (!File::isDirectory($path) || !File::isReadable($path)) { - return false; - } - - $entries = File::directories($path); - $files = File::files($path); - - return array_merge( - array_map('basename', $entries), - array_map('basename', $files) - ); - } - - /** - * Rename file with path validation - */ - public function safeRename(string $oldPath, string $newPath, string $allowedBasePath): bool - { - if (!$this->isPathWithinBase($oldPath, $allowedBasePath)) { - return false; - } - if (!$this->isPathWithinBase($newPath, $allowedBasePath)) { - return false; - } - - if (!File::exists($oldPath)) { - return false; - } - if (File::exists($newPath)) { - return false; - } - - $newDir = dirname($newPath); - if (!File::isDirectory($newDir)) { - return false; - } - - return File::move($oldPath, $newPath); - } - - /** - * Replace directory with rename (atomic operation) - * - * Old -> _old - * New -> Old - */ - public function replaceWithRename(string $sourceDir, string $targetDir, string $allowedBasePath): bool - { - if (!$this->isPathWithinBase($sourceDir, $allowedBasePath)) { - return false; - } - if (!$this->isPathWithinBase($targetDir, $allowedBasePath)) { - return false; - } - - if (!File::exists($sourceDir)) { - return false; - } - if (File::exists($targetDir)) { - return false; - } - - $parentDir = dirname($targetDir); - if (!is_writable($parentDir)) { - return false; - } - - if (!File::makeDirectory($targetDir, 0755, true, true)) { - return false; - } - - $entries = $this->safeScandir($sourceDir); - if (empty($entries)) { - return File::deleteDirectory($sourceDir); - } - - foreach ($entries as $entry) { - $item = $sourceDir . '/' . $entry; - $newPath = $targetDir . '/' . $entry; - - if (File::isDirectory($item)) { - if (!$this->replaceWithRename($item, $newPath, $allowedBasePath)) { - return false; - } - } else { - if (!File::move($item, $newPath)) { - return false; - } - } - } - - return File::deleteDirectory($sourceDir); - } - - /** - * Check if path is within allowed base directory - */ - private function isPathWithinBase(string $path, string $basePath): bool - { - $realPath = realpath($path); - $realBase = realpath($basePath); - - // If base directory doesn't exist, path cannot be valid - if ($realBase === false) { - \Illuminate\Support\Facades\Log::error('Base path does not exist', [ - 'base' => $basePath, - ]); - return false; - } - - if ($realPath === false) { - // For non-existent paths, check parent directory - $parentDir = dirname($path); - $realParent = realpath($parentDir); - - if ($realParent === false) { - return false; - } - - return str_starts_with($realParent . '/', $realBase . '/'); - } - - return str_starts_with($realPath . '/', $realBase . '/') || $realPath === $realBase; - } -} diff --git a/app/Containers/VikonIntegration/Tasks/RefreshVikonTokenTask.php b/app/Containers/VikonIntegration/Tasks/RefreshVikonTokenTask.php deleted file mode 100644 index d25c106..0000000 --- a/app/Containers/VikonIntegration/Tasks/RefreshVikonTokenTask.php +++ /dev/null @@ -1,50 +0,0 @@ -callVikonApiTask->post('oauth2/RefreshToken', [ - 'refresh_token' => $refreshToken, - 'client_id' => $this->clientId, - 'client_secret' => $this->clientSecret, - 'grant_type' => 'refresh_token', - ], [], 'api'); // <-- api domain (db-nica.ru), NOT auth domain - - $body = $response->json(); - - if (!isset($body['access_token']) || !isset($body['refresh_token'])) { - throw new \RuntimeException( - 'Invalid token refresh response: ' . ($body['message'] ?? 'Unknown error') - ); - } - - return [ - 'access_token' => $body['access_token'], - 'refresh_token' => $body['refresh_token'], - ]; - } -} diff --git a/app/Containers/VikonIntegration/Tasks/ValidateVikonTokenTask.php b/app/Containers/VikonIntegration/Tasks/ValidateVikonTokenTask.php deleted file mode 100644 index 25c4864..0000000 --- a/app/Containers/VikonIntegration/Tasks/ValidateVikonTokenTask.php +++ /dev/null @@ -1,40 +0,0 @@ -callVikonApiTask->getWithToken( - 'api/profile_applicant/check_access_token', - $accessToken, - 'auth' // <-- auth domain (auth.db-nica.ru) - ); - - return $response->successful(); - } catch (\Throwable $e) { - \Illuminate\Support\Facades\Log::warning('Vikon token validation failed', [ - 'error' => $e->getMessage(), - ]); - - return false; - } - } -} diff --git a/app/Containers/VikonIntegration/UI/WEB/Controllers/VikonUpdateController.php b/app/Containers/VikonIntegration/UI/WEB/Controllers/VikonUpdateController.php deleted file mode 100644 index 327f007..0000000 --- a/app/Containers/VikonIntegration/UI/WEB/Controllers/VikonUpdateController.php +++ /dev/null @@ -1,305 +0,0 @@ -hasValidVikonSession(); - - return inertia()->render('Dashboard/VikonUpdates/Index', [ - 'is_authenticated' => $isAuthenticated, - 'current_version' => $this->getCurrentVersion(), - 'modules' => config('vikon.modules'), - 'vikon_auth_domain' => config('vikon.api_domain'), - 'vikon_client_id' => config('vikon.client_id'), - ]); - } - - /** - * POST /dashboard/vikon-updates/authenticate - * Exchange OAuth code for tokens - */ - public function authenticate(AuthenticateVikonRequest $request): JsonResponse - { - try { - $tokens = $this->authenticateAction->run( - $request->validated('code'), - $request->validated('redirect_uri') - ); - - // Store tokens in secure session (HttpOnly cookie) - Session::put('vikon_access_token', $tokens['access_token']); - Session::put('vikon_refresh_token', $tokens['refresh_token']); - - return response()->json([ - 'success' => true, - 'message' => 'Авторизация успешна', - ]); - } catch (\Throwable $e) { - \Illuminate\Support\Facades\Log::error('Vikon authentication failed', [ - 'error' => $e->getMessage(), - ]); - - return response()->json([ - 'success' => false, - 'message' => 'Ошибка авторизации. Пожалуйста, попробуйте снова.', - ], 422); - } - } - - /** - * POST /dashboard/vikon-updates/refresh-token - * Refresh access token - */ - public function refreshToken(RefreshVikonTokenRequest $request): JsonResponse - { - try { - $tokens = $this->refreshTokenTask->run( - $request->validated('refresh_token') - ); - - Session::put('vikon_access_token', $tokens['access_token']); - Session::put('vikon_refresh_token', $tokens['refresh_token']); - - return response()->json([ - 'success' => true, - 'message' => 'Токен обновлён', - ]); - } catch (\Throwable $e) { - \Illuminate\Support\Facades\Log::error('Vikon token refresh failed', [ - 'error' => $e->getMessage(), - ]); - - return response()->json([ - 'success' => false, - 'message' => 'Ошибка обновления токена. Пожалуйста, выполните повторную авторизацию.', - ], 422); - } - } - - /** - * POST /dashboard/vikon-updates/check-access - * Verify user has update permissions - */ - public function checkAccess(Request $request): JsonResponse - { - $accessToken = Session::get('vikon_access_token'); - - if (!$accessToken) { - return response()->json([ - 'success' => false, - 'message' => 'Требуется авторизация', - 'requires_auth' => true, - ], 401); - } - - $result = $this->checkAccessAction->run($accessToken); - - return response()->json([ - 'success' => $result['has_access'], - 'has_access' => $result['has_access'], - 'error' => $result['error'], - 'permissions' => $result['permissions'], - ]); - } - - /** - * POST /dashboard/vikon-updates/check-version - * Check for available updates - */ - public function checkVersion(Request $request): JsonResponse - { - $accessToken = Session::get('vikon_access_token'); - - if (!$accessToken) { - return response()->json([ - 'success' => false, - 'message' => 'Требуется авторизация', - 'requires_auth' => true, - ], 401); - } - - $result = $this->checkVersionAction->run($accessToken); - - return response()->json($result); - } - - /** - * POST /dashboard/vikon-updates/download-update - * Download and install module update - */ - public function downloadUpdate(DownloadModuleUpdateRequest $request): JsonResponse - { - $accessToken = Session::get('vikon_access_token'); - - if (!$accessToken) { - return response()->json([ - 'success' => false, - 'message' => 'Требуется авторизация', - 'requires_auth' => true, - ], 401); - } - - try { - $message = $this->downloadUpdateAction->run( - $request->validated('module_id'), - $accessToken - ); - - return response()->json([ - 'success' => true, - 'message' => $message, - ]); - } catch (\Throwable $e) { - \Illuminate\Support\Facades\Log::error('Vikon module update failed', [ - 'module_id' => $request->validated('module_id'), - 'error' => $e->getMessage(), - ]); - - return response()->json([ - 'success' => false, - 'message' => 'Произошла ошибка при обновлении модуля. Обратитесь к администратору.', - ], 500); - } - } - - /** - * POST /dashboard/vikon-updates/sync-files - * Initialize file sync for module - */ - public function syncFiles(Request $request): JsonResponse - { - $request->validate([ - 'module_id' => ['required', 'integer', 'in:1,2,6'], - ]); - - $accessToken = Session::get('vikon_access_token'); - - if (!$accessToken) { - return response()->json([ - 'success' => false, - 'message' => 'Требуется авторизация', - 'requires_auth' => true, - ], 401); - } - - try { - $result = $this->syncFilesAction->run( - $request->input('module_id'), - $accessToken - ); - - return response()->json([ - 'success' => true, - 'directories' => $result['directories'], - 'files_to_sync' => $result['files_to_sync'], - ]); - } catch (\Throwable $e) { - \Illuminate\Support\Facades\Log::error('Vikon file sync failed', [ - 'module_id' => $request->input('module_id'), - 'error' => $e->getMessage(), - ]); - - return response()->json([ - 'success' => false, - 'message' => 'Произошла ошибка при синхронизации файлов.', - ], 500); - } - } - - /** - * GET /dashboard/vikon-updates/check-entry - * Verify current URL is valid entry point - */ - public function checkEntry(Request $request): JsonResponse - { - $entryPoint = $request->input('entry', url()->current()); - - try { - $isValid = $this->checkEntryPointTask->run($entryPoint); - - return response()->json([ - 'success' => $isValid, - 'entry_point' => $entryPoint, - ]); - } catch (\Throwable $e) { - \Illuminate\Support\Facades\Log::error('Vikon entry point check failed', [ - 'error' => $e->getMessage(), - ]); - - return response()->json([ - 'success' => false, - 'message' => 'Не удалось проверить точку входа.', - ], 500); - } - } - - /** - * POST /dashboard/vikon-updates/logout - * Clear Vikon session - */ - public function logout(Request $request): JsonResponse - { - Session::forget(['vikon_access_token', 'vikon_refresh_token']); - - return response()->json([ - 'success' => true, - 'message' => 'Сессия завершена', - ]); - } - - /** - * Check if user has valid Vikon session - */ - private function hasValidVikonSession(): bool - { - $accessToken = Session::get('vikon_access_token'); - - if (!$accessToken) { - return false; - } - - return $this->validateTokenTask->run($accessToken); - } -} diff --git a/app/Containers/VikonIntegration/UI/WEB/Requests/AuthenticateVikonRequest.php b/app/Containers/VikonIntegration/UI/WEB/Requests/AuthenticateVikonRequest.php deleted file mode 100644 index 1d6754a..0000000 --- a/app/Containers/VikonIntegration/UI/WEB/Requests/AuthenticateVikonRequest.php +++ /dev/null @@ -1,31 +0,0 @@ -check(); - } - - public function rules(): array - { - return [ - 'code' => ['required', 'string', 'max:255'], - 'redirect_uri' => ['required', 'url'], - ]; - } - - public function messages(): array - { - return [ - 'code.required' => 'Код авторизации обязателен.', - 'redirect_uri.required' => 'URL перенаправления обязателен.', - 'redirect_uri.url' => 'Некорректный URL перенаправления.', - ]; - } -} diff --git a/app/Containers/VikonIntegration/UI/WEB/Requests/DownloadModuleUpdateRequest.php b/app/Containers/VikonIntegration/UI/WEB/Requests/DownloadModuleUpdateRequest.php deleted file mode 100644 index f6bc4c7..0000000 --- a/app/Containers/VikonIntegration/UI/WEB/Requests/DownloadModuleUpdateRequest.php +++ /dev/null @@ -1,30 +0,0 @@ -check(); - } - - public function rules(): array - { - return [ - 'module_id' => ['required', 'integer', Rule::in([1, 2, 6])], - ]; - } - - public function messages(): array - { - return [ - 'module_id.required' => 'Идентификатор модуля обязателен.', - 'module_id.integer' => 'Идентификатор модуля должен быть числом.', - 'module_id.in' => 'Неподдерживаемый идентификатор модуля. Допустимы: 1 (Сведения), 2 (Абитуриент), 6 (ВСОКО).', - ]; - } -} diff --git a/app/Containers/VikonIntegration/UI/WEB/Requests/RefreshVikonTokenRequest.php b/app/Containers/VikonIntegration/UI/WEB/Requests/RefreshVikonTokenRequest.php deleted file mode 100644 index c60ebfd..0000000 --- a/app/Containers/VikonIntegration/UI/WEB/Requests/RefreshVikonTokenRequest.php +++ /dev/null @@ -1,27 +0,0 @@ -check(); - } - - public function rules(): array - { - return [ - 'refresh_token' => ['required', 'string', 'max:500'], - ]; - } - - public function messages(): array - { - return [ - 'refresh_token.required' => 'Refresh token обязателен.', - ]; - } -} diff --git a/app/Containers/VikonIntegration/UI/WEB/Routes/web.php b/app/Containers/VikonIntegration/UI/WEB/Routes/web.php deleted file mode 100644 index 34f8638..0000000 --- a/app/Containers/VikonIntegration/UI/WEB/Routes/web.php +++ /dev/null @@ -1,41 +0,0 @@ -name('dashboard.vikon-updates.') - ->middleware(['access-check', 'dashboard.auth', 'throttle:30,1']) - ->group(function () { - // Main page - Route::get('/', [VikonUpdateController::class, 'index'])->name('index'); - - // OAuth authentication - Route::post('/authenticate', [VikonUpdateController::class, 'authenticate'])->name('authenticate'); - Route::post('/refresh-token', [VikonUpdateController::class, 'refreshToken'])->name('refresh-token'); - Route::post('/logout', [VikonUpdateController::class, 'logout'])->name('logout'); - - // Access & version checks - Route::post('/check-access', [VikonUpdateController::class, 'checkAccess'])->name('check-access'); - Route::post('/check-version', [VikonUpdateController::class, 'checkVersion'])->name('check-version'); - Route::get('/check-entry', [VikonUpdateController::class, 'checkEntry'])->name('check-entry'); - - // Update operations - Route::post('/download-update', [VikonUpdateController::class, 'downloadUpdate'])->name('download-update'); - Route::post('/sync-files', [VikonUpdateController::class, 'syncFiles'])->name('sync-files'); - }); diff --git a/config/app.php b/config/app.php index 39d245a..2f0f0aa 100755 --- a/config/app.php +++ b/config/app.php @@ -172,7 +172,7 @@ return [ // App\Providers\Filament\DashboardPanelProvider::class, App\Providers\RouteServiceProvider::class, \App\Providers\ForceHttpsServiceProvider::class, - \App\Containers\VikonIntegration\Providers\VikonIntegrationServiceProvider::class, + // \App\Containers\VikonIntegration\Providers\VikonServiceProvider::class, // will be re-added ])->toArray(), /* diff --git a/config/vikon.php b/config/vikon.php deleted file mode 100644 index 294794f..0000000 --- a/config/vikon.php +++ /dev/null @@ -1,101 +0,0 @@ - env('VIKON_CLIENT_ID', '542'), - - 'client_secret' => env('VIKON_CLIENT_SECRET', ''), - - 'vuz_id' => env('VIKON_VUZ_ID', '16775'), - - /* - |-------------------------------------------------------------------------- - | Current Version - |-------------------------------------------------------------------------- - */ - - 'current_version' => env('VIKON_CURRENT_VERSION', file_get_contents(base_path('vikon_version.txt')) ?: '1.0.0'), - - /* - |-------------------------------------------------------------------------- - | API Endpoints - |-------------------------------------------------------------------------- - */ - - 'api_domain' => env('VIKON_API_DOMAIN', 'https://db-nica.ru/'), - - 'auth_domain' => env('VIKON_AUTH_DOMAIN', 'https://auth.db-nica.ru/'), - - 'filemanager_domain' => env('VIKON_FILEMANAGER_DOMAIN', 'https://file.db-nica.ru/'), - - /* - |-------------------------------------------------------------------------- - | Module Configuration - |-------------------------------------------------------------------------- - | - | Module IDs and their deployment paths - | 1 = Sveden (Сведения) - | 2 = Abitur (Абитуриент) - | 6 = VSOKO (ВСОКО) - | - */ - - 'modules' => [ - 1 => [ - 'name' => 'Сведения об образовательной организации', - 'path' => 'sveden', - 'allowed_folders' => [ - 'assets', 'files_zaglushka', 'common', 'struct', 'document', - 'education', 'managers', 'employees', 'objects', 'paid_edu', - 'budget', 'vacant', 'grants', 'inter', 'catering', - 'eduStandarts', 'corruption', 'antiterrorism', 'files', - 'update', 'index.html', '.vikon', '.htaccess', - ], - ], - 2 => [ - 'name' => 'Абитуриент', - 'path' => 'abitur', - 'allowed_folders' => ['abitur'], - ], - 6 => [ - 'name' => 'ВСОКО', - 'path' => 'vsoko', - 'allowed_folders' => [ - 'assets', 'general', 'structure', 'faq', 'procedures', - 'results-and-reports', 'plans', 'survey', 'files', - '.vikon', 'index.html', '.htaccess', - ], - ], - ], - - /* - |-------------------------------------------------------------------------- - | HTTP Client Settings - |-------------------------------------------------------------------------- - */ - - 'http_timeout' => env('VIKON_HTTP_TIMEOUT', 60), - - 'http_retries' => env('VIKON_HTTP_RETRIES', 3), - - /* - |-------------------------------------------------------------------------- - | Update Settings - |-------------------------------------------------------------------------- - */ - - 'storage_path' => storage_path('app/vikon'), - - 'max_upload_size' => env('VIKON_MAX_UPLOAD_SIZE', 50 * 1024 * 1024), // 50MB - -]; diff --git a/resources/js/Pages/Dashboard/VikonUpdates/Index.vue b/resources/js/Pages/Dashboard/VikonUpdates/Index.vue deleted file mode 100644 index db42871..0000000 --- a/resources/js/Pages/Dashboard/VikonUpdates/Index.vue +++ /dev/null @@ -1,377 +0,0 @@ - - -