Passed
Push — 4.1 ( 6d2665...02ad0f )
by
unknown
32:36 queued 24:09
created

ConfirmationTokenChain   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 161
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 48
dl 0
loc 161
rs 10
c 0
b 0
f 0
wmc 25

11 Methods

Rating   Name   Duplication   Size   Complexity  
A suppressTokens() 0 4 2
A filteredTokens() 0 5 4
A reloadRequired() 0 9 3
A pushToken() 0 3 1
A reloadWithTokens() 0 15 1
A getRedirectUrlParams() 0 8 2
A suppressionRequired() 0 9 3
A redirectURL() 0 4 1
A params() 0 8 2
A reloadRequiredIfError() 0 9 3
A getRedirectUrlBase() 0 15 3
1
<?php
2
3
namespace SilverStripe\Core\Startup;
4
5
use SilverStripe\Control\Controller;
6
use SilverStripe\Control\Director;
7
use SilverStripe\Control\HTTPResponse;
8
use SilverStripe\Core\Convert;
9
10
/**
11
 * A chain of confirmation tokens to be validated on each request. This allows the application to
12
 * check multiple tokens at once without having to potentially redirect the user for each of them
13
 *
14
 * @internal This class is designed specifically for use pre-startup and may change without warning
15
 */
16
class ConfirmationTokenChain
17
{
18
    /**
19
     * @var array
20
     */
21
    protected $tokens = [];
22
23
    /**
24
     * @param AbstractConfirmationToken $token
25
     */
26
    public function pushToken(AbstractConfirmationToken $token)
27
    {
28
        $this->tokens[] = $token;
29
    }
30
31
    /**
32
     * Collect all tokens that require a redirect
33
     *
34
     * @return \Generator
35
     */
36
    protected function filteredTokens()
37
    {
38
        foreach ($this->tokens as $token) {
39
            if ($token->reloadRequired() || $token->reloadRequiredIfError()) {
40
                yield $token;
41
            }
42
        }
43
    }
44
45
    /**
46
     * @return bool
47
     */
48
    public function suppressionRequired()
49
    {
50
        foreach ($this->tokens as $token) {
51
            if ($token->reloadRequired()) {
52
                return true;
53
            }
54
        }
55
56
        return false;
57
    }
58
59
    /**
60
     * Suppress URLs & GET vars from tokens that require a redirect
61
     */
62
    public function suppressTokens()
63
    {
64
        foreach ($this->filteredTokens() as $token) {
65
            $token->suppress();
66
        }
67
    }
68
69
    /**
70
     * @return bool
71
     */
72
    public function reloadRequired()
73
    {
74
        foreach ($this->tokens as $token) {
75
            if ($token->reloadRequired()) {
76
                return true;
77
            }
78
        }
79
80
        return false;
81
    }
82
83
    /**
84
     * @return bool
85
     */
86
    public function reloadRequiredIfError()
87
    {
88
        foreach ($this->tokens as $token) {
89
            if ($token->reloadRequiredIfError()) {
90
                return true;
91
            }
92
        }
93
94
        return false;
95
    }
96
97
    /**
98
     * @param bool $includeToken
99
     * @return array
100
     */
101
    public function params($includeToken = true)
102
    {
103
        $params = [];
104
        foreach ($this->tokens as $token) {
105
            $params = array_merge($params, $token->params($includeToken));
106
        }
107
108
        return $params;
109
    }
110
111
    /**
112
     * Fetch the URL we want to redirect to, excluding query string parameters. This may
113
     * be the same URL (with a token to be added outside this method), or to a different
114
     * URL if the current one has been suppressed
115
     *
116
     * @return string
117
     */
118
    public function getRedirectUrlBase()
119
    {
120
        // URLConfirmationTokens may alter the URL to suppress the URL they're protecting,
121
        // so we need to ensure they're inspected last and therefore take priority
122
        $tokens = iterator_to_array($this->filteredTokens(), false);
123
        usort($tokens, function ($a, $b) {
0 ignored issues
show
Unused Code introduced by
The parameter $b is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

123
        usort($tokens, function ($a, /** @scrutinizer ignore-unused */ $b) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
124
            return ($a instanceof URLConfirmationToken) ? 1 : 0;
125
        });
126
127
        $urlBase = Director::baseURL();
128
        foreach ($tokens as $token) {
129
            $urlBase = $token->getRedirectUrlBase();
130
        }
131
132
        return $urlBase;
133
    }
134
135
    /**
136
     * Collate GET vars from all token providers that need to apply a token
137
     *
138
     * @return array
139
     */
140
    public function getRedirectUrlParams()
141
    {
142
        $params = [];
143
        foreach ($this->filteredTokens() as $token) {
144
            $params = array_merge($params, $token->getRedirectUrlParams());
145
        }
146
147
        return $params;
148
    }
149
150
    /**
151
     * @return string
152
     */
153
    protected function redirectURL()
154
    {
155
        $params = http_build_query($this->getRedirectUrlParams());
156
        return Controller::join_links($this->getRedirectUrlBase(), '?' . $params);
157
    }
158
159
    /**
160
     * @return HTTPResponse
161
     */
162
    public function reloadWithTokens()
163
    {
164
        $location = $this->redirectURL();
165
        $locationJS = Convert::raw2js($location);
166
        $locationATT = Convert::raw2att($location);
167
        $body = <<<HTML
168
<script>location.href='$locationJS';</script>
169
<noscript><meta http-equiv="refresh" content="0; url=$locationATT"></noscript>
170
You are being redirected. If you are not redirected soon, <a href="$locationATT">click here to continue</a>
171
HTML;
172
173
        // Build response
174
        $result = new HTTPResponse($body);
175
        $result->redirect($location);
176
        return $result;
177
    }
178
}
179