Failed Conditions
Push — newinternal-releasecandidate ( 2e1778...b14046 )
by Simon
15:26 queued 05:35
created

InternalPageBase::setIdentificationVerifier()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 1
1
<?php
2
/******************************************************************************
3
 * Wikipedia Account Creation Assistance tool                                 *
4
 *                                                                            *
5
 * All code in this file is released into the public domain by the ACC        *
6
 * Development Team. Please see team.json for a list of contributors.         *
7
 ******************************************************************************/
8
9
namespace Waca\Tasks;
10
11
use Exception;
12
use PDO;
13
use Waca\DataObjects\SiteNotice;
14
use Waca\DataObjects\User;
15
use Waca\Exceptions\AccessDeniedException;
16
use Waca\Exceptions\NotIdentifiedException;
17
use Waca\Fragments\NavigationMenuAccessControl;
18
use Waca\Helpers\Interfaces\IBlacklistHelper;
19
use Waca\Helpers\Interfaces\ITypeAheadHelper;
20
use Waca\Security\SecurityManager;
21
use Waca\WebRequest;
22
23
abstract class InternalPageBase extends PageBase
24
{
25
    use NavigationMenuAccessControl;
26
27
    /** @var ITypeAheadHelper */
28
    private $typeAheadHelper;
29
    /** @var SecurityManager */
30
    private $securityManager;
31
    /** @var IBlacklistHelper */
32
    private $blacklistHelper;
33
34
    /**
35
     * @return ITypeAheadHelper
36
     */
37
    public function getTypeAheadHelper()
38
    {
39
        return $this->typeAheadHelper;
40
    }
41
42
    /**
43
     * @param ITypeAheadHelper $typeAheadHelper
44
     */
45
    public function setTypeAheadHelper(ITypeAheadHelper $typeAheadHelper)
46
    {
47
        $this->typeAheadHelper = $typeAheadHelper;
48
    }
49
50
    /**
51
     * Runs the page code
52
     *
53
     * @throws Exception
54
     * @category Security-Critical
55
     */
56
    final public function execute()
57
    {
58
        if ($this->getRouteName() === null) {
0 ignored issues
show
introduced by
The condition $this->getRouteName() === null is always false.
Loading history...
59
            throw new Exception("Request is unrouted.");
60
        }
61
62
        if ($this->getSiteConfiguration() === null) {
63
            throw new Exception("Page has no configuration!");
64
        }
65
66
        $this->setupPage();
67
68
        $this->touchUserLastActive();
69
70
        $currentUser = User::getCurrent($this->getDatabase());
71
72
        // Hey, this is also a security barrier, in addition to the below. Separated out for readability.
73
        if (!$this->isProtectedPage()) {
74
            // This page is /not/ a protected page, as such we can just run it.
75
            $this->runPage();
76
77
            return;
78
        }
79
80
        // Security barrier.
81
        //
82
        // This code essentially doesn't care if the user is logged in or not, as the security manager hides all that
83
        // away for us
84
        $securityResult = $this->getSecurityManager()->allows(get_called_class(), $this->getRouteName(), $currentUser);
85
        if ($securityResult === SecurityManager::ALLOWED) {
86
            // We're allowed to run the page, so let's run it.
87
            $this->runPage();
88
        }
89
        else {
90
            $this->handleAccessDenied($securityResult);
91
92
            // Send the headers
93
            $this->sendResponseHeaders();
94
        }
95
    }
96
97
    /**
98
     * Performs final tasks needed before rendering the page.
99
     */
100
    final public function finalisePage()
101
    {
102
        parent::finalisePage();
103
104
        $database = $this->getDatabase();
105
        $currentUser = User::getCurrent($database);
106
107
        if ($this->barrierTest('viewSiteNotice', User::getCurrent($database), 'GlobalInfo')) {
108
            $siteNoticeText = SiteNotice::get($this->getDatabase());
109
            $this->assign('siteNoticeText', $siteNoticeText);
110
        }
111
112
        if ($this->barrierTest('viewOnlineUsers', User::getCurrent($database), 'GlobalInfo')) {
113
            $sql = 'SELECT * FROM user WHERE lastactive > DATE_SUB(CURRENT_TIMESTAMP(), INTERVAL 5 MINUTE);';
114
            $statement = $database->query($sql);
115
            $activeUsers = $statement->fetchAll(PDO::FETCH_CLASS, User::class);
116
            $this->assign('onlineusers', $activeUsers);
117
        }
118
119
        $this->setupNavMenuAccess($currentUser);
120
    }
121
122
    /**
123
     * Configures whether the page respects roles or not. You probably want this to return true.
124
     *
125
     * Set to false for public pages. You probably want this to return true.
126
     *
127
     * This defaults to true unless you explicitly set it to false. Setting it to false means anybody can do anything
128
     * on this page, so you probably want this to return true.
129
     *
130
     * @return bool
131
     * @category Security-Critical
132
     */
133
    protected function isProtectedPage()
134
    {
135
        return true;
136
    }
137
138
    protected function handleAccessDenied($denyReason)
139
    {
140
        $currentUser = User::getCurrent($this->getDatabase());
141
142
        // Not allowed to access this resource.
143
        // Firstly, let's check if we're even logged in.
144
        if ($currentUser->isCommunityUser()) {
145
            // Not logged in, redirect to login page
146
            WebRequest::setPostLoginRedirect();
147
            $this->redirect("login");
148
149
            return;
150
        }
151
        else {
152
            // Decide whether this was a rights failure, or an identification failure.
153
154
            if ($denyReason === SecurityManager::ERROR_NOT_IDENTIFIED) {
155
                // Not identified
156
                throw new NotIdentifiedException($this->getSecurityManager());
157
            }
158
            elseif ($denyReason === SecurityManager::ERROR_DENIED) {
159
                // Nope, plain old access denied
160
                throw new AccessDeniedException($this->getSecurityManager());
161
            }
162
            else {
163
                throw new Exception('Unknown response from security manager.');
164
            }
165
        }
166
    }
167
168
    /**
169
     * Tests the security barrier for a specified action.
170
     *
171
     * Don't use within templates
172
     *
173
     * @param string      $action
174
     *
175
     * @param User        $user
176
     * @param null|string $pageName
177
     *
178
     * @return bool
179
     * @category Security-Critical
180
     */
181
    final public function barrierTest($action, User $user, $pageName = null)
182
    {
183
        $page = get_called_class();
184
        if ($pageName !== null) {
185
            $page = $pageName;
186
        }
187
188
        $securityResult = $this->getSecurityManager()->allows($page, $action, $user);
189
190
        return $securityResult === SecurityManager::ALLOWED;
191
    }
192
193
    /**
194
     * Updates the lastactive timestamp
195
     */
196
    private function touchUserLastActive()
197
    {
198
        if (WebRequest::getSessionUserId() !== null) {
199
            $query = 'UPDATE user SET lastactive = CURRENT_TIMESTAMP() WHERE id = :id;';
200
            $this->getDatabase()->prepare($query)->execute(array(":id" => WebRequest::getSessionUserId()));
201
        }
202
    }
203
204
    /**
205
     * @return SecurityManager
206
     */
207
    public function getSecurityManager()
208
    {
209
        return $this->securityManager;
210
    }
211
212
    /**
213
     * @param SecurityManager $securityManager
214
     */
215
    public function setSecurityManager(SecurityManager $securityManager)
216
    {
217
        $this->securityManager = $securityManager;
218
    }
219
220
    /**
221
     * @return IBlacklistHelper
222
     */
223
    public function getBlacklistHelper()
224
    {
225
        return $this->blacklistHelper;
226
    }
227
228
    /**
229
     * @param IBlacklistHelper $blacklistHelper
230
     */
231
    public function setBlacklistHelper(IBlacklistHelper $blacklistHelper)
232
    {
233
        $this->blacklistHelper = $blacklistHelper;
234
    }
235
}
236