Add Gravatar and DNS Records collectors
Two pure-PHP collectors, no Python/venv/subprocess needed:
- GravatarRunner (email): checks gravatar.com/avatar/{md5}?d=404 for a
200 vs 404. Scoped to that binary signal since Gravatar's profile
JSON endpoint now requires API auth even for real, public profiles
(confirmed against Gravatar's own creator's email).
- DnsRunner (domain): dns_get_record() for A/AAAA/MX/NS/TXT/CNAME. Raw
payload is naturally keyed by record type, which the existing
generic list-renderer on the investigation page turns into one
collapsible section per type with no UI changes needed.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
bb15f13bac
commit
86f73c46b2
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Osint;
|
||||
|
||||
use App\Models\Target;
|
||||
use App\Osint\Runners\DnsRunner;
|
||||
use App\Osint\RunnerException;
|
||||
use Tests\TestCase;
|
||||
|
||||
class DnsRunnerTest extends TestCase
|
||||
{
|
||||
public function test_rejects_non_domain_targets(): void
|
||||
{
|
||||
$target = new Target(['type' => 'ip', 'value' => '8.8.8.8']);
|
||||
|
||||
$this->expectException(RunnerException::class);
|
||||
|
||||
(new DnsRunner)->run($target);
|
||||
}
|
||||
|
||||
public function test_rejects_unsafe_domain_format(): void
|
||||
{
|
||||
$target = new Target(['type' => 'domain', 'value' => '../../etc/passwd']);
|
||||
|
||||
$this->expectException(RunnerException::class);
|
||||
|
||||
(new DnsRunner)->run($target);
|
||||
}
|
||||
|
||||
/**
|
||||
* example.com is IANA-controlled and has had stable NS/A records for
|
||||
* decades — safe to rely on for a real (non-mocked) DNS lookup.
|
||||
*/
|
||||
public function test_resolves_a_real_stable_domain(): void
|
||||
{
|
||||
$target = new Target(['type' => 'domain', 'value' => 'example.com']);
|
||||
|
||||
$result = (new DnsRunner)->run($target);
|
||||
|
||||
$this->assertArrayHasKey('NS', $result->raw);
|
||||
$this->assertNotEmpty($result->raw['NS']);
|
||||
$this->assertStringContainsString('DNS record', $result->summary);
|
||||
}
|
||||
|
||||
public function test_reports_no_records_for_a_nonexistent_domain(): void
|
||||
{
|
||||
$target = new Target(['type' => 'domain', 'value' => 'this-domain-should-not-exist-osint-test.invalid']);
|
||||
|
||||
$result = (new DnsRunner)->run($target);
|
||||
|
||||
$this->assertSame([], $result->raw);
|
||||
$this->assertSame('No DNS records found.', $result->summary);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Osint;
|
||||
|
||||
use App\Models\Target;
|
||||
use App\Osint\Runners\GravatarRunner;
|
||||
use App\Osint\RunnerException;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Tests\TestCase;
|
||||
|
||||
class GravatarRunnerTest extends TestCase
|
||||
{
|
||||
public function test_reports_avatar_found(): void
|
||||
{
|
||||
Http::fake(['gravatar.com/avatar/*' => Http::response('', 200)]);
|
||||
|
||||
$target = new Target(['type' => 'email', 'value' => 'test@example.com']);
|
||||
|
||||
$result = (new GravatarRunner)->run($target);
|
||||
|
||||
$this->assertTrue($result->raw['has_avatar']);
|
||||
$this->assertNotNull($result->raw['avatar_url']);
|
||||
$this->assertStringContainsString('Gravatar image found', $result->summary);
|
||||
}
|
||||
|
||||
public function test_reports_no_avatar(): void
|
||||
{
|
||||
Http::fake(['gravatar.com/avatar/*' => Http::response('', 404)]);
|
||||
|
||||
$target = new Target(['type' => 'email', 'value' => 'test@example.com']);
|
||||
|
||||
$result = (new GravatarRunner)->run($target);
|
||||
|
||||
$this->assertFalse($result->raw['has_avatar']);
|
||||
$this->assertNull($result->raw['avatar_url']);
|
||||
$this->assertSame('No Gravatar found for this email.', $result->summary);
|
||||
}
|
||||
|
||||
public function test_rejects_non_email_targets(): void
|
||||
{
|
||||
$target = new Target(['type' => 'domain', 'value' => 'example.com']);
|
||||
|
||||
$this->expectException(RunnerException::class);
|
||||
|
||||
(new GravatarRunner)->run($target);
|
||||
}
|
||||
|
||||
public function test_rejects_invalid_email_format(): void
|
||||
{
|
||||
$target = new Target(['type' => 'email', 'value' => 'not-an-email']);
|
||||
|
||||
$this->expectException(RunnerException::class);
|
||||
|
||||
(new GravatarRunner)->run($target);
|
||||
}
|
||||
|
||||
public function test_throws_on_unexpected_status(): void
|
||||
{
|
||||
Http::fake(['gravatar.com/avatar/*' => Http::response('', 500)]);
|
||||
|
||||
$target = new Target(['type' => 'email', 'value' => 'test@example.com']);
|
||||
|
||||
$this->expectException(RunnerException::class);
|
||||
|
||||
(new GravatarRunner)->run($target);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user