Test project for media files management.
<?php
namespace Illuminate\Validation;
use Exception;
use Illuminate\Contracts\Validation\UncompromisedVerifier;
use Illuminate\Support\Str;
class NotPwnedVerifier implements UncompromisedVerifier
{
/**
* The HTTP factory instance.
*
* @var \Illuminate\Http\Client\Factory
*/
protected $factory;
/**
* The number of seconds the request can run before timing out.
*
* @var int
*/
protected $timeout;
/**
* Create a new uncompromised verifier.
*
* @param \Illuminate\Http\Client\Factory $factory
* @param int|null $timeout
* @return void
*/
public function __construct($factory, $timeout = null)
{
$this->factory = $factory;
$this->timeout = $timeout ?? 30;
}
/**
* Verify that the given data has not been compromised in public breaches.
*
* @param array $data
* @return bool
*/
public function verify($data)
{
$value = $data['value'];
$threshold = $data['threshold'];
if (empty($value = (string) $value)) {
return false;
}
[$hash, $hashPrefix] = $this->getHash($value);
return ! $this->search($hashPrefix)
->contains(function ($line) use ($hash, $hashPrefix, $threshold) {
[$hashSuffix, $count] = explode(':', $line);
return $hashPrefix.$hashSuffix == $hash && $count > $threshold;
});
}
/**
* Get the hash and its first 5 chars.
*
* @param string $value
* @return array
*/
protected function getHash($value)
{
$hash = strtoupper(sha1((string) $value));
$hashPrefix = substr($hash, 0, 5);
return [$hash, $hashPrefix];
}
/**
* Search by the given hash prefix and returns all occurrences of leaked passwords.
*
* @param string $hashPrefix
* @return \Illuminate\Support\Collection
*/
protected function search($hashPrefix)
{
try {
$response = $this->factory->withHeaders([
'Add-Padding' => true,
])->timeout($this->timeout)->get(
'https://api.pwnedpasswords.com/range/'.$hashPrefix
);
} catch (Exception $e) {
report($e);
}
$body = (isset($response) && $response->successful())
? $response->body()
: '';
return Str::of($body)->trim()->explode("\n")->filter(function ($line) {
return str_contains($line, ':');
});
}
}