56 lines
3.0 KiB
PHP
56 lines
3.0 KiB
PHP
<?php
|
|
|
|
use App\Models\User;
|
|
use Illuminate\Contracts\Console\Kernel;
|
|
use Illuminate\Support\Facades\Crypt;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
// Revoke only synthetic QA21 sessions from this failed browser batch.
|
|
require dirname(__DIR__).'/vendor/autoload.php';
|
|
require __DIR__.'/portal-qa-environment.php';
|
|
$target = portalQaEnvironment();
|
|
$app = require dirname(__DIR__).'/bootstrap/app.php';
|
|
$app->make(Kernel::class)->bootstrap();
|
|
$identity = portalQaAssertTarget($target);
|
|
$actor = User::findOrFail(21);
|
|
throw_unless(str_ends_with($actor->email, '@example.invalid'), RuntimeException::class, 'Only synthetic QA actor');
|
|
$count = DB::table('sessions')->where('user_id', 21)->where('last_activity', '>=', strtotime('2026-10-10 20:15:00 UTC'))->delete();
|
|
$qaSessionRoot = realpath(storage_path('app/private/investmoz-v2/qa-opportunity-resources-sessions'));
|
|
throw_unless($qaSessionRoot && str_starts_with($qaSessionRoot, realpath(storage_path('app/private/investmoz-v2'))), RuntimeException::class, 'QA session directory outside allowed target');
|
|
$cutoff = 0;
|
|
foreach (glob(storage_path('app/private/investmoz-v2/portal-audit/consumer-workflow-chromium-20261010-attempt-*.json')) as $receipt) {
|
|
$r = json_decode(file_get_contents($receipt), true);
|
|
if (($r['result'] ?? null) === 'failed') {
|
|
$cutoff = max($cutoff, strtotime($r['finished_at'] ?? '1970-01-01'));
|
|
}
|
|
}
|
|
throw_unless($cutoff > 0, RuntimeException::class, 'Failed browser batch cutoff required');
|
|
$filesRevoked = 0;
|
|
foreach (glob($qaSessionRoot.DIRECTORY_SEPARATOR.'*') as $file) {
|
|
if (! is_file($file) || filemtime($file) < strtotime('2026-10-10 20:15:00 UTC') || filemtime($file) > $cutoff) {
|
|
continue;
|
|
}
|
|
$raw = file_get_contents($file);
|
|
$data = json_decode($raw, true) ?? @unserialize($raw, ['allowed_classes' => false]);
|
|
if (! is_array($data)) {
|
|
try {
|
|
$raw = Crypt::decrypt($raw);
|
|
$data = json_decode($raw, true) ?? @unserialize($raw, ['allowed_classes' => false]);
|
|
} catch (Throwable) {
|
|
continue;
|
|
}
|
|
}
|
|
if (! is_array($data)) {
|
|
continue;
|
|
}
|
|
foreach ($data as $key => $value) {
|
|
if (str_starts_with((string) $key, 'login_web_') && (int) $value === 21) {
|
|
throw_unless(unlink($file), RuntimeException::class, 'Could not revoke synthetic QA session');
|
|
$filesRevoked++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
file_put_contents(storage_path('app/private/investmoz-v2/portal-audit/consumer-browser-session-revocation-qa.json'), json_encode(['at' => gmdate('c'), 'target' => $identity, 'actor_id' => 21, 'revoked_database_sessions' => $count, 'revoked_file_sessions' => $filesRevoked, 'failed_batch_cutoff_utc' => gmdate('c', $cutoff), 'scope' => 'synthetic QA21 failed batch since20:15UTC; later sessions excluded', 'mfa_changed' => false, 'active_writes' => 0], JSON_PRETTY_PRINT));
|
|
echo json_encode(['actor_id' => 21, 'revoked_database_sessions' => $count, 'revoked_file_sessions' => $filesRevoked, 'target' => $identity, 'active_writes' => 0]).PHP_EOL;
|