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
@@ -12,6 +12,8 @@ use App\Containers\VikonIntegration\UI\WEB\Requests\AuthenticateRequest;
use App\Containers\VikonIntegration\UI\WEB\Requests\UpdateModuleRequest;
use App\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Session;
class VikonController extends Controller
@@ -39,6 +41,39 @@ class VikonController extends Controller
]);
}
public function oauthCallback(Request $request): \Inertia\Response
{
$state = $request->query('state');
$expectedState = Session::pull('oauth_state');
if ($state && $expectedState && $state !== $expectedState) {
Log::warning('Vikon OAuth CSRF mismatch');
}
$code = $request->query('code');
if ($code) {
try {
$redirectUri = route('dashboard.vikon-updates.callback');
$tokens = $this->auth->run($code, $redirectUri);
Session::put('vikon_access_token', $tokens['access_token']);
Session::put('vikon_refresh_token', $tokens['refresh_token']);
} catch (\Throwable $e) {
Log::error('OAuth callback failed', ['error' => $e->getMessage()]);
}
}
$token = Session::get('vikon_access_token');
$isAuth = $token ? $this->validateToken->run($token) : false;
return inertia()->render('Dashboard/VikonUpdates/Index', [
'is_authenticated' => $isAuth,
'current_version' => config('vikon.current_version'),
'modules' => config('vikon.modules'),
'vikon_api_domain' => config('vikon.api_domain'),
'vikon_client_id' => config('vikon.client_id'),
]);
}
public function authenticate(AuthenticateRequest $request): JsonResponse
{
try {
@@ -114,4 +149,19 @@ class VikonController extends Controller
Session::forget(['vikon_access_token', 'vikon_refresh_token']);
return response()->json(['success' => true]);
}
public function authorize(): JsonResponse
{
$state = \Illuminate\Support\Str::random(32);
Session::put('oauth_state', $state);
$redirectUri = route('dashboard.vikon-updates.callback');
$url = config('vikon.auth_domain') . 'oauth2/authorize'
. '?client_id=' . config('vikon.client_id')
. '&redirect_uri=' . urlencode($redirectUri)
. '&response_type=code'
. '&state=' . $state;
return response()->json(['url' => $url]);
}
}
@@ -5,9 +5,11 @@ use Illuminate\Support\Facades\Route;
Route::prefix('/dashboard/vikon-updates')
->name('dashboard.vikon-updates.')
->middleware(['access-check', 'dashboard.auth', 'throttle:30,1'])
->middleware(['access-check', 'dashboard.auth', 'throttle:30,1', 'vikon.refresh'])
->group(function () {
Route::get('/', [VikonController::class, 'index'])->name('index');
Route::get('/callback', [VikonController::class, 'oauthCallback'])->name('callback');
Route::post('/authorize', [VikonController::class, 'authorize'])->name('authorize');
Route::post('/authenticate', [VikonController::class, 'authenticate'])->name('authenticate');
Route::post('/refresh-token', [VikonController::class, 'refreshToken'])->name('refresh-token');
Route::post('/check-access', [VikonController::class, 'checkAccess'])->name('check-access');