Merge branch '3.0'
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / system / WCFACP.class.php
1 <?php
2 namespace wcf\system;
3 use wcf\acp\form\MasterPasswordForm;
4 use wcf\acp\form\MasterPasswordInitForm;
5 use wcf\data\menu\Menu;
6 use wcf\data\menu\MenuCache;
7 use wcf\system\application\ApplicationHandler;
8 use wcf\system\cache\builder\ACPSearchProviderCacheBuilder;
9 use wcf\system\event\EventHandler;
10 use wcf\system\exception\AJAXException;
11 use wcf\system\exception\PermissionDeniedException;
12 use wcf\system\exception\SystemException;
13 use wcf\system\request\LinkHandler;
14 use wcf\system\request\RouteHandler;
15 use wcf\system\session\ACPSessionFactory;
16 use wcf\system\session\SessionHandler;
17 use wcf\system\template\ACPTemplateEngine;
18 use wcf\util\FileUtil;
19 use wcf\util\HeaderUtil;
20
21 /**
22 * Extends WCF class with functions for the ACP.
23 *
24 * @author Marcel Werk
25 * @copyright 2001-2018 WoltLab GmbH
26 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
27 * @package WoltLabSuite\Core\System
28 */
29 class WCFACP extends WCF {
30 /**
31 * rescue mode
32 * @var boolean
33 */
34 protected static $inRescueMode;
35
36 /**
37 * URL to WCF within rescue mode
38 * @var string
39 */
40 protected static $rescueModePageURL;
41
42 /** @noinspection PhpMissingParentConstructorInspection */
43 /**
44 * Calls all init functions of the WCF and the WCFACP class.
45 */
46 public function __construct() {
47 // add autoload directory
48 self::$autoloadDirectories['wcf'] = WCF_DIR . 'lib/';
49
50 // define tmp directory
51 if (!defined('TMP_DIR')) define('TMP_DIR', FileUtil::getTempFolder());
52
53 // start initialization
54 $this->initDB();
55 $this->loadOptions();
56 $this->initPackage();
57 $this->initSession();
58 $this->initLanguage();
59 $this->initTPL();
60 $this->initCronjobs();
61 $this->initCoreObjects();
62
63 // prevent application loading during setup
64 if (PACKAGE_ID) {
65 $this->initApplications();
66 }
67
68 $this->initBlacklist();
69 $this->initAuth();
70
71 EventHandler::getInstance()->fireAction($this, 'initialized');
72 }
73
74 /**
75 * Returns the main menu object.
76 *
77 * @return Menu|null menu object
78 * @since 3.0
79 */
80 public function getFrontendMenu() {
81 return MenuCache::getInstance()->getMainMenu();
82 }
83
84 /**
85 * Returns true if ACP is currently in rescue mode.
86 *
87 * @return boolean
88 */
89 public static function inRescueMode() {
90 if (self::$inRescueMode === null) {
91 self::$inRescueMode = false;
92
93 if (PACKAGE_ID && isset($_SERVER['HTTP_HOST'])) {
94 self::$inRescueMode = true;
95
96 foreach (ApplicationHandler::getInstance()->getApplications() as $application) {
97 if ($application->domainName === $_SERVER['HTTP_HOST']) {
98 self::$inRescueMode = false;
99 break;
100 }
101 }
102
103 if (self::$inRescueMode) {
104 self::$rescueModePageURL = RouteHandler::getProtocol() . $_SERVER['HTTP_HOST'] . RouteHandler::getPath(['acp']);
105 }
106 }
107 }
108
109 return self::$inRescueMode;
110 }
111
112 /**
113 * Returns URL for rescue mode page.
114 *
115 * @return string
116 */
117 public static function getRescueModePageURL() {
118 if (self::inRescueMode()) {
119 return self::$rescueModePageURL;
120 }
121
122 return '';
123 }
124
125 /**
126 * Does the user authentication.
127 */
128 protected function initAuth() {
129 // this is a work-around since neither RequestHandler
130 // nor RouteHandler are populated right now
131 $pathInfo = RouteHandler::getPathInfo();
132
133 if (self::inRescueMode()) {
134 if (!preg_match('~^/?rescue-mode/~', $pathInfo)) {
135 $redirectURI = self::$rescueModePageURL . 'acp/index.php?rescue-mode/';
136
137 HeaderUtil::redirect($redirectURI);
138 exit;
139 }
140 }
141 else if (empty($pathInfo) || !preg_match('~^/?(acp-?captcha|login|logout)/~i', $pathInfo)) {
142 if (WCF::getUser()->userID == 0) {
143 // work-around for AJAX-requests within ACP
144 if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
145 throw new AJAXException(WCF::getLanguage()->getDynamicVariable('wcf.ajax.error.sessionExpired'), AJAXException::SESSION_EXPIRED, '');
146 }
147
148 // build redirect path
149 $application = ApplicationHandler::getInstance()->getActiveApplication();
150 if ($application === null) {
151 throw new SystemException("You have aborted the installation, therefore this installation is unusable. You are required to reinstall the software.");
152 }
153
154 HeaderUtil::redirect(
155 LinkHandler::getInstance()->getLink('Login', [
156 'url' => RouteHandler::getProtocol() . $_SERVER['HTTP_HOST'] . WCF::getSession()->requestURI
157 ])
158 );
159 exit;
160 }
161 else {
162 // work-around for AJAX-requests within ACP
163 if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
164 try {
165 WCF::getSession()->checkPermissions(['admin.general.canUseAcp']);
166 }
167 catch (PermissionDeniedException $e) {
168 throw new AJAXException(self::getLanguage()->getDynamicVariable('wcf.ajax.error.permissionDenied'), AJAXException::INSUFFICIENT_PERMISSIONS, $e->getTraceAsString());
169 }
170 }
171 else {
172 WCF::getSession()->checkPermissions(['admin.general.canUseAcp']);
173 }
174
175 // force debug mode if in ACP and authenticated
176 self::$overrideDebugMode = true;
177 }
178 }
179 }
180
181 /**
182 * @inheritDoc
183 */
184 protected function initSession() {
185 self::$sessionObj = SessionHandler::getInstance();
186 self::$sessionObj->setCookieSuffix('_acp');
187
188 $factory = new ACPSessionFactory();
189 $factory->load();
190
191 self::$sessionObj->setHasValidCookie($factory->hasValidCookie());
192 }
193
194 /**
195 * @inheritDoc
196 */
197 protected function initTPL() {
198 self::$tplObj = ACPTemplateEngine::getInstance();
199 self::getTPL()->setLanguageID(self::getLanguage()->languageID);
200 $this->assignDefaultTemplateVariables();
201 }
202
203 /**
204 * @inheritDoc
205 */
206 protected function assignDefaultTemplateVariables() {
207 parent::assignDefaultTemplateVariables();
208
209 // base tag is determined on runtime
210 $host = RouteHandler::getHost();
211 $path = RouteHandler::getPath();
212
213 // available acp search providers
214 $availableAcpSearchProviders = [];
215 foreach (ACPSearchProviderCacheBuilder::getInstance()->getData() as $searchProvider) {
216 $availableAcpSearchProviders[$searchProvider->providerName] = self::getLanguage()->get('wcf.acp.search.provider.'.$searchProvider->providerName);
217 }
218 asort($availableAcpSearchProviders);
219
220 self::getTPL()->assign([
221 'baseHref' => $host . $path,
222 'availableAcpSearchProviders' => $availableAcpSearchProviders
223 ]);
224 }
225
226 /**
227 * Initializes the active package.
228 */
229 protected function initPackage() {
230 // define active package id
231 if (!defined('PACKAGE_ID')) {
232 define('PACKAGE_ID', 1);
233 }
234 }
235
236 /**
237 * Checks whether the active user has entered the valid master password.
238 */
239 public static function checkMasterPassword() {
240 if (defined('MODULE_MASTER_PASSWORD') && MODULE_MASTER_PASSWORD == 1 && !WCF::getSession()->getVar('masterPassword')) {
241 if (file_exists(WCF_DIR.'acp/masterPassword.inc.php')) {
242 require_once(WCF_DIR.'acp/masterPassword.inc.php');
243 }
244 if (defined('MASTER_PASSWORD')) {
245 $form = new MasterPasswordForm();
246 $form->__run();
247 exit;
248 }
249 else {
250 $form = new MasterPasswordInitForm();
251 $form->__run();
252 exit;
253 }
254 }
255 }
256 }