WebStart::main()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 5
c 2
b 0
f 0
dl 0
loc 12
rs 10
cc 1
nc 1
nop 0
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;
10
11
use Waca\DataObjects\Domain;
12
use Waca\DataObjects\User;
13
use Waca\Exceptions\EnvironmentException;
14
use Waca\Exceptions\ReadableException;
15
use Waca\Helpers\BlacklistHelper;
16
use Waca\Helpers\FakeBlacklistHelper;
17
use Waca\Helpers\TypeAheadHelper;
18
use Waca\Providers\GlobalState\GlobalStateProvider;
19
use Waca\Router\IRequestRouter;
20
use Waca\Security\ContentSecurityPolicyManager;
21
use Waca\Security\DomainAccessManager;
22
use Waca\Security\RoleConfiguration;
23
use Waca\Security\SecurityManager;
24
use Waca\Security\TokenManager;
25
use Waca\Tasks\ITask;
26
use Waca\Tasks\InternalPageBase;
27
use Waca\Tasks\PageBase;
28
29
/**
30
 * Application entry point.
31
 *
32
 * @package Waca
33
 */
34
class WebStart extends ApplicationBase
35
{
36
    /**
37
     * @var IRequestRouter $requestRouter The request router to use. Note that different entry points have different
38
     *                                    routers and hence different URL mappings
39
     */
40
    private $requestRouter;
41
    /**
42
     * @var bool $isPublic Determines whether to use public interface objects or internal interface objects
43
     */
44
    private $isPublic = false;
45
46
    /**
47
     * WebStart constructor.
48
     *
49
     * @param SiteConfiguration $configuration The site configuration
50
     * @param IRequestRouter    $router        The request router to use
51
     */
52
    public function __construct(SiteConfiguration $configuration, IRequestRouter $router)
53
    {
54
        parent::__construct($configuration);
55
56
        $this->requestRouter = $router;
57
    }
58
59
    /**
60
     * @param ITask             $page
61
     * @param SiteConfiguration $siteConfiguration
62
     * @param PdoDatabase       $database
63
     *
64
     * @return void
65
     */
66
    protected function setupHelpers(
67
        ITask $page,
68
        SiteConfiguration $siteConfiguration,
69
        PdoDatabase $database
70
    ) {
71
        parent::setupHelpers($page, $siteConfiguration, $database);
72
73
        if ($page instanceof PageBase) {
74
            $page->setTokenManager(new TokenManager());
75
            $page->setCspManager(new ContentSecurityPolicyManager($siteConfiguration));
76
77
            if ($page instanceof InternalPageBase) {
78
                $page->setTypeAheadHelper(new TypeAheadHelper());
79
80
                $identificationVerifier = new IdentificationVerifier($page->getHttpHelper(), $siteConfiguration, $database);
81
                $page->setSecurityManager(new SecurityManager($identificationVerifier, new RoleConfiguration()));
82
83
                if ($siteConfiguration->getTitleBlacklistEnabled()) {
84
                    $page->setBlacklistHelper(new BlacklistHelper($page->getHttpHelper(), $database));
85
                }
86
                else {
87
                    $page->setBlacklistHelper(new FakeBlacklistHelper());
88
                }
89
90
                $page->setDomainAccessManager(new DomainAccessManager($page->getSecurityManager()));
91
            }
92
        }
93
    }
94
95
    /**
96
     * Application entry point.
97
     *
98
     * Sets up the environment and runs the application, performing any global cleanup operations when done.
99
     */
100
    public function run()
101
    {
102
        try {
103
            if ($this->setupEnvironment()) {
104
                $this->main();
105
            }
106
        }
107
        catch (EnvironmentException $ex) {
108
            ob_end_clean();
109
            print Offline::getOfflineMessage($this->isPublic(), $ex->getMessage());
110
        }
111
            /** @noinspection PhpRedundantCatchClauseInspection */
112
        catch (ReadableException $ex) {
113
            ob_end_clean();
114
            print $ex->getReadableError();
115
        }
116
        finally {
117
            $this->cleanupEnvironment();
118
        }
119
    }
120
121
    /**
122
     * Environment setup
123
     *
124
     * This method initialises the tool environment. If the tool cannot be initialised correctly, it will return false
125
     * and shut down prematurely.
126
     *
127
     * @return bool
128
     * @throws EnvironmentException
129
     */
130
    protected function setupEnvironment()
131
    {
132
        // initialise global exception handler
133
        set_exception_handler(array(ExceptionHandler::class, 'exceptionHandler'));
134
        set_error_handler(array(ExceptionHandler::class, 'errorHandler'), E_RECOVERABLE_ERROR);
135
136
        // start output buffering if necessary
137
        if (ob_get_level() === 0) {
138
            ob_start();
139
        }
140
141
        // initialise super-global providers
142
        WebRequest::setGlobalStateProvider(new GlobalStateProvider());
143
144
        if (Offline::isOffline()) {
145
            print Offline::getOfflineMessage($this->isPublic());
146
            ob_end_flush();
147
148
            return false;
149
        }
150
151
        // Call parent setup
152
        if (!parent::setupEnvironment()) {
153
            return false;
154
        }
155
156
        // Start up sessions
157
        Session::start();
158
159
        // Check the user is allowed to be logged in still. This must be before we call any user-loading functions and
160
        // get the current user cached.
161
        // I'm not sure if this function call being here is particularly a good thing, but it's part of starting up a
162
        // session I suppose.
163
        $this->checkForceLogout();
164
165
        // environment initialised!
166
        return true;
167
    }
168
169
    /**
170
     * Main application logic
171
     */
172
    protected function main()
173
    {
174
        // Get the right route for the request
175
        $page = $this->requestRouter->route();
176
177
        $siteConfiguration = $this->getConfiguration();
178
        $database = PdoDatabase::getDatabaseConnection('acc');
179
180
        $this->setupHelpers($page, $siteConfiguration, $database);
181
182
        // run the route code for the request.
183
        $page->execute();
184
    }
185
186
    /**
187
     * Any cleanup tasks should go here
188
     *
189
     * Note that we need to be very careful here, as exceptions may have been thrown and handled.
190
     * This should *only* be for cleaning up, no logic should go here.
191
     */
192
    protected function cleanupEnvironment()
193
    {
194
        // Clean up anything we splurged after sending the page.
195
        if (ob_get_level() > 0) {
196
            for ($i = ob_get_level(); $i > 0; $i--) {
197
                ob_end_clean();
198
            }
199
        }
200
    }
201
202
    private function checkForceLogout()
203
    {
204
        $database = PdoDatabase::getDatabaseConnection('acc');
205
206
        $sessionUserId = WebRequest::getSessionUserId();
207
        iF ($sessionUserId === null) {
208
            return;
209
        }
210
211
        // Note, User::getCurrent() caches it's result, which we *really* don't want to trigger.
212
        $currentUser = User::getById($sessionUserId, $database);
213
214
        if ($currentUser === false) {
0 ignored issues
show
introduced by
The condition $currentUser === false is always false.
Loading history...
215
            // Umm... this user has a session cookie with a userId set, but no user exists...
216
            Session::restart();
217
218
            $currentUser = User::getCurrent($database);
219
        }
220
221
        if ($currentUser->getForceLogout()) {
222
            Session::restart();
223
224
            $currentUser->setForceLogout(false);
225
            $currentUser->save();
226
        }
227
    }
228
229
    public function isPublic()
230
    {
231
        return $this->isPublic;
232
    }
233
234
    public function setPublic($isPublic)
235
    {
236
        $this->isPublic = $isPublic;
237
    }
238
}
239