* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ use Chevereto\Config\Config; use Chevereto\Legacy\Classes\DB; use Chevereto\Legacy\Classes\Fonts; use Chevereto\Legacy\Classes\IpBan; use Chevereto\Legacy\Classes\L10n; use Chevereto\Legacy\Classes\Login; use Chevereto\Legacy\Classes\Page; use Chevereto\Legacy\Classes\Palettes; use Chevereto\Legacy\Classes\RequestLog; use Chevereto\Legacy\Classes\Settings; use Chevereto\Legacy\Classes\Tag; use Chevereto\Legacy\Classes\User; use Chevereto\Legacy\G\Handler; use function Chevereto\Legacy\badgePaid; use function Chevereto\Legacy\cheveretoVersionInstalled; use function Chevereto\Legacy\editionCombo; use function Chevereto\Legacy\G\get_base_url; use function Chevereto\Legacy\G\get_current_url; use function Chevereto\Legacy\G\get_public_url; use function Chevereto\Legacy\G\is_route_available; use function Chevereto\Legacy\G\is_url; use function Chevereto\Legacy\G\redirect; use function Chevereto\Legacy\G\safe_html; use function Chevereto\Legacy\G\set_status_header; use function Chevereto\Legacy\get_enabled_languages; use function Chevereto\Legacy\getSetting; use function Chevereto\Legacy\getSystemNotices; use function Chevereto\Legacy\getVariable; use function Chevereto\Legacy\headersNoCache; use function Chevereto\Legacy\headersResetCache; use function Chevereto\Legacy\is_max_invalid_request; use function Chevereto\Vars\cookie; use function Chevereto\Vars\env; use function Chevereto\Vars\get; use function Chevereto\Vars\server; use function Chevereto\Vars\session; use function Chevereto\Vars\sessionVar; if (cheveretoVersionInstalled() === '') { new Handler( loadTemplate: ! REPL, // @phpstan-ignore-line before: function ($handler) { headersNoCache(); if ($handler->request_array()[0] !== 'install') { redirect('install', 302); } }, ); } $bannedIp = IpBan::getSingle(); if ($bannedIp !== []) { headersNoCache(); // TODO: Cache until ban expires if (is_url($bannedIp['message'] ?? false)) { redirect($bannedIp['message'], 301); } else { $exitMessage = $bannedIp['message'] ?? ''; $exitMessage = match ($exitMessage) { '' => _s('You have been forbidden to use this website.'), default => $bannedIp['message'], }; exit($exitMessage); } } $hook_before = function (Handler $handler) { header('Permissions-Policy: unload=()'); header('Permissions-Policy: interest-cohort=()'); header("Content-Security-Policy: frame-ancestors 'none'"); $exitEarlyRoutes = [ 'webmanifest', ]; $doNotCacheRoutes = [ 'login', 'signup', 'logout', 'account', 'connect', 'json', 'api', 'captcha-verify', 'oembed', 'upload', 'dashboard', 'install', 'settings', 'redirect', ]; $cache_ttl = (int) max(0, getSetting('cache_ttl') ?? 0); if (in_array($handler->request_array()[0], $doNotCacheRoutes, true)) { headersNoCache(); } elseif ($cache_ttl > 0) { headersResetCache(); header("Cache-Control: private, max-age={$cache_ttl}"); } if (in_array($handler->request_array()[0], $exitEarlyRoutes, true)) { return; } $failed_access_requests = RequestLog::getCounts(['login', 'signup'], 'fail'); if (is_max_invalid_request($failed_access_requests['day'])) { set_status_header(403); } else { Login::tryLogin(); } $user_cookie_lang = cookie()['USER_SELECTED_LANG'] ?? null; $user_lang = $user_cookie_lang ?? getSetting('default_language'); if (Login::isLoggedUser()) { $user_lang = Login::getUser()['language']; if (Login::getUser()['status'] === 'banned') { set_status_header(403); } if (sessionVar()->hasKey('challenge_two_factor') && ! in_array($handler->getRoutePath(), ['account/two-factor', 'captcha-verify', 'logout'], true) && $handler->request_array()[0] !== 'page' ) { headersNoCache(); redirect('account/two-factor', 302); } } if (! getSetting('language_chooser_enable')) { $user_lang = getSetting('default_language'); } new L10n( $user_lang, (Login::isLoggedUser() || $user_cookie_lang !== null) ? false : getSetting('auto_language') ); if (http_response_code() === 403) { headersNoCache(); exit(); } if ($handler->request_array()[0] !== 'api' && Settings::get('enable_uploads_url') && ! Login::isAdmin()) { Settings::setValue('enable_uploads_url', 0); } if (isset(get()['lang']) && array_key_exists(get()['lang'], get_enabled_languages()) ) { L10n::setCookieLang(get()['lang']); L10n::processTranslation(get()['lang']); define('PUSH_LANG', get()['lang']); } if (array_key_exists('agree-consent', get())) { setcookie( 'AGREE_CONSENT', '1', time() + (60 * 60 * 24 * 30), Config::host()->hostnamePath() ); sessionVar()->put('agree-consent', true); headersNoCache(); redirect(get_current_url(true, ['agree-consent']), 302); } $base = $handler::baseRequest(); parse_str(server()['QUERY_STRING'] ?? '', $querystr); $handler::setVar('auth_token', $handler::getAuthToken()); $handler::setVar('doctitle', getSetting('website_name')); $handler::setVar('meta_description', getSetting('website_description')); $handler::setVar('logged_user', Login::getUser()); $handler::setVar('failed_access_requests', $failed_access_requests); $handler::setVar('header_logo_link', get_base_url()); $handler::setCond('admin', Login::isAdmin()); $handler::setCond('manager', Login::isManager()); $showContentManager = Login::isAdmin() || Login::isManager(); $handler::setCond('content_manager', $showContentManager); $allowed_nsfw_flagging = ! getSetting('image_lock_nsfw_editing'); if ($handler::cond('content_manager')) { $moderateLink = get_base_url('moderate'); $moderateLabel = _s('Moderate'); if (! in_array('pro', editionCombo()[env()['CHEVERETO_EDITION']], true)) { if ((bool) env()['CHEVERETO_ENABLE_EXPOSE_PAID_FEATURES']) { $moderateLink = 'https://chevereto.com/pricing'; $moderateLabel .= ' ' . badgePaid('pro'); } else { $showContentManager = false; } } $handler::setVar('moderate_link', $moderateLink); $handler::setVar('moderate_label', $moderateLabel); $allowed_nsfw_flagging = true; } $handler::setCond('show_content_manager', $showContentManager); $handler::setCond('allowed_nsfw_flagging', $allowed_nsfw_flagging); $handler::setCond('maintenance', getSetting('maintenance') and ! Login::isAdmin()); $handler::setCond( 'show_consent_screen', $base !== 'api' && ( getSetting('enable_consent_screen') ? ! (Login::getUser() || isset(session()['agree-consent']) || isset(cookie()['AGREE_CONSENT'])) : false ) ); $handler::setCond('captcha_needed', getSetting('captcha') && getSetting('captcha_threshold') === 0); $handler::setCond('show_header', ! ($handler::cond('maintenance') || $handler::cond('show_consent_screen'))); $handler::setCond('show_notifications', getSetting('website_mode') === 'community' && (getSetting('enable_followers') || getSetting('enable_likes'))); $handler::setCond('allowed_to_delete_content', Login::isAdmin() || getSetting('enable_user_content_delete')); $handler::setVar('canonical', null); $palettes = new Palettes(); $handler::setVar('palettes', $palettes); $fonts = new Fonts(); $handler::setVar('fonts', $fonts); $fontId = intval(getSetting('theme_font') ?? 0); $handler::setVar('theme_font', $fontId); if (in_array($handler->request_array()[0], ['login', 'signup', 'account'], true)) { $paletteId = 0; } else { $paletteId = Login::isLoggedUser() ? Login::getUser()['palette_id'] : Settings::get('theme_palette'); } $theme_palette_handle = $palettes->getHandle(intval($paletteId)); if ($theme_palette_handle === '') { $paletteId = 1; $theme_palette_handle = $palettes->getHandle(intval($paletteId)); } $handler::setVar('theme_palette', $paletteId); $handler::setVar('theme_palette_handle', $theme_palette_handle); if ($handler::cond('maintenance') && $handler->request_array()[0] === 'dashboard') { headersNoCache(); redirect('login', 302); } $langLinks = []; $langToggleUrl = get_current_url(true, ['lang']); parse_str(server()['QUERY_STRING'] ?? '', $qs); unset($qs['lang']); $qs = http_build_query($qs); $langLinks['x-default'] = [ 'hreflang' => 'x-default', 'name' => 'x-default', 'url' => get_public_url($langToggleUrl), ]; $langToggleUrl = rtrim($langToggleUrl, '/') . ($qs ? '&' : '/?') . 'lang='; foreach (get_enabled_languages() as $k => $v) { $hreflang = strtolower($k); $langUrl = $langToggleUrl . $k; $langLinks[$k] = [ 'hreflang' => $hreflang, 'name' => $v['name'], 'url' => get_public_url($langUrl), ]; } $handler::setVar('langLinks', $langLinks); if ($handler::cond('show_consent_screen')) { $hasQs = parse_url(get_current_url(), PHP_URL_QUERY) !== null; $consent_accept_url = get_current_url() . ($hasQs ? '&' : '/?') . 'agree-consent'; $consent_accept_url = '/' . ltrim($consent_accept_url, '/'); $handler::setVar( 'consent_accept_url', $consent_accept_url ); } if (! Login::getUser()) { if (getSetting('captcha') && $failed_access_requests['day'] >= getSetting('captcha_threshold')) { $handler::setCond('captcha_needed', true); } } if (getSetting('website_mode') === 'personal') { $userMapPaths = ['search']; $userMapPaths[] = getSetting('user_profile_view') === 'files' ? 'albums' : 'files'; if ($handler->request_array()[0] === '/' && getSetting('website_mode_personal_routing') === '/' && in_array(key($querystr), ['random'], true) ) { $handler->mapRoute('index'); } elseif ($handler->request_array()[0] === 'search' && in_array($handler->request_array()[1] ?? [], ['images', 'albums', 'users'], true) ) { $handler->mapRoute('search'); } elseif ($handler->request_array()[0] === getSetting('website_mode_personal_routing') || (getSetting('website_mode_personal_routing') === '/' && in_array($handler->request_array()[0], $userMapPaths, true)) ) { $handler->mapRoute('user', [ 'id' => getSetting('website_mode_personal_uid'), ]); } if ($handler->request_array()[0] === '/' && ! in_array(key($querystr), ['random', 'lang'], true) && ! $handler::cond('mapped_route') ) { $personal_mode_user = User::getSingle(getSetting('website_mode_personal_uid')); if ($personal_mode_user !== []) { if (Settings::get('homepage_cta_html') === null) { Settings::setValue('homepage_cta_html', _s('View all my images')); } if (Settings::get('homepage_title_html') === null) { Settings::setValue('homepage_title_html', $personal_mode_user['name']); } if (Settings::get('homepage_paragraph_html') === null) { Settings::setValue('homepage_paragraph_html', _s('Feel free to browse and discover all my shared images and albums.')); } if (Settings::get('homepage_cta_fn') !== 'cta-link') { Settings::setValue('homepage_cta_fn', 'cta-link'); Settings::setValue('homepage_cta_fn_extra', $personal_mode_user['url']); } if ($personal_mode_user['background']['url'] ?? false) { Settings::setValue('homepage_cover_image', $personal_mode_user['background']['url']); } } } } else { if ($base !== 'index' and ! is_route_available($handler->request_array()[0])) { $mapTo = getSetting('root_route'); $handler->mapRoute($mapTo); } } $virtual_routes = ['image', 'album', 'user', 'video', 'audio']; if (in_array($handler->request_array()[0], $virtual_routes, true)) { $virtual_route = getSetting('route_' . $handler->request_array()[0]); if ($handler->request_array()[0] !== $virtual_route) { $virtualized_url = str_replace( get_base_url($handler->request_array()[0]), get_base_url($virtual_route), get_current_url() ); redirect($virtualized_url, 301); return; } } if ($base !== 'index' && ! is_route_available($handler->request_array()[0])) { foreach ($virtual_routes as $k) { if ($handler->request_array()[0] === getSetting('route_' . $k)) { $handler->mapRoute($k); } } } if (getSetting('website_privacy_mode') === 'private' && ! Login::getUser()) { $allowed_requests = ['api', 'login', 'logout', 'page', 'account', 'connect', 'json', 'captcha-verify']; foreach ($virtual_routes as $v) { $v = getSetting('route_' . $v); if (isset($v)) { $allowed_requests[] = $v; } } if (getSetting('enable_signups')) { $allowed_requests[] = 'signup'; } if (! in_array($handler->request_array()[0], $allowed_requests, true)) { headersNoCache(); redirect('login', 302); } } $handler::setCond( 'private_gate', getSetting('website_privacy_mode') === 'private' && ! Login::getUser() ); $handler::setCond( 'forced_private_mode', getSetting('website_privacy_mode') === 'private' && getSetting('website_content_privacy_mode') !== 'default' ); $handler::setCond( 'explore_enabled', $handler::cond('content_manager') ?: (getSetting('website_explore_page') ? ((bool) Login::isLoggedUser() ?: getSetting('website_explore_page_guest')) : false) ); $handler::setCond( 'search_enabled', $handler::cond('content_manager') ?: ( getSetting('website_search') && (Login::isLoggedUser() ?: getSetting('website_search_guest')) ) ); $handler::setCond( 'random_enabled', getSetting('website_random') && (Login::isLoggedUser() ?: getSetting('website_random_guest')) ); $moderate_uploads = false; switch (getSetting('moderate_uploads')) { case 'all': $moderate_uploads = ! $handler::cond('content_manager'); break; case 'guest': $moderate_uploads = ! Login::isLoggedUser(); break; } $handler::setCond('moderate_uploads', $moderate_uploads); $categories = []; $tags_top = []; if ($handler::cond('explore_enabled') || $base === 'dashboard') { try { $categories_db = DB::queryFetchAll( 'SELECT * FROM ' . DB::getTable('categories') . ' ORDER BY category_name ASC;' ); foreach ($categories_db as $k => $v) { $key = $v['category_id']; $categories[$key] = $v; $categories[$key]['category_url'] = get_base_url('category/' . $v['category_url_key']); $categories[$key] = DB::formatRow($categories[$key]); } } catch (Throwable) { } try { $tagsTable = DB::getTable('tags'); $tags_db = DB::queryFetchAll( << $v) { $tag = array_merge($v, Tag::row($v['name'])); $tags_top[] = $tag; } } catch (Throwable) { } } $handler::setVar('categories', $categories); $handler::setVar('tags_top', $tags_top); $explore_discovery = [ 'recent' => [ 'label' => _s('Recent'), 'icon' => 'fas fa-history', ], 'trending' => [ 'label' => _s('Trending'), 'icon' => 'fas fa-chart-simple', ], 'popular' => [ 'label' => _s('Popular'), 'icon' => 'fas fa-heart', ], ]; $explore_content = [ 'images' => [ 'label' => _n('Image', 'Images', 20), 'icon' => 'fas fa-image', ], 'videos' => [ 'label' => _n('Video', 'Videos', 20), 'icon' => 'fas fa-video', ], 'animated' => [ 'label' => _s('Animated'), 'icon' => 'fas fa-play', ], 'tags' => [ 'label' => _n('Tag', 'Tags', 20), 'icon' => 'fas fa-tags', ], 'albums' => [ 'label' => _n('Album', 'Albums', 20), 'icon' => 'fas fa-photo-film', ], 'users' => [ 'label' => _n('User', 'Users', 20), 'icon' => 'fas fa-users', ], ]; if (Login::isLoggedUser() && getSetting('enable_followers')) { $explore_discovery['following'] = [ 'label' => _s('Following'), 'icon' => 'fas fa-rss', 'url' => get_base_url('following'), ]; } if (! getSetting('enable_likes')) { unset($explore_discovery['popular']); } foreach ($explore_discovery as $k => &$v) { $v['url'] = get_base_url('explore/' . $k); } foreach ($explore_content as $k => &$v) { $v['url'] = get_base_url('explore/' . $k); } unset($v); $handler::setVar('explore_discovery', $explore_discovery); $handler::setVar('explore_content', $explore_content); $versionInstalled = cheveretoVersionInstalled(); $pages_visible = []; if (version_compare($versionInstalled, '3.6.7', '>=')) { $pages_visible_db = Page::getAll( args: [ 'is_active' => '1', 'is_link_visible' => '1', ], sort: [ 'field' => 'sort_display', 'order' => 'ASC', ] ); $pos_page_tos = array_search('tos', array_column($pages_visible_db, 'internal')); $pos_page_privacy = array_search('privacy', array_column($pages_visible_db, 'internal')); $page_tos = $pos_page_tos === false ? null : $pages_visible_db[$pos_page_tos]; $page_privacy = $pos_page_privacy === false ? null : $pages_visible_db[$pos_page_privacy]; $handler::setVar('page_tos', $page_tos); $handler::setVar('page_privacy', $page_privacy); } if ((bool) env()['CHEVERETO_ENABLE_PAGES']) { foreach ($pages_visible_db ?? [] as $k => $v) { if (! ($v['is_active'] ?? false) && ! ($v['is_link_visible'] ?? false)) { continue; } $pages_visible[$v['id']] = $v; } } $api_page = [ 'type' => 'link', 'link_url' => get_base_url('api-v1'), 'icon' => 'fas fa-project-diagram', 'title' => 'API', 'is_active' => 1, 'is_link_visible' => 1, 'attr_target' => '_self', 'sort_display' => -2, ]; Page::fill($api_page); $pages_visible[] = $api_page; if (getSetting('enable_plugin_route')) { $plugin_page = [ 'type' => 'link', 'link_url' => get_base_url('plugin'), 'icon' => 'fas fa-plug-circle-plus', 'title' => _s('Plugin'), 'is_active' => 1, 'is_link_visible' => 1, 'attr_target' => '_self', 'sort_display' => -1, ]; Page::fill($plugin_page); $pages_visible[] = $plugin_page; } uasort($pages_visible, function ($a, $b) { return $a['sort_display'] - $b['sort_display']; }); $handler::setVar('pages_link_visible', $pages_visible); $upload_enabled = Login::isAdmin() ?: getSetting('enable_uploads'); $upload_allowed = $upload_enabled; if (! Login::getUser()) { if (! getSetting('guest_uploads') || getSetting('website_privacy_mode') === 'private' || $handler::cond('maintenance')) { $upload_allowed = false; } } elseif (! Login::isAdmin() && getSetting('website_mode') === 'personal' && getSetting('website_mode_personal_uid') !== Login::getUser()['id']) { $upload_allowed = false; } if ((! (bool) env()['CHEVERETO_ENABLE_LOCAL_STORAGE']) && getVariable('storages_active')->nullInt() === 0) { $upload_enabled = false; $upload_allowed = false; } if (! Login::getUser() && $upload_allowed && getSetting('upload_max_filesize_mb_guest')) { Settings::setValue('upload_max_filesize_mb_bak', getSetting('upload_max_filesize_mb')); Settings::setValue('upload_max_filesize_mb', getSetting('upload_max_filesize_mb_guest')); } if ($upload_allowed && in_array($handler->request_array()[0], ['login', 'signup', 'account'], true) ) { $upload_allowed = false; } $handler::setCond('upload_enabled', $upload_enabled); // System allows to upload? $handler::setCond('upload_allowed', $upload_allowed); // Current user can upload? if ($handler::cond('maintenance') || $handler::cond('show_consent_screen')) { $handler::setCond('private_gate', true); $allowed_requests = ['login', 'account', 'connect', 'captcha-verify', 'oembed']; if (! in_array($handler->request_array()[0], $allowed_requests, true)) { $handler->preventRoute($handler::cond('show_consent_screen') ? 'consent-screen' : 'maintenance'); } } $handler::setVar('system_notices', Login::isAdmin() ? getSystemNotices() : []); $excludeLastUrl = [ 'login', 'signup', 'account', 'connect', 'logout', 'json', 'api', 'captcha-verify', 'webmanifest', 'tag-autocomplete', ]; if (! in_array($handler->request_array()[0], $excludeLastUrl, true)) { sessionVar()->put('last_url', get_current_url()); } $detect = new Mobile_Detect(); $isMobile = $detect->isMobile(); $handler::setCond('mobile_device', (bool) $isMobile); $handler::setCond('show_viewer_zero', false); if ($handler->template() === 'request-denied') { $handler::setVar('doctitle', _s('Request denied') . ' (403) - ' . getSetting('website_name')); $handler->preventRoute('request-denied'); } $handler::setVar('tos_privacy_agreement', _s('I agree to the %terms_link and %privacy_link', [ '%terms_link' => '' . _s('terms') . '', '%privacy_link' => '' . _s('privacy policy') . '', ])); $show_powered_by_footer = getSetting('enable_powered_by'); if (array_key_exists('CHEVERETO_ENABLE_FORCE_POWERED_BY_FOOTER', env())) { if ((bool) env()['CHEVERETO_ENABLE_FORCE_POWERED_BY_FOOTER']) { $show_powered_by_footer = true; } } $handler::setCond('show_powered_by_footer', $show_powered_by_footer); }; $hook_after = function (Handler $handler) { if (array_key_exists('deleted', get()) && in_array($handler->template(), ['user', 'album'], true) ) { set_status_header(303); } if ($handler->template() === '404') { if (sessionVar()->hasKey('last_url')) { sessionVar()->remove('last_url'); } $handler::setVar('doctitle', _s("That page doesn't exist") . ' (404) - ' . getSetting('website_name')); } $list_params = $handler::var('list_params'); if (isset($list_params) && $list_params['page_show']) { $handler::setVar('doctitle', $handler::var('doctitle') . ' | ' . _s('Page %s', $list_params['page_show'])); } if (defined('PUSH_LANG')) { $handler::setVar('doctitle', $handler::var('doctitle') . ' (' . get_enabled_languages()[PUSH_LANG]['name'] . ')'); } $handler::setVar('safe_html_website_name', getSetting('website_name', true)); $handler::setVar('safe_html_doctitle', safe_html($handler::var('doctitle'))); if ($handler::var('pre_doctitle')) { $handler::setVar('safe_html_pre_doctitle', safe_html($handler::var('pre_doctitle'))); } if ($handler::var('meta_description')) { $handler::setVar('safe_html_meta_description', safe_html($handler::var('meta_description'))); } if ($handler::var('meta_keywords')) { $handler::setVar('safe_html_meta_keywords', safe_html($handler::var('meta_keywords'))); } sessionVar()->put('REQUEST_REFERER', get_current_url()); header('X-Powered-By: Chevereto 4'); }; // @phpstan-ignore-next-line new Handler(loadTemplate: ! REPL, before: $hook_before, after: $hook_after);