Completed
Push — master ( 1b2d0a...89ea1a )
by Oscar
03:00
created

Honeypot::getGenerator()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
namespace Psr7Middlewares\Middleware;
4
5
use Psr7Middlewares\Middleware;
6
use Psr7Middlewares\Utils;
7
use Psr\Http\Message\ServerRequestInterface;
8
use Psr\Http\Message\ResponseInterface;
9
use RuntimeException;
10
11
/**
12
 * Middleware to span protection using the honeypot technique.
13
 */
14
class Honeypot
15
{
16
    use Utils\FormTrait;
17
18
    const KEY_GENERATOR = 'HONEYPOT_GENERATOR';
19
20
    /**
21
     * @var string The honeypot input name
22
     */
23
    private $inputName = 'hpt_name';
24
25
    /**
26
     * @var string The honeypot class name
27
     */
28
    private $inputClass = 'hpt_input';
29
30
    /**
31
     * Returns a callable to generate the inputs.
32
     *
33
     * @param ServerRequestInterface $request
34
     *
35
     * @return callable|null
36
     */
37
    public static function getGenerator(ServerRequestInterface $request)
38
    {
39
        return Middleware::getAttribute($request, self::KEY_GENERATOR);
40
    }
41
42
    /**
43
     * Set the field name.
44
     * 
45
     * @param string $inputName
46
     * 
47
     * @return self
48
     */
49
    public function inputName($inputName)
50
    {
51
        $this->inputName = $inputName;
52
53
        return $this;
54
    }
55
56
    /**
57
     * Set the field class.
58
     * 
59
     * @param string $inputClass
60
     * 
61
     * @return self
62
     */
63
    public function inputClass($inputClass)
64
    {
65
        $this->inputClass = $inputClass;
66
67
        return $this;
68
    }
69
70
    /**
71
     * Execute the middleware.
72
     *
73
     * @param ServerRequestInterface $request
74
     * @param ResponseInterface      $response
75
     * @param callable               $next
76
     *
77
     * @return ResponseInterface
78
     */
79
    public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
80
    {
81
        if (!Middleware::hasAttribute($request, FormatNegotiator::KEY)) {
82
            throw new RuntimeException('Honeypot middleware needs FormatNegotiator executed before');
83
        }
84
85
        if (FormatNegotiator::getFormat($request) !== 'html') {
86
            return $next($request, $response);
87
        }
88
89
        if (Utils\Helpers::isPost($request) && !$this->isValid($request)) {
90
            return $response->withStatus(403);
91
        }
92
93
        $generator = function () {
94
            return '<input type="text" name="'.$this->inputName.'" class="'.$this->inputClass.'">';
95
        };
96
97
        $response = $next($request, $response);
98
99
        return $this->insertIntoPostForms($response, function ($match) use ($generator) {
100
            return $match[0].$generator();
101
        });
102
    }
103
104
    /**
105
     * Check whether the request is valid.
106
     * 
107
     * @param ServerRequestInterface $request
108
     * 
109
     * @return bool
110
     */
111
    private function isValid(ServerRequestInterface $request)
112
    {
113
        $data = $request->getParsedBody();
114
115
        return isset($data[$this->inputName]) && $data[$this->inputName] === '';
116
    }
117
}
118