83 lines
2.8 KiB
PHP
83 lines
2.8 KiB
PHP
<?php
|
|
|
|
use MintyPHP\Http\SessionStoreInterface;
|
|
use MintyPHP\I18n;
|
|
use MintyPHP\Module\Security\SecurityAuthorizationPolicy;
|
|
use MintyPHP\Module\Security\Service\SecurityCheckProcess;
|
|
use MintyPHP\Module\Security\Service\SecurityCheckService;
|
|
use MintyPHP\Module\Security\Service\SecurityReportPdfService;
|
|
use MintyPHP\Router;
|
|
use MintyPHP\Support\Flash;
|
|
use MintyPHP\Support\Guard;
|
|
|
|
// Streams the generated PDF directly — no view template for this route.
|
|
define('MINTY_ALLOW_OUTPUT', true);
|
|
|
|
Guard::requireLogin();
|
|
Guard::requireAbilityOrForbidden(SecurityAuthorizationPolicy::ABILITY_CHECKS_VIEW);
|
|
|
|
$checkId = (int) ($id ?? 0);
|
|
$closeTarget = requestResolveReturnTarget('security/checks');
|
|
$editTarget = requestPathWithReturnTarget('security/checks/edit/' . $checkId, requestResolveReturnTarget());
|
|
|
|
$session = app(SessionStoreInterface::class)->all();
|
|
$tenantId = (int) ($session['current_tenant']['id'] ?? 0);
|
|
|
|
$service = app(SecurityCheckService::class);
|
|
$process = app(SecurityCheckProcess::class);
|
|
$check = $service->findById($tenantId, $checkId);
|
|
|
|
if ($check === null) {
|
|
Flash::error(t('Security check not found'), $closeTarget, 'security_check_not_found');
|
|
Router::redirect($closeTarget);
|
|
|
|
return;
|
|
}
|
|
|
|
// Re-enforce the gate server-side: the report can only be produced once the
|
|
// check has actually been carried out (all preceding steps complete). The UI
|
|
// hides the button, but it must not be the only line of defence.
|
|
$prerequisitesMet = $process->reportPrerequisitesMet(
|
|
is_array($check['process_state'] ?? null) ? $check['process_state'] : [],
|
|
is_array($check['tech_schema_snapshot'] ?? null) ? $check['tech_schema_snapshot'] : [],
|
|
is_array($check['tech_state'] ?? null) ? $check['tech_state'] : []
|
|
);
|
|
if (!$prerequisitesMet) {
|
|
Flash::error(t('Complete all previous steps before generating the customer report.'), $editTarget, 'security_report_gated');
|
|
Router::redirect($editTarget);
|
|
|
|
return;
|
|
}
|
|
|
|
$pdfService = app(SecurityReportPdfService::class);
|
|
$pdf = $pdfService->renderCustomerReportPdf($check, [
|
|
'locale' => strtolower((string) (I18n::$locale ?? I18n::$defaultLocale)),
|
|
'app_name' => appTitle(),
|
|
'tenant_uuid' => (string) ($session['current_tenant']['uuid'] ?? ''),
|
|
]);
|
|
|
|
if ($pdf === '') {
|
|
// Concrete renderer/template failures are handled inside the service.
|
|
http_response_code(500);
|
|
|
|
return;
|
|
}
|
|
|
|
$filename = $pdfService->buildReportFilename($check);
|
|
|
|
header('Content-Type: application/pdf');
|
|
header('Content-Disposition: inline; filename="' . $filename . '"');
|
|
header('Cache-Control: private, no-store, max-age=0');
|
|
header('Pragma: no-cache');
|
|
header('X-Content-Type-Options: nosniff');
|
|
header('Content-Length: ' . strlen($pdf));
|
|
|
|
$output = fopen('php://output', 'wb');
|
|
if ($output === false) {
|
|
http_response_code(500);
|
|
|
|
return;
|
|
}
|
|
fwrite($output, $pdf);
|
|
fclose($output);
|