Completed
Push — master ( 81f221...a04b20 )
by Michael
02:43
created

Middleware::add()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 17
rs 9.2
c 1
b 0
f 0
cc 4
eloc 10
nc 4
nop 1
1
<?php
2
3
namespace Schnittstabil\Psr7\Csrf;
4
5
use Schnittstabil\Csrf\TokenService;
6
use Schnittstabil\Csrf\TokenServiceInterface;
7
use Schnittstabil\Psr7\Csrf\Middlewares\AcceptHeaderToken;
8
use Schnittstabil\Psr7\Csrf\Middlewares\AcceptMethods;
9
use Schnittstabil\Psr7\Csrf\Middlewares\AcceptParsedBodyToken;
10
use Schnittstabil\Psr7\Csrf\Middlewares\Guard;
11
use Schnittstabil\Psr7\Csrf\Middlewares\GuardInterface;
12
use Schnittstabil\Psr7\Csrf\Middlewares\RespondWithCookieToken;
13
use Schnittstabil\Psr7\Csrf\Middlewares\RespondWithHeaderToken;
14
use Schnittstabil\Psr7\Middleware\Stack as MiddlewareStack;
15
16
/**
17
 * CSRF protection middleware.
18
 */
19
class Middleware extends MiddlewareStack
20
{
21
    protected $isGuarded;
22
    protected $tokenService;
23
24
    /**
25
     * Create a new Middleware.
26
     *
27
     * @param TokenServiceInterface $tokenService A token service.
28
     */
29
    public function __construct(TokenServiceInterface $tokenService)
30
    {
31
        parent::__construct();
32
        $this->isGuarded = false;
33
        $this->tokenService = $tokenService;
34
    }
35
36
    /**
37
     * Get the token service.
38
     *
39
     * @return TokenServiceInterface
40
     */
41
    public function getTokenService()
42
    {
43
        return $this->tokenService;
44
    }
45
46
    /**
47
     * Push a middleware onto the top of a new Stack instance.
48
     *
49
     * @param callable $newTopMiddleware the middleware to be pushed onto the top.
50
     *
51
     * @return static the new instance
52
     *
53
     * @SuppressWarnings(PHPMD.ElseExpression)
54
     */
55
    public function add(callable $newTopMiddleware)
56
    {
57
        if ($this->isGuarded) {
58
            if ($newTopMiddleware instanceof GuardInterface) {
59
                throw new \RuntimeException('Invalid state: already guarded');
60
            }
61
        } else {
62
            if (!($newTopMiddleware instanceof GuardInterface)) {
63
                throw new \RuntimeException('Invalid state: not guarded');
64
            }
65
        }
66
67
        $clone = parent::add($newTopMiddleware);
68
        $clone->isGuarded = true;
69
70
        return $clone;
71
    }
72
73
    /**
74
     * Add new Guard middleware.
75
     *
76
     * @param callable $rejectMiddleware Defaults to `new Reject()`.
77
     *
78
     * @return static
79
     */
80
    public function withGuard(callable $rejectMiddleware = null)
81
    {
82
        return $this->add(new Guard($rejectMiddleware));
83
    }
84
85
    /**
86
     * Add new AcceptHeaderToken middleware.
87
     *
88
     * @param string $headerName Header field name.
89
     *
90
     * @return static
91
     */
92
    public function withAcceptHeaderToken($headerName = 'X-XSRF-TOKEN')
93
    {
94
        return $this->add(new AcceptHeaderToken([$this->tokenService, 'getConstraintViolations'], $headerName));
95
    }
96
97
    /**
98
     * Add new AcceptMethods middleware.
99
     *
100
     * @param string[] $methods HTTP methods allowed to bypass CSRF protection.
101
     *
102
     * @return static
103
     */
104
    public function withAcceptMethods(array $methods = array('GET', 'OPTIONS'))
105
    {
106
        return $this->add(new AcceptMethods($methods));
107
    }
108
109
    /**
110
     * Add new AcceptParsedBodyToken middleware.
111
     *
112
     * @param string|int|mixed[] $path <a href="https://github.com/schnittstabil/get" target="_blank">See `Get::value` for details</a>
113
     *
114
     * @return static
115
     */
116
    public function withAcceptParsedBodyToken($path = 'X-XSRF-TOKEN')
117
    {
118
        return $this->add(new AcceptParsedBodyToken([$this->tokenService, 'getConstraintViolations'], $path));
119
    }
120
121
    /**
122
     * Add new RespondWithCookieToken middleware.
123
     *
124
     * @param string   $cookieName Cookie name.
125
     * @param callable $modify     Allows to modify the cookie; same signature as `$this->modifyCookie`.
126
     *
127
     * @return static
128
     */
129
    public function withRespondWithCookieToken($cookieName = 'XSRF-TOKEN', callable $modify = null)
130
    {
131
        return $this->add(new RespondWithCookieToken([$this->tokenService, 'generate'], $cookieName, $modify));
132
    }
133
134
    /**
135
     * Add new RespondWithHeaderToken middleware.
136
     *
137
     * @param string $headerName Header field name.
138
     *
139
     * @return static
140
     */
141
    public function withRespondWithHeaderToken($headerName = 'XSRF-TOKEN')
142
    {
143
        return $this->add(new RespondWithHeaderToken([$this->tokenService, 'generate'], $headerName));
144
    }
145
}
146