99 lines
3.7 KiB
PHP
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();
|
|
}
|
|
}
|