159 lines
5.1 KiB
PHP
Executable file
159 lines
5.1 KiB
PHP
Executable file
<?php
|
|
|
|
namespace Tests\Unit;
|
|
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Tests\TestCase;
|
|
|
|
class UserHashEmailTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
public function test_hash_uses_hmac_sha256_with_app_key(): void
|
|
{
|
|
$email = 'test@example.com';
|
|
$hash = User::hashEmail($email);
|
|
|
|
$expectedHash = hash_hmac('sha256', strtolower(trim($email)), config('app.key'));
|
|
$this->assertEquals($expectedHash, $hash);
|
|
|
|
$plainSha256Hash = hash('sha256', strtolower(trim($email)));
|
|
$this->assertNotEquals($plainSha256Hash, $hash, 'HMAC-SHA256 should be different from plain SHA-256');
|
|
}
|
|
|
|
public function test_hash_is_deterministic(): void
|
|
{
|
|
$email = 'test@example.com';
|
|
|
|
$hash1 = User::hashEmail($email);
|
|
$hash2 = User::hashEmail($email);
|
|
|
|
$this->assertEquals($hash1, $hash2, 'Same email should produce the same hash');
|
|
}
|
|
|
|
public function test_hash_is_case_insensitive(): void
|
|
{
|
|
$email1 = 'test@example.com';
|
|
$email2 = 'TEST@EXAMPLE.COM';
|
|
$email3 = 'TeSt@ExAmPlE.cOm';
|
|
|
|
$hash1 = User::hashEmail($email1);
|
|
$hash2 = User::hashEmail($email2);
|
|
$hash3 = User::hashEmail($email3);
|
|
|
|
$this->assertEquals($hash1, $hash2, 'Uppercase email should produce the same hash');
|
|
$this->assertEquals($hash1, $hash3, 'Mixed case email should produce the same hash');
|
|
}
|
|
|
|
public function test_hash_trims_whitespace(): void
|
|
{
|
|
$email1 = 'test@example.com';
|
|
$email2 = ' test@example.com ';
|
|
$email3 = "\ttest@example.com\n";
|
|
|
|
$hash1 = User::hashEmail($email1);
|
|
$hash2 = User::hashEmail($email2);
|
|
$hash3 = User::hashEmail($email3);
|
|
|
|
$this->assertEquals($hash1, $hash2, 'Email with leading/trailing spaces should produce the same hash');
|
|
$this->assertEquals($hash1, $hash3, 'Email with tabs/newlines should produce the same hash');
|
|
}
|
|
|
|
public function test_different_emails_produce_different_hashes(): void
|
|
{
|
|
$email1 = 'user1@example.com';
|
|
$email2 = 'user2@example.com';
|
|
$email3 = 'admin@example.com';
|
|
|
|
$hash1 = User::hashEmail($email1);
|
|
$hash2 = User::hashEmail($email2);
|
|
$hash3 = User::hashEmail($email3);
|
|
|
|
$this->assertNotEquals($hash1, $hash2, 'Different emails should produce different hashes');
|
|
$this->assertNotEquals($hash1, $hash3, 'Different emails should produce different hashes');
|
|
$this->assertNotEquals($hash2, $hash3, 'Different emails should produce different hashes');
|
|
}
|
|
|
|
public function test_find_by_email_method_works_correctly(): void
|
|
{
|
|
$email = 'findme@example.com';
|
|
$emailHash = User::hashEmail($email);
|
|
|
|
$this->assertNull(User::findByEmail($email), 'User should not exist yet');
|
|
|
|
$user = User::create([
|
|
'email_hash' => $emailHash,
|
|
]);
|
|
|
|
$foundUser = User::findByEmail($email);
|
|
|
|
$this->assertNotNull($foundUser, 'User should be found');
|
|
$this->assertEquals($user->id, $foundUser->id, 'Found user should match created user');
|
|
$this->assertEquals($emailHash, $foundUser->email_hash, 'Email hash should match');
|
|
}
|
|
|
|
public function test_find_by_email_is_case_insensitive(): void
|
|
{
|
|
$email = 'case@example.com';
|
|
$emailHash = User::hashEmail($email);
|
|
|
|
$user = User::create([
|
|
'email_hash' => $emailHash,
|
|
]);
|
|
|
|
$foundUser1 = User::findByEmail('case@example.com');
|
|
$foundUser2 = User::findByEmail('CASE@EXAMPLE.COM');
|
|
$foundUser3 = User::findByEmail('CaSe@ExAmPlE.cOm');
|
|
|
|
$this->assertNotNull($foundUser1);
|
|
$this->assertNotNull($foundUser2);
|
|
$this->assertNotNull($foundUser3);
|
|
|
|
$this->assertEquals($user->id, $foundUser1->id);
|
|
$this->assertEquals($user->id, $foundUser2->id);
|
|
$this->assertEquals($user->id, $foundUser3->id);
|
|
}
|
|
|
|
public function test_find_by_email_trims_whitespace(): void
|
|
{
|
|
$email = 'trim@example.com';
|
|
$emailHash = User::hashEmail($email);
|
|
|
|
$user = User::create([
|
|
'email_hash' => $emailHash,
|
|
]);
|
|
|
|
$foundUser = User::findByEmail(' trim@example.com ');
|
|
|
|
$this->assertNotNull($foundUser);
|
|
$this->assertEquals($user->id, $foundUser->id);
|
|
}
|
|
|
|
public function test_hash_length_is_consistent(): void
|
|
{
|
|
$emails = [
|
|
'a@b.c',
|
|
'test@example.com',
|
|
'very.long.email.address@subdomain.example.com',
|
|
];
|
|
|
|
$hashes = array_map(fn($email) => User::hashEmail($email), $emails);
|
|
|
|
foreach ($hashes as $hash) {
|
|
$this->assertEquals(64, strlen($hash), 'SHA-256 hash should always be 64 characters');
|
|
}
|
|
}
|
|
|
|
public function test_hash_contains_only_hexadecimal_characters(): void
|
|
{
|
|
$email = 'test@example.com';
|
|
$hash = User::hashEmail($email);
|
|
|
|
$this->assertMatchesRegularExpression(
|
|
'/^[a-f0-9]{64}$/',
|
|
$hash,
|
|
'Hash should contain only lowercase hexadecimal characters'
|
|
);
|
|
}
|
|
}
|