170ca9c90SGreg Roach<?php 270ca9c90SGreg Roach 370ca9c90SGreg Roach/** 470ca9c90SGreg Roach * webtrees: online genealogy 5*d11be702SGreg Roach * Copyright (C) 2023 webtrees development team 670ca9c90SGreg Roach * This program is free software: you can redistribute it and/or modify 770ca9c90SGreg Roach * it under the terms of the GNU General Public License as published by 870ca9c90SGreg Roach * the Free Software Foundation, either version 3 of the License, or 970ca9c90SGreg Roach * (at your option) any later version. 1070ca9c90SGreg Roach * This program is distributed in the hope that it will be useful, 1170ca9c90SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 1270ca9c90SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1370ca9c90SGreg Roach * GNU General Public License for more details. 1470ca9c90SGreg Roach * You should have received a copy of the GNU General Public License 1589f7189bSGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>. 1670ca9c90SGreg Roach */ 1770ca9c90SGreg Roach 1870ca9c90SGreg Roachdeclare(strict_types=1); 1970ca9c90SGreg Roach 2070ca9c90SGreg Roachnamespace Fisharebest\Webtrees\Services; 2170ca9c90SGreg Roach 222e464181SGreg Roachuse Fisharebest\Webtrees\Registry; 2370ca9c90SGreg Roachuse Fisharebest\Webtrees\Session; 24b55cbc6bSGreg Roachuse Fisharebest\Webtrees\Validator; 2570ca9c90SGreg Roachuse Psr\Http\Message\ServerRequestInterface; 2670ca9c90SGreg Roach 2710e06497SGreg Roachuse function assert; 2810e06497SGreg Roachuse function is_float; 2910e06497SGreg Roachuse function is_string; 3070ca9c90SGreg Roachuse function view; 3170ca9c90SGreg Roach 3270ca9c90SGreg Roach/** 3370ca9c90SGreg Roach * Completely Automated Public Turing test to tell Computers and Humans Apart. 3470ca9c90SGreg Roach */ 3570ca9c90SGreg Roachclass CaptchaService 3670ca9c90SGreg Roach{ 3770ca9c90SGreg Roach // If the form is completed faster than this, then suspect a robot. 3870ca9c90SGreg Roach private const MINIMUM_FORM_TIME = 3.0; 3970ca9c90SGreg Roach 4070ca9c90SGreg Roach /** 4170ca9c90SGreg Roach * Create the captcha 4270ca9c90SGreg Roach * 4370ca9c90SGreg Roach * @return string 4470ca9c90SGreg Roach */ 4570ca9c90SGreg Roach public function createCaptcha(): string 4670ca9c90SGreg Roach { 472e464181SGreg Roach $x = Registry::idFactory()->uuid(); 482e464181SGreg Roach $y = Registry::idFactory()->uuid(); 492e464181SGreg Roach $z = Registry::idFactory()->uuid(); 5070ca9c90SGreg Roach 51eeec557aSGreg Roach Session::put('captcha-t', Registry::timeFactory()->now()); 5270ca9c90SGreg Roach Session::put('captcha-x', $x); 5370ca9c90SGreg Roach Session::put('captcha-y', $y); 5470ca9c90SGreg Roach Session::put('captcha-z', $z); 5570ca9c90SGreg Roach 5670ca9c90SGreg Roach return view('captcha', [ 5770ca9c90SGreg Roach 'x' => $x, 5870ca9c90SGreg Roach 'y' => $y, 5970ca9c90SGreg Roach 'z' => $z, 6070ca9c90SGreg Roach ]); 6170ca9c90SGreg Roach } 6270ca9c90SGreg Roach 6370ca9c90SGreg Roach /** 6470ca9c90SGreg Roach * Check the user's response. 6570ca9c90SGreg Roach * 6670ca9c90SGreg Roach * @param ServerRequestInterface $request 6770ca9c90SGreg Roach * 6870ca9c90SGreg Roach * @return bool 6970ca9c90SGreg Roach */ 7070ca9c90SGreg Roach public function isRobot(ServerRequestInterface $request): bool 7170ca9c90SGreg Roach { 72d8809d62SGreg Roach $t = Session::pull('captcha-t'); 73d8809d62SGreg Roach $x = Session::pull('captcha-x'); 74d8809d62SGreg Roach $y = Session::pull('captcha-y'); 75d8809d62SGreg Roach $z = Session::pull('captcha-z'); 7670ca9c90SGreg Roach 77e6b1f16dSGreg Roach assert(is_float($t)); 78b55cbc6bSGreg Roach assert(is_string($x)); 79b55cbc6bSGreg Roach assert(is_string($y)); 80b55cbc6bSGreg Roach assert(is_string($z)); 81b55cbc6bSGreg Roach 82b55cbc6bSGreg Roach $value_x = Validator::parsedBody($request)->string($x, ''); 83b55cbc6bSGreg Roach $value_y = Validator::parsedBody($request)->string($y, ''); 8470ca9c90SGreg Roach 8570ca9c90SGreg Roach // The captcha uses javascript to copy value z from field y to field x. 8670ca9c90SGreg Roach // Expect it in both fields. 8770ca9c90SGreg Roach if ($value_x !== $z || $value_y !== $z) { 8870ca9c90SGreg Roach return true; 8970ca9c90SGreg Roach } 9070ca9c90SGreg Roach 91e6b1f16dSGreg Roach // If the form was returned too quickly, then probably a robot. 92eeec557aSGreg Roach return Registry::timeFactory()->now() < $t + self::MINIMUM_FORM_TIME; 9370ca9c90SGreg Roach } 9470ca9c90SGreg Roach} 95