Multi-user OSINT investigation tool with owner-controlled per-user and per-group access grants. Includes Sherlock, theHarvester, crt.sh, WHOIS, and ip-api.com collectors wired through a pluggable Runner/queue pipeline, investigation search, and printable/CSV/JSON reporting. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
78 lines
2.4 KiB
PHP
78 lines
2.4 KiB
PHP
<?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;
|
|
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}...");
|
|
}
|
|
}
|