Files
BetiX/app/Auth/EncryptedUserProvider.php
Dolo 0280278978
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (8.4) (push) Has been cancelled
tests / ci (8.5) (push) Has been cancelled
Initialer Laravel Commit für BetiX
2026-04-04 18:01:50 +02:00

99 lines
3.7 KiB
PHP

<?php
namespace App\Auth;
use Illuminate\Auth\EloquentUserProvider;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
class EncryptedUserProvider extends EloquentUserProvider
{
/**
* Retrieve a user by the given credentials.
*
* @param array $credentials
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveByCredentials(array $credentials)
{
// Remove any password-related keys; we never query by them
$credentials = array_filter(
$credentials,
fn ($key) => ! str_contains($key, 'password'),
ARRAY_FILTER_USE_KEY
);
// Handle the common Fortify username alias `login` (email or username)
if (array_key_exists('login', $credentials)) {
$login = $credentials['login'];
unset($credentials['login']); // prevent accidental `where login = ?`
}
// If there are no identifier credentials and no `login`, fall back to the
// currently authenticated user (used by Fortify confirm-password flow).
if ((empty($credentials)) && (!isset($login) || $login === null || $login === '')) {
$currentId = Auth::id();
if ($currentId) {
return $this->retrieveById($currentId);
}
return null;
}
$query = $this->newModelQuery();
// If a generic `login` was provided, match against blind indexes for email/username
if (isset($login) && is_string($login) && $login !== '') {
if (strlen($login) === 64 && ctype_xdigit($login)) {
// Already a sha256 hash
$query->where(function ($q) use ($login) {
$q->where('email_index', $login)
->orWhere('username_index', $login);
});
} else {
$hash = hash('sha256', $login);
$query->where(function ($q) use ($hash) {
$q->where('email_index', $hash)
->orWhere('username_index', $hash);
});
}
}
// Apply any remaining credential filters safely
foreach ($credentials as $key => $value) {
// Skip empty scalars to avoid `WHERE <field> IS NULL` and unknown columns
if ($value === null || (is_string($value) && $value === '')) {
continue;
}
if (is_array($value) || $value instanceof Arrayable) {
// Only use whereIn for known lookup keys
if (in_array($key, ['id', 'email', 'username', 'email_index', 'username_index'], true)) {
$query->whereIn($key, $value);
}
continue;
}
if ($key === 'email') {
// Accept either plaintext email (hashed) or a precomputed hash
if (strlen($value) === 64 && ctype_xdigit($value)) {
$query->where('email_index', $value);
} else {
$query->where('email_index', hash('sha256', $value));
}
} elseif ($key === 'username') {
// Use blind index for username lookup
$query->where('username_index', hash('sha256', $value));
} elseif (in_array($key, ['id', 'email_index', 'username_index'], true)) {
// Allow direct lookups on safe columns only
$query->where($key, $value);
} else {
// Ignore unknown/non-whitelisted keys to avoid querying non-existent columns
continue;
}
}
return $query->first();
}
}