[ 'root' => MSZ_ROOT . '/assets/js', 'mime' => 'application/javascript; charset=utf-8', ], 'css' => [ 'root' => MSZ_ROOT . '/assets/css', 'mime' => 'text/css; charset=utf-8', ], ]; public function __construct() { $GLOBALS['misuzuBypassLockdown'] = true; parent::__construct(); } private static function recurse(string $dir): string { $str = ''; $dir = rtrim(realpath($dir), '/') . '/*'; $dirs = []; foreach(glob($dir) as $path) { if(is_dir($path)) { $dirs[] = $path; continue; } if(MSZ_DEBUG) $str .= "/*** {$path} ***/\n"; $str .= trim(file_get_contents($path)); $str .= "\n\n"; } foreach($dirs as $path) $str .= self::recurse($path); return $str; } public function serveComponent($response, $request, string $fileName) { $name = pathinfo($fileName, PATHINFO_FILENAME); $type = pathinfo($fileName, PATHINFO_EXTENSION); $entityTag = sprintf('%s.%s/%s', $name, $type, GitInfo::hash()); if(!MSZ_DEBUG && $name === 'debug') return 404; if(!MSZ_DEBUG && $request->getHeaderFirstLine('If-None-Match') === '"' . $entityTag . '"') return 304; if(array_key_exists($type, self::TYPES)) { $type = self::TYPES[$type]; $path = ($type['root'] ?? '') . '/' . $name; if(is_dir($path)) { $response->setContentType($type['mime'] ?? 'application/octet-stream'); $response->setCacheControl(MSZ_DEBUG ? 'no-cache' : 'must-revalidate'); $response->setEntityTag($entityTag); return self::recurse($path); } } } private function canViewAsset($request, User $assetUser): bool { return !$assetUser->isBanned() || ( User::hasCurrent() && parse_url($request->getHeaderFirstLine('Referer'), PHP_URL_PATH) === url('user-profile') && perms_check_user(MSZ_PERMS_USER, User::getCurrent()->getId(), MSZ_PERM_USER_MANAGE_USERS) ); } private function serveUserAsset($response, $request, UserImageAssetInterface $assetInfo): void { $contentType = $assetInfo->getMimeType(); $publicPath = $assetInfo->getPublicPath(); $fileName = $assetInfo->getFileName(); if($assetInfo instanceof UserAssetScalableInterface) { $dimensions = (int)($request->getParam('res', FILTER_SANITIZE_NUMBER_INT) ?? $request->getParam('r', FILTER_SANITIZE_NUMBER_INT)); if($dimensions > 0) { $assetInfo->ensureScaledExists($dimensions); $contentType = $assetInfo->getScaledMimeType($dimensions); $publicPath = $assetInfo->getPublicScaledPath($dimensions); $fileName = $assetInfo->getScaledFileName($dimensions); } } $response->accelRedirect($publicPath); $response->setContentType($contentType); $response->setFileName($fileName, false); } public function serveAvatar($response, $request, string $fileName) { $userId = (int)pathinfo($fileName, PATHINFO_FILENAME); $type = pathinfo($fileName, PATHINFO_EXTENSION); if($type !== '' && $type !== 'png') return 404; $assetInfo = new StaticUserImageAsset(MSZ_PUBLIC . '/images/no-avatar.png', MSZ_PUBLIC); try { $userInfo = User::byId($userId); if(!$this->canViewAsset($request, $userInfo)) { $assetInfo = new StaticUserImageAsset(MSZ_PUBLIC . '/images/banned-avatar.png', MSZ_PUBLIC); } elseif($userInfo->hasAvatar()) { $assetInfo = $userInfo->getAvatarInfo(); } } catch(UserNotFoundException $ex) {} $this->serveUserAsset($response, $request, $assetInfo); } public function serveProfileBackground($response, $request, string $fileName) { $userId = (int)pathinfo($fileName, PATHINFO_FILENAME); $type = pathinfo($fileName, PATHINFO_EXTENSION); if($type !== '' && $type !== 'png') return 404; try { $userInfo = User::byId($userId); } catch(UserNotFoundException $ex) {} if(empty($userInfo) || !$userInfo->hasBackground() || !$this->canViewAsset($request, $userInfo)) { $response->setContent(''); return 404; } $this->serveUserAsset($response, $request, $userInfo->getBackgroundInfo()); } public function serveLegacy($response, $request) { $assetUserId = (int)$request->getParam('u', FILTER_SANITIZE_NUMBER_INT); switch($request->getParam('m')) { case 'avatar': $this->serveAvatar($response, $request, $assetUserId); return; case 'background': $this->serveProfileBackground($response, $request, $assetUserId); return; } $response->setContent(''); return 404; } }