xref: /webtrees/app/Services/CaptchaService.php (revision 5bfc689774bb9a6401271c4ed15a6d50652c991b)
170ca9c90SGreg Roach<?php
270ca9c90SGreg Roach
370ca9c90SGreg Roach/**
470ca9c90SGreg Roach * webtrees: online genealogy
5*5bfc6897SGreg Roach * Copyright (C) 2022 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
2270ca9c90SGreg Roachuse Fisharebest\Webtrees\Session;
23b55cbc6bSGreg Roachuse Fisharebest\Webtrees\Validator;
2470ca9c90SGreg Roachuse Psr\Http\Message\ServerRequestInterface;
2570ca9c90SGreg Roachuse Ramsey\Uuid\Uuid;
2670ca9c90SGreg Roach
2770ca9c90SGreg Roachuse function view;
2870ca9c90SGreg Roach
2970ca9c90SGreg Roach/**
3070ca9c90SGreg Roach * Completely Automated Public Turing test to tell Computers and Humans Apart.
3170ca9c90SGreg Roach */
3270ca9c90SGreg Roachclass CaptchaService
3370ca9c90SGreg Roach{
3470ca9c90SGreg Roach    // If the form is completed faster than this, then suspect a robot.
3570ca9c90SGreg Roach    private const MINIMUM_FORM_TIME = 3.0;
3670ca9c90SGreg Roach
3770ca9c90SGreg Roach    /**
3870ca9c90SGreg Roach     * Create the captcha
3970ca9c90SGreg Roach     *
4070ca9c90SGreg Roach     * @return string
4170ca9c90SGreg Roach     */
4270ca9c90SGreg Roach    public function createCaptcha(): string
4370ca9c90SGreg Roach    {
4470ca9c90SGreg Roach        $x = Uuid::uuid4()->toString();
4570ca9c90SGreg Roach        $y = Uuid::uuid4()->toString();
4670ca9c90SGreg Roach        $z = Uuid::uuid4()->toString();
4770ca9c90SGreg Roach
4870ca9c90SGreg Roach        Session::put('captcha-t', microtime(true));
4970ca9c90SGreg Roach        Session::put('captcha-x', $x);
5070ca9c90SGreg Roach        Session::put('captcha-y', $y);
5170ca9c90SGreg Roach        Session::put('captcha-z', $z);
5270ca9c90SGreg Roach
5370ca9c90SGreg Roach        return view('captcha', [
5470ca9c90SGreg Roach            'x' => $x,
5570ca9c90SGreg Roach            'y' => $y,
5670ca9c90SGreg Roach            'z' => $z,
5770ca9c90SGreg Roach        ]);
5870ca9c90SGreg Roach    }
5970ca9c90SGreg Roach
6070ca9c90SGreg Roach    /**
6170ca9c90SGreg Roach     * Check the user's response.
6270ca9c90SGreg Roach     *
6370ca9c90SGreg Roach     * @param ServerRequestInterface $request
6470ca9c90SGreg Roach     *
6570ca9c90SGreg Roach     * @return bool
6670ca9c90SGreg Roach     */
6770ca9c90SGreg Roach    public function isRobot(ServerRequestInterface $request): bool
6870ca9c90SGreg Roach    {
69d8809d62SGreg Roach        $t = Session::pull('captcha-t');
70d8809d62SGreg Roach        $x = Session::pull('captcha-x');
71d8809d62SGreg Roach        $y = Session::pull('captcha-y');
72d8809d62SGreg Roach        $z = Session::pull('captcha-z');
7370ca9c90SGreg Roach
74b55cbc6bSGreg Roach        assert(is_int($t));
75b55cbc6bSGreg Roach        assert(is_string($x));
76b55cbc6bSGreg Roach        assert(is_string($y));
77b55cbc6bSGreg Roach        assert(is_string($z));
78b55cbc6bSGreg Roach
79b55cbc6bSGreg Roach        $value_x = Validator::parsedBody($request)->string($x, '');
80b55cbc6bSGreg Roach        $value_y = Validator::parsedBody($request)->string($y, '');
8170ca9c90SGreg Roach
8270ca9c90SGreg Roach        // The captcha uses javascript to copy value z from field y to field x.
8370ca9c90SGreg Roach        // Expect it in both fields.
8470ca9c90SGreg Roach        if ($value_x !== $z || $value_y !== $z) {
8570ca9c90SGreg Roach            return true;
8670ca9c90SGreg Roach        }
8770ca9c90SGreg Roach
8870ca9c90SGreg Roach        // If the form was returned too quickly, the probably a robot.
8970ca9c90SGreg Roach        return microtime(true) < $t + self::MINIMUM_FORM_TIME;
9070ca9c90SGreg Roach    }
9170ca9c90SGreg Roach}
92