2022-09-13 13:14:49 +00:00
|
|
|
<?php
|
|
|
|
namespace Misuzu;
|
|
|
|
|
|
|
|
use Index\Autoloader;
|
|
|
|
use Index\Environment;
|
2023-01-01 19:06:01 +00:00
|
|
|
use Index\Data\ConnectionFailedException;
|
|
|
|
use Index\Data\DbTools;
|
2023-01-06 20:50:41 +00:00
|
|
|
use Misuzu\Config\IConfig;
|
2023-01-01 20:23:53 +00:00
|
|
|
use Misuzu\Config\DbConfig;
|
2022-09-13 13:14:49 +00:00
|
|
|
use Misuzu\Users\User;
|
|
|
|
use Misuzu\Users\UserNotFoundException;
|
|
|
|
use Misuzu\Users\UserSession;
|
|
|
|
use Misuzu\Users\UserSessionNotFoundException;
|
|
|
|
|
|
|
|
define('MSZ_STARTUP', microtime(true));
|
|
|
|
define('MSZ_ROOT', __DIR__);
|
|
|
|
define('MSZ_CLI', PHP_SAPI === 'cli');
|
|
|
|
define('MSZ_DEBUG', is_file(MSZ_ROOT . '/.debug'));
|
|
|
|
define('MSZ_PUBLIC', MSZ_ROOT . '/public');
|
|
|
|
define('MSZ_SOURCE', MSZ_ROOT . '/src');
|
|
|
|
define('MSZ_LIBRARIES', MSZ_ROOT . '/lib');
|
|
|
|
define('MSZ_CONFIG', MSZ_ROOT . '/config');
|
|
|
|
define('MSZ_TEMPLATES', MSZ_ROOT . '/templates');
|
2023-01-07 04:15:19 +00:00
|
|
|
define('MSZ_MIGRATIONS', MSZ_ROOT . '/database');
|
2023-07-17 14:37:39 +00:00
|
|
|
define('MSZ_ASSETS', MSZ_ROOT . '/assets');
|
2022-09-13 13:14:49 +00:00
|
|
|
|
2023-01-01 19:06:01 +00:00
|
|
|
define('MSZ_NDX_PATH', MSZ_LIBRARIES . '/index');
|
|
|
|
define('MSZ_NDX_PATH_DEV', MSZ_LIBRARIES . '/index-dev');
|
|
|
|
|
|
|
|
require_once (MSZ_DEBUG && is_dir(MSZ_NDX_PATH_DEV) ? MSZ_NDX_PATH_DEV : MSZ_NDX_PATH) . '/index.php';
|
2022-09-13 13:14:49 +00:00
|
|
|
|
|
|
|
Autoloader::addNamespace(__NAMESPACE__, MSZ_SOURCE);
|
|
|
|
Environment::setDebug(MSZ_DEBUG);
|
|
|
|
|
|
|
|
mb_internal_encoding('utf-8');
|
|
|
|
date_default_timezone_set('utc');
|
|
|
|
set_include_path(get_include_path() . PATH_SEPARATOR . MSZ_ROOT);
|
|
|
|
|
|
|
|
set_exception_handler(function(\Throwable $ex) {
|
|
|
|
if(MSZ_CLI) {
|
|
|
|
echo (string)$ex;
|
|
|
|
} else {
|
|
|
|
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_TEMPLATES . '/500.html');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
exit;
|
|
|
|
});
|
|
|
|
|
|
|
|
require_once 'vendor/autoload.php';
|
|
|
|
|
|
|
|
require_once 'utility.php';
|
|
|
|
require_once 'src/perms.php';
|
|
|
|
require_once 'src/manage.php';
|
|
|
|
require_once 'src/url.php';
|
|
|
|
require_once 'src/Forum/perms.php';
|
|
|
|
require_once 'src/Forum/forum.php';
|
|
|
|
require_once 'src/Forum/leaderboard.php';
|
|
|
|
require_once 'src/Forum/post.php';
|
|
|
|
require_once 'src/Forum/topic.php';
|
|
|
|
require_once 'src/Forum/validate.php';
|
|
|
|
|
|
|
|
$dbConfig = parse_ini_file(MSZ_CONFIG . '/config.ini', true, INI_SCANNER_TYPED);
|
|
|
|
|
|
|
|
if(empty($dbConfig)) {
|
|
|
|
echo 'Database config is missing.';
|
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
2023-01-01 19:06:01 +00:00
|
|
|
define('MSZ_DB_INIT', 'SET SESSION time_zone = \'+00:00\', sql_mode = \'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION\';');
|
2022-09-13 13:14:49 +00:00
|
|
|
|
2023-01-01 19:06:01 +00:00
|
|
|
$db = DbTools::create($dbConfig['dsn']);
|
|
|
|
$db->execute(MSZ_DB_INIT);
|
|
|
|
|
2023-07-11 22:45:23 +00:00
|
|
|
DB::init(DbTools::parse($dbConfig['dsn']));
|
2023-01-01 19:06:01 +00:00
|
|
|
DB::exec(MSZ_DB_INIT);
|
2022-09-13 13:14:49 +00:00
|
|
|
|
2023-01-01 20:23:53 +00:00
|
|
|
$cfg = new DbConfig($db);
|
|
|
|
$cfg->reload();
|
|
|
|
|
|
|
|
Config::init($cfg);
|
|
|
|
|
2023-01-06 20:50:41 +00:00
|
|
|
Mailer::init($cfg->getValue('mail.method', IConfig::T_STR), [
|
|
|
|
'host' => $cfg->getValue('mail.host', IConfig::T_STR),
|
|
|
|
'port' => $cfg->getValue('mail.port', IConfig::T_INT, 25),
|
|
|
|
'username' => $cfg->getValue('mail.username', IConfig::T_STR),
|
|
|
|
'password' => $cfg->getValue('mail.password', IConfig::T_STR),
|
|
|
|
'encryption' => $cfg->getValue('mail.encryption', IConfig::T_STR),
|
|
|
|
'sender_name' => $cfg->getValue('mail.sender.name', IConfig::T_STR),
|
|
|
|
'sender_addr' => $cfg->getValue('mail.sender.address', IConfig::T_STR),
|
2022-09-13 13:14:49 +00:00
|
|
|
]);
|
|
|
|
|
|
|
|
// replace this with a better storage mechanism
|
2023-01-06 20:50:41 +00:00
|
|
|
define('MSZ_STORAGE', $cfg->getValue('storage.path', IConfig::T_STR, MSZ_ROOT . '/store'));
|
2022-09-13 13:14:49 +00:00
|
|
|
if(!is_dir(MSZ_STORAGE))
|
|
|
|
mkdir(MSZ_STORAGE, 0775, true);
|
|
|
|
|
2023-01-06 20:35:03 +00:00
|
|
|
$msz = new MisuzuContext($db, $cfg);
|
2023-01-05 03:20:31 +00:00
|
|
|
|
2023-07-10 22:52:30 +00:00
|
|
|
if(MSZ_CLI)
|
2022-09-13 13:14:49 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
|
|
|
|
ob_start();
|
|
|
|
|
|
|
|
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_TEMPLATES . '/503.html');
|
|
|
|
}
|
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!is_readable(MSZ_STORAGE) || !is_writable(MSZ_STORAGE)) {
|
|
|
|
echo 'Cannot access storage directory.';
|
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!MSZ_DEBUG) {
|
2023-01-01 20:33:32 +00:00
|
|
|
$twigCacheDirSfx = GitInfo::hash(true);
|
|
|
|
if(empty($twigCacheDirSfx))
|
|
|
|
$twigCacheDirSfx = md5(MSZ_ROOT);
|
|
|
|
|
|
|
|
$twigCache = sys_get_temp_dir() . '/msz-tpl-' . $twigCacheDirSfx;
|
2022-09-13 13:14:49 +00:00
|
|
|
if(!is_dir($twigCache))
|
|
|
|
mkdir($twigCache, 0775, true);
|
|
|
|
}
|
|
|
|
|
2023-01-06 20:35:03 +00:00
|
|
|
Template::init($msz, $twigCache ?? null, MSZ_DEBUG);
|
2022-09-13 13:14:49 +00:00
|
|
|
|
|
|
|
Template::set('globals', [
|
2023-01-06 20:50:41 +00:00
|
|
|
'site_name' => $cfg->getValue('site.name', IConfig::T_STR, 'Misuzu'),
|
|
|
|
'site_description' => $cfg->getValue('site.desc', IConfig::T_STR),
|
|
|
|
'site_url' => $cfg->getValue('site.url', IConfig::T_STR),
|
2023-01-31 16:21:19 +00:00
|
|
|
'site_chat' => $cfg->getValue('sockChat.chatPath.normal', IConfig::T_STR),
|
2023-03-09 21:05:37 +00:00
|
|
|
'eeprom' => [
|
|
|
|
'path' => $cfg->getValue('eeprom.path', IConfig::T_STR),
|
|
|
|
'app' => $cfg->getValue('eeprom.app', IConfig::T_STR),
|
|
|
|
],
|
2022-09-13 13:14:49 +00:00
|
|
|
]);
|
|
|
|
|
2023-07-17 14:37:39 +00:00
|
|
|
$mszAssetsInfo = json_decode(file_get_contents(MSZ_ASSETS . '/current.json'));
|
|
|
|
if(!empty($mszAssetsInfo))
|
|
|
|
Template::set('assets', $mszAssetsInfo);
|
|
|
|
unset($mszAssetsInfo);
|
|
|
|
|
2022-09-13 13:14:49 +00:00
|
|
|
Template::addPath(MSZ_TEMPLATES);
|
|
|
|
|
2023-05-21 18:15:04 +00:00
|
|
|
AuthToken::setSecretKey($cfg->getValue('auth.secret', IConfig::T_STR, 'meow'));
|
|
|
|
|
2022-09-13 13:14:49 +00:00
|
|
|
if(isset($_COOKIE['msz_uid']) && isset($_COOKIE['msz_sid'])) {
|
2023-05-21 18:15:04 +00:00
|
|
|
$authToken = new AuthToken;
|
|
|
|
$authToken->setUserId(filter_input(INPUT_COOKIE, 'msz_uid', FILTER_SANITIZE_NUMBER_INT) ?? 0);
|
|
|
|
$authToken->setSessionToken(filter_input(INPUT_COOKIE, 'msz_sid') ?? '');
|
2022-09-13 13:14:49 +00:00
|
|
|
|
|
|
|
if($authToken->isValid())
|
2023-05-21 18:15:04 +00:00
|
|
|
$authToken->applyCookie(strtotime('1 year'));
|
2022-09-13 13:14:49 +00:00
|
|
|
|
2023-05-21 18:15:04 +00:00
|
|
|
AuthToken::nukeCookieLegacy();
|
2022-09-13 13:14:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(!isset($authToken))
|
|
|
|
$authToken = AuthToken::unpack(filter_input(INPUT_COOKIE, 'msz_auth') ?? '');
|
|
|
|
|
|
|
|
if($authToken->isValid()) {
|
2023-05-21 18:15:04 +00:00
|
|
|
$authToken->setCurrent();
|
|
|
|
|
2022-09-13 13:14:49 +00:00
|
|
|
try {
|
2023-05-21 18:15:04 +00:00
|
|
|
$sessionInfo = UserSession::byToken($authToken->getSessionToken());
|
2022-09-13 13:14:49 +00:00
|
|
|
if($sessionInfo->hasExpired()) {
|
|
|
|
$sessionInfo->delete();
|
|
|
|
} elseif($sessionInfo->getUserId() === $authToken->getUserId()) {
|
|
|
|
$userInfo = $sessionInfo->getUser();
|
|
|
|
if(!$userInfo->isDeleted()) {
|
|
|
|
$sessionInfo->setCurrent();
|
|
|
|
$userInfo->setCurrent();
|
2023-01-05 18:33:03 +00:00
|
|
|
$sessionInfo->bump($_SERVER['REMOTE_ADDR']);
|
2022-09-13 13:14:49 +00:00
|
|
|
|
|
|
|
if($sessionInfo->shouldBumpExpire())
|
2023-05-21 18:15:04 +00:00
|
|
|
$authToken->applyCookie($sessionInfo->getExpiresTime());
|
|
|
|
|
|
|
|
// only allow impersonation when super user
|
|
|
|
if($authToken->hasImpersonatedUserId() && $userInfo->isSuper()) {
|
|
|
|
$userInfoReal = $userInfo;
|
|
|
|
|
|
|
|
try {
|
|
|
|
$userInfo = User::byId($authToken->getImpersonatedUserId());
|
|
|
|
} catch(UserNotFoundException $ex) {
|
|
|
|
$userInfo = $userInfoReal;
|
|
|
|
$authToken->removeImpersonatedUserId();
|
|
|
|
$authToken->applyCookie();
|
|
|
|
}
|
|
|
|
|
|
|
|
$userInfo->setCurrent();
|
|
|
|
}
|
2022-09-13 13:14:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch(UserNotFoundException $ex) {
|
|
|
|
UserSession::unsetCurrent();
|
|
|
|
User::unsetCurrent();
|
|
|
|
} catch(UserSessionNotFoundException $ex) {
|
|
|
|
UserSession::unsetCurrent();
|
|
|
|
User::unsetCurrent();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(UserSession::hasCurrent()) {
|
2023-01-05 18:33:03 +00:00
|
|
|
$userInfo->bumpActivity($_SERVER['REMOTE_ADDR']);
|
2023-05-21 18:15:04 +00:00
|
|
|
} else
|
|
|
|
AuthToken::nukeCookie();
|
2022-09-13 13:14:49 +00:00
|
|
|
}
|
|
|
|
|
2023-07-11 22:13:56 +00:00
|
|
|
CSRF::init(
|
|
|
|
$cfg->getValue('csrf.secret', IConfig::T_STR, 'soup'),
|
|
|
|
(UserSession::hasCurrent() ? UserSession::getCurrent()->getToken() : ($_SERVER['REMOTE_ADDR'] ?? '::1'))
|
2023-01-05 18:33:03 +00:00
|
|
|
);
|
2022-09-13 13:14:49 +00:00
|
|
|
|
|
|
|
function mszLockdown(): void {
|
2023-01-01 20:23:53 +00:00
|
|
|
global $misuzuBypassLockdown, $cfg;
|
2022-09-13 13:14:49 +00:00
|
|
|
|
2023-01-06 20:50:41 +00:00
|
|
|
if($cfg->getValue('private.enabled', IConfig::T_BOOL)) {
|
2022-09-13 13:14:49 +00:00
|
|
|
$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()) {
|
2023-01-06 20:50:41 +00:00
|
|
|
$privatePermCat = $cfg->getValue('private.perm.cat', IConfig::T_STR);
|
|
|
|
$privatePermVal = $cfg->getValue('private.perm.val', IConfig::T_INT);
|
2022-09-13 13:14:49 +00:00
|
|
|
|
|
|
|
if(!empty($privatePermCat) && $privatePermVal > 0) {
|
|
|
|
if(!perms_check_user($privatePermCat, User::getCurrent()->getId(), $privatePermVal)) {
|
|
|
|
// au revoir
|
|
|
|
UserSession::unsetCurrent();
|
|
|
|
User::unsetCurrent();
|
|
|
|
}
|
|
|
|
}
|
2023-01-06 20:50:41 +00:00
|
|
|
} elseif(!$onLoginPage && !($onPasswordPage && $cfg->getValue('private.allow_password_reset', IConfig::T_BOOL, true))) {
|
2022-09-13 13:14:49 +00:00
|
|
|
url_redirect('auth-login');
|
|
|
|
exit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(parse_url($_SERVER['PHP_SELF'], PHP_URL_PATH) !== '/index.php')
|
|
|
|
mszLockdown();
|
|
|
|
|
|
|
|
if(!empty($userInfo))
|
|
|
|
Template::set('current_user', $userInfo);
|
2023-05-21 18:15:04 +00:00
|
|
|
if(!empty($userInfoReal))
|
|
|
|
Template::set('current_user_real', $userInfoReal);
|
2022-09-13 13:14:49 +00:00
|
|
|
|
|
|
|
$inManageMode = str_starts_with($_SERVER['REQUEST_URI'], '/manage');
|
|
|
|
$hasManageAccess = User::hasCurrent()
|
|
|
|
&& !User::getCurrent()->hasActiveWarning()
|
|
|
|
&& perms_check_user(MSZ_PERMS_GENERAL, User::getCurrent()->getId(), MSZ_PERM_GENERAL_CAN_MANAGE);
|
|
|
|
Template::set('has_manage_access', $hasManageAccess);
|
|
|
|
|
|
|
|
if($inManageMode) {
|
|
|
|
if(!$hasManageAccess) {
|
|
|
|
echo render_error(403);
|
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
Template::set('manage_menu', manage_get_menu(User::getCurrent()->getId()));
|
|
|
|
}
|