2026-07-20 10:22:05 +03:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
|
|
|
|
|
|
use App\Jobs\RunFinding;
|
|
|
|
|
use App\Models\Finding;
|
|
|
|
|
use App\Models\Investigation;
|
|
|
|
|
use App\Models\Source;
|
|
|
|
|
use App\Models\Target;
|
2026-07-20 11:29:26 +03:00
|
|
|
use App\Osint\FindingDispatcher;
|
2026-07-20 10:22:05 +03:00
|
|
|
use App\Osint\RunnerRegistry;
|
|
|
|
|
use Illuminate\Http\RedirectResponse;
|
|
|
|
|
use Illuminate\Http\Request;
|
|
|
|
|
|
|
|
|
|
class TargetController extends Controller
|
|
|
|
|
{
|
|
|
|
|
public function store(Request $request, Investigation $investigation): RedirectResponse
|
|
|
|
|
{
|
|
|
|
|
$this->authorize('update', $investigation);
|
|
|
|
|
|
|
|
|
|
$type = $request->validate([
|
|
|
|
|
'type' => ['required', 'string', 'in:'.implode(',', Target::TYPES)],
|
|
|
|
|
])['type'];
|
|
|
|
|
|
|
|
|
|
$data = $request->validate([
|
|
|
|
|
'value' => Target::valueRulesFor($type),
|
|
|
|
|
'notes' => ['nullable', 'string', 'max:5000'],
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$investigation->targets()->create([
|
|
|
|
|
...$data,
|
|
|
|
|
'type' => $type,
|
|
|
|
|
'created_by' => $request->user()->id,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
return redirect()->route('investigations.show', $investigation);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function destroy(Investigation $investigation, Target $target): RedirectResponse
|
|
|
|
|
{
|
|
|
|
|
$this->authorize('update', $investigation);
|
|
|
|
|
|
|
|
|
|
abort_if($target->investigation_id !== $investigation->id, 404);
|
|
|
|
|
|
|
|
|
|
$target->delete();
|
|
|
|
|
|
|
|
|
|
return redirect()->route('investigations.show', $investigation);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function run(Request $request, Investigation $investigation, Target $target, RunnerRegistry $registry): RedirectResponse
|
|
|
|
|
{
|
|
|
|
|
$this->authorize('update', $investigation);
|
|
|
|
|
|
|
|
|
|
abort_if($target->investigation_id !== $investigation->id, 404);
|
|
|
|
|
|
|
|
|
|
$data = $request->validate([
|
|
|
|
|
'source_id' => ['required', 'integer', 'exists:sources,id'],
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$source = Source::findOrFail($data['source_id']);
|
|
|
|
|
|
|
|
|
|
if (! in_array($target->type, $source->target_types, true) || ! $registry->has($source->key)) {
|
|
|
|
|
return back()->withErrors(['source_id' => "{$source->name} can't be run against this target."]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$finding = Finding::create([
|
|
|
|
|
'target_id' => $target->id,
|
|
|
|
|
'source_id' => $source->id,
|
|
|
|
|
'run_by' => $request->user()->id,
|
|
|
|
|
'status' => 'pending',
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
RunFinding::dispatch($finding->id);
|
|
|
|
|
|
|
|
|
|
return redirect()->route('investigations.show', $investigation)
|
|
|
|
|
->with('status', "Running {$source->name} against {$target->value}...");
|
|
|
|
|
}
|
2026-07-20 11:29:26 +03:00
|
|
|
|
|
|
|
|
public function runAll(Request $request, Investigation $investigation, Target $target, FindingDispatcher $dispatcher): RedirectResponse
|
|
|
|
|
{
|
|
|
|
|
$this->authorize('update', $investigation);
|
|
|
|
|
|
|
|
|
|
abort_if($target->investigation_id !== $investigation->id, 404);
|
|
|
|
|
|
|
|
|
|
$queued = $dispatcher->dispatchAllApplicable($target, $request->user());
|
|
|
|
|
|
|
|
|
|
return redirect()->route('investigations.show', $investigation)
|
|
|
|
|
->with('status', $queued > 0
|
|
|
|
|
? "Queued {$queued} lookup(s) for {$target->value}..."
|
|
|
|
|
: "Nothing to queue for {$target->value} — already up to date.");
|
|
|
|
|
}
|
2026-07-20 10:22:05 +03:00
|
|
|
}
|