. */ declare(strict_types=1); namespace FireflyIII\Services\Password; use GuzzleHttp\Client; use GuzzleHttp\Exception\GuzzleException; use GuzzleHttp\Exception\RequestException; /** * Class PwndVerifierV2. */ class PwndVerifierV2 implements Verifier { /** * Verify the given password against (some) service. */ public function validPassword(string $password): bool { // Yes SHA1 is unsafe but in this context its fine. $hash = sha1($password); $prefix = substr($hash, 0, 5); $rest = substr($hash, 5); $url = sprintf('https://api.pwnedpasswords.com/range/%s', $prefix); $opt = [ 'headers' => [ 'User-Agent' => sprintf('Firefly III v%s', config('firefly.version')), 'Add-Padding' => 'true', ], 'timeout' => 3.1415, ]; app('log')->debug(sprintf('hash prefix is %s', $prefix)); app('log')->debug(sprintf('rest is %s', $rest)); try { $client = new Client(); $res = $client->request('GET', $url, $opt); } catch (GuzzleException|RequestException $e) { app('log')->error(sprintf('Could not verify password security: %s', $e->getMessage())); return true; } app('log')->debug(sprintf('Status code returned is %d', $res->getStatusCode())); if (404 === $res->getStatusCode()) { return true; } $strpos = stripos($res->getBody()->getContents(), $rest); if (false === $strpos) { app('log')->debug(sprintf('%s was not found in result body. Return true.', $rest)); return true; } app('log')->debug(sprintf('Found %s, return FALSE.', $rest)); return false; } }