]> jfr.im git - irc/unrealircd/unrealircd-webpanel.git/blob - common.php
It is now mandatory to load an auth provider: either sql_auth or file_auth.
[irc/unrealircd/unrealircd-webpanel.git] / common.php
1 <?php
2 if (version_compare(PHP_VERSION, '8.0.0', '<'))
3 die("This webserver is using PHP version ".PHP_VERSION." but we require at least PHP 8.0.0.<br>".
4 "If you already installed PHP8 but are still seeing this error, then it means ".
5 "apache/nginx/.. is loading an older PHP version. Eg. on Debian/Ubuntu you need ".
6 "<code>apt-get install libapache2-mod-php8.2</code> (or a similar version) and ".
7 "<code>apt-get remove libapache2-mod-php7.4</code> (or a similar version). ".
8 "You may also need to choose again the PHP module to load in apache via <code>a2enmod php8.2</code>");
9
10 define('UPATH', dirname(__FILE__));
11
12 function get_config($setting)
13 {
14 GLOBAL $config;
15
16 $item = $config;
17 foreach(explode("::", $setting) as $x)
18 {
19 if (isset($item[$x]))
20 $item = $item[$x];
21 else
22 return NULL;
23 }
24 return $item;
25 }
26
27 function page_requires_no_config()
28 {
29 if (str_ends_with($_SERVER['SCRIPT_FILENAME'],"install.php") ||
30 str_ends_with($_SERVER['SCRIPT_FILENAME'],"installation.php"))
31 {
32 return TRUE;
33 }
34 return FALSE;
35 }
36
37 function page_requires_no_login()
38 {
39 if (str_ends_with($_SERVER['SCRIPT_FILENAME'],"login/index.php") ||
40 page_requires_no_config())
41 {
42 return TRUE;
43 }
44 return FALSE;
45 }
46
47 function read_config_file()
48 {
49 GLOBAL $config;
50 GLOBAL $config_transition_unreal_server;
51
52 $config = Array();
53 if (!file_exists(UPATH."/config/config.php") && file_exists(UPATH."/config.php"))
54 {
55 require_once UPATH . "/config.php";
56 require_once UPATH . "/config/compat.php";
57 }
58 if ((@include(UPATH . "/config/config.php")) !== 1)
59 return false;
60 if (isset($config['unrealircd']))
61 $config_transition_unreal_server = true;
62 return true;
63 }
64
65 function read_config_db()
66 {
67 GLOBAL $config;
68
69 if (page_requires_no_config())
70 return;
71
72 $merge = DbSettings::get();
73 /* DB settings overwrite config.php keys: */
74 $config = array_merge($config, $merge);
75 }
76
77 function config_is_file_item($name)
78 {
79 if (($name == "plugins") ||
80 ($name == "mysql") ||
81 ($name == "base_url"))
82 {
83 return true;
84 }
85 return false;
86 }
87
88 function write_config_file()
89 {
90 GLOBAL $config;
91
92 $file_settings = [];
93 foreach($config as $k=>$v)
94 {
95 if (config_is_file_item($k))
96 $file_settings[$k] = $v;
97 }
98
99 $cfg_filename = UPATH.'/config/config.php';
100 $tmpfile = UPATH.'/config/config.tmp.'.bin2hex(random_bytes(8)).'.php';
101 $fd = fopen($tmpfile, "w");
102 if (!$fd)
103 die("Could not write to temporary config file $tmpfile.<br>We need write permissions on the config/ directory!<br>");
104
105 $str = var_export($file_settings, true);
106 if ($str === null)
107 die("Error while running write_config_file() -- weird!");
108 if (!fwrite($fd, "<?php\n".
109 "/* This config file is written automatically by the UnrealIRCd webpanel.\n".
110 " * You are not really supposed to edit it manually.\n".
111 " */\n".
112 '$config = '.$str.";\n"))
113 {
114 die("Error writing to config file $tmpfile (on fwrite).<br>");
115 }
116 if (!fclose($fd))
117 die("Error writing to config file $tmpfile (on close).<br>");
118 /* Now atomically rename the file */
119 if (!rename($tmpfile, $cfg_filename))
120 die("Could not write (rename) to file ".$cfg_filename."<br>");
121 opcache_invalidate($cfg_filename);
122
123 /* Do not re-read config, as it would reinitialize config
124 * without having the DB settings read. (And it also
125 * serves no purpose)
126 */
127 return true;
128 }
129
130 // XXX: handle unsetting of config items :D - explicit unset function ?
131
132 function write_config($setting = null)
133 {
134 GLOBAL $config;
135
136 /* Specific request? Easy, write only this setting to the DB (never used for file) */
137 if ($setting !== null)
138 {
139 return DbSettings::set($setting, $config[$setting]);
140 }
141
142 /* Otherwise write the whole config.
143 * TODO: avoid writing settings file if unneeded,
144 * as it is more noisy than db settings.
145 */
146 $db_settings = [];
147
148 foreach($config as $k=>$v)
149 {
150 if (!config_is_file_item($k))
151 $db_settings[$k] = $v;
152 }
153
154 if (!write_config_file())
155 return false;
156
157 foreach($db_settings as $k=>$v)
158 {
159 $ret = DbSettings::set($k, $v);
160 if (!$ret)
161 return $ret;
162 }
163
164 return true;
165 }
166
167 function get_version()
168 {
169 $fd = @fopen(UPATH."/.git/FETCH_HEAD", "r");
170 if ($fd === false)
171 return "unknown";
172 $line = fgets($fd, 512);
173 fclose($fd);
174 $commit = substr($line, 0, 8);
175 return $commit; /* short git commit id */
176 }
177
178 function upgrade_check()
179 {
180 GLOBAL $config_transition_unreal_server;
181
182 /* Moving of a config.php item to DB: */
183 if ($config_transition_unreal_server)
184 write_config();
185
186 $version = get_version();
187 if (!isset($config['webpanel_version']))
188 $config['webpanel_version'] = '';
189 if ($version != $config['webpanel_version'])
190 {
191 $versioninfo = [
192 "old_version" => $config['webpanel_version'],
193 "new_version" => $version
194 ];
195 Hook::run(HOOKTYPE_UPGRADE, $versioninfo);
196 /* And set the new version now that the upgrade is "done" */
197 $config['webpanel_version'] = $version;
198 write_config("webpanel_version");
199 }
200 }
201
202 function panel_start_session($user = false)
203 {
204 if (!isset($_SESSION))
205 {
206 session_set_cookie_params(86400); // can't set this to session_timeout due to catch-22
207 session_start();
208 }
209
210 if ($user === false)
211 {
212 $user = unreal_get_current_user();
213 if ($user === false)
214 return false;
215 }
216
217 $timeout = 3600;
218 if (isset($user->user_meta['session_timeout']))
219 $timeout = (INT)$user->user_meta['session_timeout'];
220
221 if (!isset($_SESSION['session_timeout']))
222 $_SESSION['session_timeout'] = $timeout;
223
224 $_SESSION['last-activity'] = time();
225 return true;
226 }
227
228 /* Now read the config, and redirect to install screen if we don't have it */
229 $config_transition_unreal_server = false;
230 if (!read_config_file())
231 {
232 if (page_requires_no_config())
233 {
234 /* Allow empty conf */
235 } else
236 if (!file_exists(UPATH."/config/config.php") && !file_exists(UPATH."/config.php"))
237 {
238 header("Location: settings/install.php");
239 die();
240 }
241 }
242
243 require_once "Classes/class-hook.php";
244 if (!is_dir(UPATH . "/vendor"))
245 die("The vendor/ directory is missing. Most likely the admin forgot to run 'composer install'\n");
246 require_once UPATH . '/vendor/autoload.php';
247 require_once UPATH . "/Classes/class-cmodes.php";
248 require_once UPATH . "/cfg/defines.php";
249 require_once UPATH . "/misc/strings.php";
250 require_once UPATH . "/misc/channel-lookup-misc.php";
251 require_once UPATH . "/misc/user-lookup-misc.php";
252 require_once UPATH . "/misc/server-lookup-misc.php";
253 require_once UPATH . "/misc/ip-whois-misc.php";
254 require_once UPATH . "/Classes/class-log.php";
255 require_once UPATH . "/Classes/class-message.php";
256 require_once UPATH . "/Classes/class-rpc.php";
257 require_once UPATH . "/Classes/class-paneluser.php";
258 require_once UPATH . "/plugins.php";
259
260 /* Do various checks and reading, except during setup step 1. */
261 if (!page_requires_no_config())
262 {
263 /* Now that plugins are loaded, read config from DB */
264 read_config_db();
265
266 /* Check if anything needs upgrading (eg on panel version change) */
267 upgrade_check();
268
269 /* And a check... */
270 if (!get_config("base_url"))
271 die("The base_url was not found in your config. Setup went wrong?");
272 }
273
274 $pages = [
275 "Overview" => "",
276 "Users" => "users",
277 "Channels" => "channels",
278 "Servers" => "servers",
279 "Server Bans" => [
280 "Server Bans" => "server-bans",
281 "Name Bans" => "server-bans/name-bans.php",
282 "Ban Exceptions" => "server-bans/ban-exceptions.php"
283 ],
284 "Spamfilter" => "spamfilter.php",
285 "Tools" => [
286 "IP WHOIS" => "tools/ip-whois.php",
287 ],
288 "Settings" => [
289 "Plugins" => "settings/plugins.php",
290 ],
291
292 "News" => "news.php",
293 ];
294
295 if (!panel_start_session())
296 {
297 if (!page_requires_no_login())
298 {
299 if (!is_auth_provided())
300 die("No authentication plugin loaded. You must load either sql_auth, file_auth, or a similar auth plugin!");
301 $current_page = $_SERVER['REQUEST_URI'];
302 header("Location: ".get_config("base_url")."login/?redirect=".urlencode($current_page));
303 die;
304 }
305 } else {
306 $pages["Settings"]["Accounts"] = "settings";
307
308 $user = unreal_get_current_user();
309 if ($user)
310 {
311 /* Add logout page, if logged in */
312 $pages["Logout"] = "login/?logout=true";
313 }
314 }
315
316 Hook::run(HOOKTYPE_NAVBAR, $pages);
317
318 /* Example to add new menu item:
319 *
320 * class MyPlugin
321 * {
322 *
323 * function __construct()
324 * {
325 * Hook::func(HOOKTYPE_NAVBAR, [$this, 'add_menu'])
326 * }
327 *
328 * function add_menu(&$pages) // this should pass by reference (using the & prefix)
329 * {
330 * $page_name = "My New Page";
331 * $page_link = "link/to/page.php";
332 * $pages[$page_name] = $page_link;
333 * }
334 * }
335 */