I due piu' gravi potevano causare perdita di dati silenziosa. AppServiceProvider chiamava key:generate --force a ogni richiesta quando APP_KEY risultava vuota. Poiche' nome e cognome dei proclamatori sono cifrati con quella chiave, ogni riga scritta sotto una chiave poi sostituita diventava irrecuperabile. La chiave e' ora risolta una sola volta all'avvio del container e il provider solleva un'eccezione se manca, invece di rigenerarla. importTerritoryPdfFolder() caricava i PDF, costruiva l'elenco dei file e poi lo scartava senza mai accodare il job: nessun errore, nessun territorio aggiornato, e i file restavano su disco a crescita illimitata perche' la pulizia viveva solo nel finally del job mai eseguito. Sicurezza: - i permessi non venivano riapplicati alle richieste /livewire/update, per cui un permesso revocato restava attivo fino al reload della pagina - host header injection: nginx passava l'Host del client come X-Forwarded-Host e Laravel si fidava di tutti i proxy, abbastanza per far generare a route() link verso domini arbitrari, inclusi i PDF pubblici che contengono un codice di accesso valido - lo schema forwarded e' ora deciso dal server e non dall'header del client - campagna_id in Rientra e' #[Locked]: era derivato lato server ma manipolabile dal client, permettendo di conteggiare un rientro su una campagna arbitraria - sortField del registro passava non validato a orderBy(), con 500 su colonna inesistente - SESSION_SECURE_COOKIE ora vale true fuori da local - limiti su dimensione e numero di voci negli import ZIP Integrita' e prestazioni: - il default di assignment_link_ttl_hours era rimasto 24 dopo la conversione da ore a mesi: i link PDF pubblici duravano due anni invece di uno mese - il seeder usava syncPermissions(), che a un secondo giro azzerava i permessi personalizzati dei ruoli; ora e' additivo - pdftoppm senza timeout poteva bloccare il worker indefinitamente - nomi file deterministici nell'import: "1 A" e "1-A" scrivevano sullo stesso PDF, sovrascrivendosi - Setting::flushCache() dopo le cancellazioni massive, che non emettono eventi e lasciavano la cache puntata a una riga inesistente - riga settings creata dal seeder, per evitare due singleton concorrenti - rimosse due migrazioni ridondanti che rompevano migrate:rollback - indici su assigned_at, (attivo, deleted_at) e deleted_at - risolti gli N+1 negli elenchi territori e proclamatori Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
76 lines
3.0 KiB
PHP
76 lines
3.0 KiB
PHP
<?php
|
|
|
|
namespace App\Providers;
|
|
|
|
use Illuminate\Support\ServiceProvider;
|
|
use Illuminate\Support\Facades\Gate;
|
|
use Illuminate\Support\Facades\URL;
|
|
use Livewire\Livewire;
|
|
use RuntimeException;
|
|
|
|
class AppServiceProvider extends ServiceProvider
|
|
{
|
|
public function register(): void
|
|
{
|
|
//
|
|
}
|
|
|
|
public function boot(): void
|
|
{
|
|
// Pin generated URLs to APP_URL.
|
|
//
|
|
// Behind a trusted proxy, Symfony derives the port from
|
|
// X-Forwarded-Port and falls back to the scheme's default when that
|
|
// header is absent — which silently drops a non-standard port from
|
|
// every generated link. Anchoring the root to APP_URL makes the
|
|
// public address explicit instead of reconstructed per request, and
|
|
// keeps PDF/e-mail links correct regardless of proxy behaviour.
|
|
$appUrl = (string) config('app.url');
|
|
|
|
if ($appUrl !== '') {
|
|
URL::forceRootUrl($appUrl);
|
|
|
|
if (str_starts_with($appUrl, 'https://')) {
|
|
URL::forceScheme('https');
|
|
}
|
|
}
|
|
|
|
// NOTE: APP_KEY is deliberately NOT auto-generated here.
|
|
//
|
|
// This provider boots on every request. Generating a key at runtime
|
|
// meant that if the key ever failed to persist, each request could
|
|
// mint a *different* one — and since proclamatori names are encrypted
|
|
// at column level with APP_KEY, every row written under a superseded
|
|
// key becomes permanently unreadable.
|
|
//
|
|
// The key is now resolved once at container start (docker/php/
|
|
// entrypoint.sh) and persisted to the storage volume. Fail loudly
|
|
// instead of silently rotating.
|
|
// Only enforced when serving HTTP. Build-time tooling (package:discover,
|
|
// config:cache) legitimately runs before the key exists, and failing
|
|
// there would break the image build rather than surface a real problem.
|
|
if (empty(config('app.key')) && ! $this->app->runningInConsole()) {
|
|
throw new RuntimeException(
|
|
'APP_KEY is not set. Set it in the environment before starting the application. '
|
|
.'Generate one with: php artisan key:generate --show'
|
|
);
|
|
}
|
|
|
|
// Livewire only re-applies a fixed allow-list of middleware to
|
|
// /livewire/update requests. Spatie's permission middleware is not on
|
|
// that list, so a component whose route is guarded by
|
|
// `permission:territori.manage` would keep accepting mutating actions
|
|
// from a user whose permission was revoked after page load, until they
|
|
// reload. Registering them as persistent closes that window.
|
|
Livewire::addPersistentMiddleware([
|
|
\Spatie\Permission\Middleware\PermissionMiddleware::class,
|
|
\Spatie\Permission\Middleware\RoleMiddleware::class,
|
|
\Spatie\Permission\Middleware\RoleOrPermissionMiddleware::class,
|
|
]);
|
|
|
|
Gate::before(function ($user, $ability) {
|
|
return $user->hasRole('amministratore') ? true : null;
|
|
});
|
|
}
|
|
}
|