2017-12-16 19:17:29 +00:00
|
|
|
<?php
|
|
|
|
namespace Misuzu;
|
|
|
|
|
2019-09-28 22:38:39 +00:00
|
|
|
use PDO;
|
2019-12-12 00:42:28 +00:00
|
|
|
use Misuzu\Net\GeoIP;
|
|
|
|
use Misuzu\Net\IPAddress;
|
2020-05-20 18:09:38 +00:00
|
|
|
use Misuzu\Users\User;
|
|
|
|
use Misuzu\Users\UserNotFoundException;
|
2020-05-25 19:58:06 +00:00
|
|
|
use Misuzu\Users\UserSession;
|
|
|
|
use Misuzu\Users\UserSessionNotFoundException;
|
2019-09-28 22:38:39 +00:00
|
|
|
|
2018-09-16 19:45:40 +00:00
|
|
|
define('MSZ_STARTUP', microtime(true));
|
2018-10-04 20:30:55 +00:00
|
|
|
define('MSZ_ROOT', __DIR__);
|
2019-12-06 01:04:10 +00:00
|
|
|
define('MSZ_CLI', PHP_SAPI === 'cli');
|
2018-10-04 20:30:55 +00:00
|
|
|
define('MSZ_DEBUG', is_file(MSZ_ROOT . '/.debug'));
|
2019-12-03 18:52:20 +00:00
|
|
|
define('MSZ_PHP_MIN_VER', '7.4.0');
|
2019-04-30 20:55:12 +00:00
|
|
|
|
2020-05-12 23:09:03 +00:00
|
|
|
if(version_compare(PHP_VERSION, MSZ_PHP_MIN_VER, '<'))
|
|
|
|
die("Misuzu requires <i>at least</i> PHP <b>" . MSZ_PHP_MIN_VER . "</b> to run.\r\n");
|
|
|
|
if(!extension_loaded('curl') || !extension_loaded('intl') || !extension_loaded('json')
|
|
|
|
|| !extension_loaded('mbstring') || !extension_loaded('pdo') || !extension_loaded('readline')
|
|
|
|
|| !extension_loaded('xml') || !extension_loaded('zip'))
|
|
|
|
die("An extension required by Misuzu hasn't been installed.\r\n");
|
2018-09-16 19:45:40 +00:00
|
|
|
|
2018-09-16 21:03:56 +00:00
|
|
|
error_reporting(MSZ_DEBUG ? -1 : 0);
|
|
|
|
ini_set('display_errors', MSZ_DEBUG ? 'On' : 'Off');
|
|
|
|
|
2020-05-12 23:09:03 +00:00
|
|
|
mb_internal_encoding('utf-8');
|
|
|
|
date_default_timezone_set('utc');
|
2018-10-04 20:30:55 +00:00
|
|
|
set_include_path(get_include_path() . PATH_SEPARATOR . MSZ_ROOT);
|
2018-05-27 23:24:16 +00:00
|
|
|
|
2020-05-12 23:09:03 +00:00
|
|
|
set_exception_handler(function(\Throwable $ex) {
|
2020-05-26 18:44:06 +00:00
|
|
|
if(MSZ_CLI) {
|
2020-05-12 23:09:03 +00:00
|
|
|
echo (string)$ex;
|
|
|
|
} else {
|
2020-05-26 18:44:06 +00:00
|
|
|
http_response_code(500);
|
|
|
|
ob_clean();
|
|
|
|
|
|
|
|
if(MSZ_DEBUG) {
|
|
|
|
header('Content-Type: text/plain; charset=utf-8');
|
|
|
|
echo (string)$ex;
|
|
|
|
} else {
|
|
|
|
header('Content-Type: text/html; charset-utf-8');
|
|
|
|
echo file_get_contents(MSZ_ROOT . '/templates/500.html');
|
|
|
|
}
|
2020-05-12 23:09:03 +00:00
|
|
|
}
|
|
|
|
exit;
|
|
|
|
});
|
|
|
|
|
|
|
|
set_error_handler(function(int $errno, string $errstr, string $errfile, int $errline) {
|
|
|
|
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
|
|
|
|
return true;
|
|
|
|
}, -1);
|
|
|
|
|
2018-09-28 08:56:51 +00:00
|
|
|
require_once 'vendor/autoload.php';
|
2018-08-23 18:13:37 +00:00
|
|
|
|
2020-05-12 23:09:03 +00:00
|
|
|
spl_autoload_register(function(string $className) {
|
|
|
|
$parts = explode('\\', trim($className, '\\'), 2);
|
|
|
|
if($parts[0] !== 'Misuzu')
|
|
|
|
return;
|
|
|
|
|
|
|
|
$classPath = MSZ_ROOT . '/src/' . str_replace('\\', '/', $parts[1]) . '.php';
|
|
|
|
if(is_file($classPath))
|
|
|
|
require_once $classPath;
|
|
|
|
});
|
|
|
|
|
2020-05-14 21:39:38 +00:00
|
|
|
class_alias(\Misuzu\Http\HttpResponseMessage::class, '\HttpResponse');
|
|
|
|
class_alias(\Misuzu\Http\HttpRequestMessage::class, '\HttpRequest');
|
2019-12-13 20:37:17 +00:00
|
|
|
|
2020-05-12 23:09:03 +00:00
|
|
|
require_once 'utility.php';
|
2020-05-16 22:35:11 +00:00
|
|
|
require_once 'src/perms.php';
|
2018-09-28 08:56:51 +00:00
|
|
|
require_once 'src/manage.php';
|
2019-01-24 20:54:24 +00:00
|
|
|
require_once 'src/url.php';
|
2020-05-16 22:35:11 +00:00
|
|
|
require_once 'src/Forum/perms.php';
|
2018-09-28 08:56:51 +00:00
|
|
|
require_once 'src/Forum/forum.php';
|
2019-03-31 16:49:16 +00:00
|
|
|
require_once 'src/Forum/leaderboard.php';
|
2019-04-17 23:59:33 +00:00
|
|
|
require_once 'src/Forum/poll.php';
|
2018-09-28 08:56:51 +00:00
|
|
|
require_once 'src/Forum/post.php';
|
|
|
|
require_once 'src/Forum/topic.php';
|
|
|
|
require_once 'src/Forum/validate.php';
|
2018-10-08 12:29:18 +00:00
|
|
|
require_once 'src/Users/avatar.php';
|
|
|
|
require_once 'src/Users/background.php';
|
2018-09-28 08:56:51 +00:00
|
|
|
require_once 'src/Users/role.php';
|
2020-05-13 21:14:31 +00:00
|
|
|
require_once 'src/Users/user_legacy.php';
|
2018-12-24 20:35:25 +00:00
|
|
|
require_once 'src/Users/warning.php';
|
2018-01-02 19:37:13 +00:00
|
|
|
|
2019-08-14 19:40:36 +00:00
|
|
|
$dbConfig = parse_ini_file(MSZ_ROOT . '/config/config.ini', true, INI_SCANNER_TYPED);
|
2018-10-04 20:30:55 +00:00
|
|
|
|
2019-08-14 19:40:36 +00:00
|
|
|
if(empty($dbConfig)) {
|
|
|
|
echo 'Database config is missing.';
|
|
|
|
exit;
|
2018-09-16 21:03:56 +00:00
|
|
|
}
|
|
|
|
|
2019-09-28 22:38:39 +00:00
|
|
|
$dbConfig = $dbConfig['Database'] ?? $dbConfig['Database.mysql-main'] ?? [];
|
|
|
|
|
2019-12-13 20:37:17 +00:00
|
|
|
DB::init(DB::buildDSN($dbConfig), $dbConfig['username'] ?? '', $dbConfig['password'] ?? '', DB::ATTRS);
|
2019-08-14 19:40:36 +00:00
|
|
|
|
2019-12-03 18:52:20 +00:00
|
|
|
Config::init();
|
2019-12-03 19:09:18 +00:00
|
|
|
Mailer::init(Config::get('mail.method', Config::TYPE_STR), [
|
|
|
|
'host' => Config::get('mail.host', Config::TYPE_STR),
|
|
|
|
'port' => Config::get('mail.port', Config::TYPE_INT, 25),
|
|
|
|
'username' => Config::get('mail.username', Config::TYPE_STR),
|
|
|
|
'password' => Config::get('mail.password', Config::TYPE_STR),
|
|
|
|
'encryption' => Config::get('mail.encryption', Config::TYPE_STR),
|
|
|
|
'sender_name' => Config::get('mail.sender.name', Config::TYPE_STR),
|
|
|
|
'sender_addr' => Config::get('mail.sender.address', Config::TYPE_STR),
|
|
|
|
]);
|
2018-03-14 01:39:02 +00:00
|
|
|
|
2018-10-05 09:14:54 +00:00
|
|
|
// replace this with a better storage mechanism
|
2019-12-03 18:52:20 +00:00
|
|
|
define('MSZ_STORAGE', Config::get('storage.path', Config::TYPE_STR, MSZ_ROOT . '/store'));
|
2019-02-05 20:29:37 +00:00
|
|
|
mkdirs(MSZ_STORAGE, true);
|
2018-10-05 09:14:54 +00:00
|
|
|
|
2020-05-26 18:44:06 +00:00
|
|
|
if(MSZ_CLI) { // Temporary backwards compatibility measure, remove this later
|
2019-06-10 17:04:53 +00:00
|
|
|
if(realpath($_SERVER['SCRIPT_FILENAME']) === __FILE__) {
|
2020-05-26 18:44:06 +00:00
|
|
|
if(($argv[1] ?? '') === 'cron' && ($argv[2] ?? '') === 'low')
|
|
|
|
$argv[2] = '--slow';
|
|
|
|
array_shift($argv);
|
|
|
|
echo shell_exec(__DIR__ . '/msz ' . implode(' ', $argv));
|
|
|
|
}
|
|
|
|
return;
|
2018-07-18 03:06:27 +00:00
|
|
|
}
|
|
|
|
|
2020-05-26 18:44:06 +00:00
|
|
|
// Everything below here should eventually be moved to index.php, probably only initialised when required.
|
|
|
|
// Serving things like the css/js doesn't need to initialise sessions.
|
2019-03-06 10:27:38 +00:00
|
|
|
|
2020-05-26 18:44:06 +00:00
|
|
|
if(!mb_check_encoding()) {
|
|
|
|
http_response_code(415);
|
|
|
|
echo 'Invalid request encoding.';
|
|
|
|
exit;
|
|
|
|
}
|
2019-03-18 20:57:50 +00:00
|
|
|
|
2020-05-26 18:44:06 +00:00
|
|
|
ob_start();
|
2018-07-14 17:57:21 +00:00
|
|
|
|
2020-05-26 18:59:22 +00:00
|
|
|
if(file_exists(MSZ_ROOT . '/.migrating')) {
|
|
|
|
http_response_code(503);
|
|
|
|
if(!isset($_GET['_check'])) {
|
|
|
|
header('Content-Type: text/html; charset-utf-8');
|
|
|
|
echo file_get_contents(MSZ_ROOT . '/templates/503.html');
|
|
|
|
}
|
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
2020-05-26 18:44:06 +00:00
|
|
|
if(!is_readable(MSZ_STORAGE) || !is_writable(MSZ_STORAGE)) {
|
|
|
|
echo 'Cannot access storage directory.';
|
|
|
|
exit;
|
|
|
|
}
|
2018-03-24 04:31:42 +00:00
|
|
|
|
2020-05-26 18:44:06 +00:00
|
|
|
GeoIP::init(Config::get('geoip.database', Config::TYPE_STR, '/var/lib/GeoIP/GeoLite2-Country.mmdb'));
|
2018-10-05 11:00:37 +00:00
|
|
|
|
2020-05-26 18:44:06 +00:00
|
|
|
if(!MSZ_DEBUG) {
|
|
|
|
$twigCache = sys_get_temp_dir() . '/msz-tpl-cache-' . md5(MSZ_ROOT);
|
|
|
|
mkdirs($twigCache, true);
|
|
|
|
}
|
2019-02-05 20:29:37 +00:00
|
|
|
|
2020-05-26 18:44:06 +00:00
|
|
|
Template::init($twigCache ?? null, MSZ_DEBUG);
|
2018-09-16 19:45:40 +00:00
|
|
|
|
2020-05-26 18:44:06 +00:00
|
|
|
Template::set('globals', [
|
|
|
|
'site_name' => Config::get('site.name', Config::TYPE_STR, 'Misuzu'),
|
|
|
|
'site_description' => Config::get('site.desc', Config::TYPE_STR),
|
|
|
|
'site_url' => Config::get('site.url', Config::TYPE_STR),
|
|
|
|
'site_twitter' => Config::get('social.twitter', Config::TYPE_STR),
|
|
|
|
]);
|
2018-09-16 19:45:40 +00:00
|
|
|
|
2020-05-26 18:44:06 +00:00
|
|
|
Template::addPath(MSZ_ROOT . '/templates');
|
2018-07-07 23:24:34 +00:00
|
|
|
|
2020-05-26 18:44:06 +00:00
|
|
|
if(isset($_COOKIE['msz_uid']) && isset($_COOKIE['msz_sid'])) {
|
|
|
|
$authToken = (new AuthToken)
|
|
|
|
->setUserId(filter_input(INPUT_COOKIE, 'msz_uid', FILTER_SANITIZE_NUMBER_INT) ?? 0)
|
|
|
|
->setSessionToken(filter_input(INPUT_COOKIE, 'msz_sid', FILTER_SANITIZE_STRING) ?? '');
|
2020-05-25 19:58:06 +00:00
|
|
|
|
2020-05-26 18:44:06 +00:00
|
|
|
if($authToken->isValid())
|
|
|
|
setcookie('msz_auth', $authToken->pack(), strtotime('1 year'), '/', '.' . $_SERVER['HTTP_HOST'], !empty($_SERVER['HTTPS']), true);
|
2020-05-25 19:58:06 +00:00
|
|
|
|
2020-05-26 18:44:06 +00:00
|
|
|
setcookie('msz_uid', '', -3600, '/', '', !empty($_SERVER['HTTPS']), true);
|
|
|
|
setcookie('msz_sid', '', -3600, '/', '', !empty($_SERVER['HTTPS']), true);
|
|
|
|
}
|
2019-02-12 15:26:39 +00:00
|
|
|
|
2020-05-26 18:44:06 +00:00
|
|
|
if(!isset($authToken))
|
|
|
|
$authToken = AuthToken::unpack(filter_input(INPUT_COOKIE, 'msz_auth', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH) ?? '');
|
2020-05-26 18:57:35 +00:00
|
|
|
|
2020-05-26 18:44:06 +00:00
|
|
|
if($authToken->isValid()) {
|
|
|
|
try {
|
|
|
|
$sessionInfo = $authToken->getSession();
|
|
|
|
if($sessionInfo->hasExpired()) {
|
|
|
|
$sessionInfo->delete();
|
|
|
|
} elseif($sessionInfo->getUserId() === $authToken->getUserId()) {
|
|
|
|
$userInfo = $sessionInfo->getUser();
|
|
|
|
if(!$userInfo->isDeleted()) {
|
|
|
|
$sessionInfo->setCurrent();
|
|
|
|
$userInfo->setCurrent();
|
|
|
|
|
|
|
|
$sessionInfo->bump();
|
|
|
|
|
|
|
|
if($sessionInfo->shouldBumpExpire())
|
|
|
|
setcookie('msz_auth', $authToken->pack(), $sessionInfo->getExpiresTime(), '/', '.' . $_SERVER['HTTP_HOST'], !empty($_SERVER['HTTPS']), true);
|
2020-05-25 19:58:06 +00:00
|
|
|
}
|
|
|
|
}
|
2020-05-26 18:44:06 +00:00
|
|
|
} catch(UserNotFoundException $ex) {
|
|
|
|
UserSession::unsetCurrent();
|
|
|
|
User::unsetCurrent();
|
|
|
|
} catch(UserSessionNotFoundException $ex) {
|
|
|
|
UserSession::unsetCurrent();
|
|
|
|
User::unsetCurrent();
|
|
|
|
}
|
2019-02-12 15:26:39 +00:00
|
|
|
|
2020-05-26 18:44:06 +00:00
|
|
|
if(!UserSession::hasCurrent()) {
|
|
|
|
setcookie('msz_auth', '', -9001, '/', '.' . $_SERVER['HTTP_HOST'], !empty($_SERVER['HTTPS']), true);
|
|
|
|
setcookie('msz_auth', '', -9001, '/', '', !empty($_SERVER['HTTPS']), true);
|
|
|
|
} else {
|
|
|
|
$userDisplayInfo = DB::prepare('
|
|
|
|
SELECT
|
|
|
|
u.`user_id`, u.`username`, u.`user_background_settings`, u.`user_deleted`,
|
|
|
|
COALESCE(u.`user_colour`, r.`role_colour`) AS `user_colour`
|
|
|
|
FROM `msz_users` AS u
|
|
|
|
LEFT JOIN `msz_roles` AS r
|
|
|
|
ON u.`display_role` = r.`role_id`
|
|
|
|
WHERE `user_id` = :user_id
|
|
|
|
') ->bind('user_id', $userInfo->getId())
|
|
|
|
->fetch();
|
|
|
|
|
|
|
|
user_bump_last_active($userInfo->getId());
|
|
|
|
|
|
|
|
$userDisplayInfo['perms'] = perms_get_user($userInfo->getId());
|
|
|
|
$userDisplayInfo['ban_expiration'] = user_warning_check_expiration($userInfo->getId(), MSZ_WARN_BAN);
|
|
|
|
$userDisplayInfo['silence_expiration'] = $userDisplayInfo['ban_expiration'] > 0 ? 0 : user_warning_check_expiration($userInfo->getId(), MSZ_WARN_SILENCE);
|
2018-03-31 22:28:32 +00:00
|
|
|
}
|
2020-05-26 18:44:06 +00:00
|
|
|
}
|
2018-03-31 22:28:32 +00:00
|
|
|
|
2020-05-26 18:44:06 +00:00
|
|
|
CSRF::setGlobalSecretKey(Config::get('csrf.secret', Config::TYPE_STR, 'soup'));
|
|
|
|
CSRF::setGlobalIdentity(UserSession::hasCurrent() ? UserSession::getCurrent()->getToken() : IPAddress::remote());
|
|
|
|
|
|
|
|
if(Config::get('private.enabled', Config::TYPE_BOOL)) {
|
|
|
|
$onLoginPage = $_SERVER['PHP_SELF'] === url('auth-login');
|
|
|
|
$onPasswordPage = parse_url($_SERVER['PHP_SELF'], PHP_URL_PATH) === url('auth-forgot');
|
|
|
|
$misuzuBypassLockdown = !empty($misuzuBypassLockdown) || $onLoginPage;
|
|
|
|
|
|
|
|
if(!$misuzuBypassLockdown) {
|
|
|
|
if(UserSession::hasCurrent()) {
|
|
|
|
$privatePermCat = Config::get('private.perm.cat', Config::TYPE_STR);
|
|
|
|
$privatePermVal = Config::get('private.perm.val', Config::TYPE_INT);
|
|
|
|
|
|
|
|
if(!empty($privatePermCat) && $privatePermVal > 0) {
|
|
|
|
if(!perms_check_user($privatePermCat, User::getCurrent()->getId(), $privatePermVal)) {
|
|
|
|
// au revoir
|
|
|
|
unset($userDisplayInfo);
|
|
|
|
UserSession::unsetCurrent();
|
|
|
|
User::unsetCurrent();
|
2018-10-05 07:33:26 +00:00
|
|
|
}
|
2018-09-28 07:56:55 +00:00
|
|
|
}
|
2020-05-26 18:44:06 +00:00
|
|
|
} elseif(!$onLoginPage && !($onPasswordPage && Config::get('private.allow_password_reset', Config::TYPE_BOOL, true))) {
|
|
|
|
url_redirect('auth-login');
|
|
|
|
exit;
|
2018-09-28 07:56:55 +00:00
|
|
|
}
|
2018-09-27 22:27:30 +00:00
|
|
|
}
|
2020-05-26 18:44:06 +00:00
|
|
|
}
|
2018-09-27 22:27:30 +00:00
|
|
|
|
2020-05-26 18:44:06 +00:00
|
|
|
if(!empty($userDisplayInfo)) // delete this
|
|
|
|
Template::set('current_user', $userDisplayInfo);
|
2018-10-02 23:09:41 +00:00
|
|
|
|
2020-05-26 18:44:06 +00:00
|
|
|
$inManageMode = starts_with($_SERVER['REQUEST_URI'], '/manage');
|
|
|
|
$hasManageAccess = User::hasCurrent()
|
|
|
|
&& !user_warning_check_restriction(User::getCurrent()->getId())
|
|
|
|
&& perms_check_user(MSZ_PERMS_GENERAL, User::getCurrent()->getId(), MSZ_PERM_GENERAL_CAN_MANAGE);
|
|
|
|
Template::set('has_manage_access', $hasManageAccess);
|
2018-03-28 00:35:37 +00:00
|
|
|
|
2020-05-26 18:44:06 +00:00
|
|
|
if($inManageMode) {
|
|
|
|
if(!$hasManageAccess) {
|
|
|
|
echo render_error(403);
|
|
|
|
exit;
|
2018-03-28 00:35:37 +00:00
|
|
|
}
|
2020-05-26 18:44:06 +00:00
|
|
|
|
|
|
|
Template::set('manage_menu', manage_get_menu(User::getCurrent()->getId()));
|
2018-03-14 01:39:02 +00:00
|
|
|
}
|