Issues (186)

Branch: master

includes/WebStart.php (1 issue)

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