This commit is contained in:
2026-11-02 08:06:45 +02:00
parent e4f520092e
commit 2a4169162b
108 changed files with 3793 additions and 88 deletions
+1 -1
View File
@@ -9,7 +9,7 @@ final class Audit
public static function record(string $action, ?int $actor, ?int $tenant = null, ?int $company = null, ?int $unit = null, ?int $subject = null, array $details = []): void
{
// Explicit allowlist: credentials, session/context tokens and request bodies never enter audit.
$safe = array_intersect_key($details, array_flip(['before_name', 'after_name', 'permission', 'reason', 'operator', 'grants', 'area', 'record_id', 'version', 'event_id']));
$safe = array_intersect_key($details, array_flip(['before_name', 'after_name', 'permission', 'reason', 'operator', 'grants', 'area', 'record_id', 'version', 'event_id', 'module_id', 'previous_module_id']));
DB::table('identity_audit')->insert([
'action' => $action, 'actor_id' => $actor, 'tenant_id' => $tenant,
'company_id' => $company, 'unit_id' => $unit, 'subject_id' => $subject,
@@ -43,7 +43,15 @@ final class IdentityWorkflow
$grants = DB::table('permission_grants')->where('user_id', $user->id)->where('company_id', $company->id)
->get(['permission', 'unit_id'])->map(fn ($grant) => ['permission' => $grant->permission, 'unit_id' => $grant->unit_id ? (int) $grant->unit_id : null])->all();
$result['context'] = ['company' => $company, 'unit' => $unit, 'units' => $this->units($user->id, $company->tenant_id, $company->id),
'token' => $selected['token'], 'grants' => $grants];
'token' => $selected['token'], 'grants' => $grants,
'modules' => app(\App\Shared\Context\ModuleNavigation::class)->available($this->context),
'module_id' => $selected['module_id'] ?? null];
if ($result['context']['module_id'] && !in_array($result['context']['module_id'], array_column($result['context']['modules'], 'id'), true)) {
$result['context']['module_id'] = null;
$result['context']['token'] = bin2hex(random_bytes(24));
$request->session()->put('company_context', array_replace($selected, ['module_id'=>null, 'token'=>$result['context']['token']]));
$result['notice'] = 'O acesso ao módulo mudou. Seleccione um módulo autorizado.';
}
} catch (\Symfony\Component\HttpKernel\Exception\HttpException $exception) {
if ($exception->getStatusCode() !== 403) { throw $exception; }
$request->session()->forget('company_context');
@@ -54,14 +62,26 @@ final class IdentityWorkflow
public function select(Request $request): array
{
$data = $request->validate(['tenant_id' => 'required|integer|min:1', 'company_id' => 'required|integer|min:1', 'unit_id' => 'nullable|integer|min:1']);
$data = $request->validate(['tenant_id' => 'required|integer|min:1', 'company_id' => 'required|integer|min:1', 'unit_id' => 'nullable|integer|min:1', 'module_id'=>'nullable|string|max:40']);
$unit = isset($data['unit_id']) ? (int) $data['unit_id'] : null;
// Selection is explicit, never silently carries the old unit into another company.
$this->context->selectFor($request->user()->id, (int) $data['tenant_id'], (int) $data['company_id'], $unit);
$request->session()->put('company_context', ['tenant_id' => (int) $data['tenant_id'], 'company_id' => (int) $data['company_id'],
'unit_id' => $unit, 'token' => bin2hex(random_bytes(24))]);
Audit::record('context.selected', $request->user()->id, (int) $data['tenant_id'], (int) $data['company_id'], $unit);
return $this->snapshot($request);
$module = $data['module_id'] ?? null;
abort_if($module !== null && !in_array($module, array_column(app(\App\Shared\Context\ModuleNavigation::class)->available($this->context), 'id'), true), 403, 'Módulo não autorizado ou não configurado.');
$previous = $request->session()->get('company_context.module_id');
$oldSelection=$request->session()->get('company_context');
try {
return DB::transaction(function()use($request,$data,$unit,$module,$previous){
$request->session()->put('company_context', ['tenant_id' => (int) $data['tenant_id'], 'company_id' => (int) $data['company_id'],
'unit_id' => $unit, 'module_id'=>$module, 'token' => bin2hex(random_bytes(24))]);
Audit::record('context.selected', $request->user()->id, (int) $data['tenant_id'], (int) $data['company_id'], $unit, details:['module_id'=>$module, 'previous_module_id'=>$previous]);
return $this->snapshot($request);
});
} catch (\Throwable $failure) {
if($oldSelection===null)$request->session()->forget('company_context');
else $request->session()->put('company_context',$oldSelection);
throw $failure;
}
}
public function renameCompany(Request $request, int $company): void