tpl = $tpl; $this->dataDir = rtrim($dataDir, '/') . '/'; $this->oauthProvider = $oauthProvider; $this->highlighter = new \GeSHi(); $this->highlighter->enable_classes(true); $this->highlighter->enable_line_numbers(GESHI_NORMAL_LINE_NUMBERS); $this->highlighter->set_line_style('background: #eaeaea; padding-left: 0.4em'); $this->highlighter->set_header_type(GESHI_HEADER_NONE); $this->highlighter->set_overall_class('highlighted_code'); } public function handleRequest() { session_start(); if (array_key_exists('username', $_SESSION)) { $this->tpl->addData(['user' => $_SESSION['username']]); } $this->handleFormActions(); $url = $_SERVER['REQUEST_URI']; if (strpos($url, '?') !== false) { $url = substr($url, 0, strpos($url, '?')); } if (preg_match('_^/([a-z0-9]{8,12})(/raw)?$_', $url, $matches)) { $this->showPaste($matches[1], $matches[2] === '/raw'); } else if ($url === '/p/github-login') { $this->handleOauthLogin(); } else if ($url === '/p/logout') { unset($_SESSION['username']); $this->redirect('/'); } else if ($url === '/') { $this->enforceOauthLogin(); $this->showIndex(); } else { $this->showError('Oh damn, this page does not exist. :-('); } } private function redirect(string $path) { http_response_code(302); $url = sprintf('%s://%s%s', (!empty($_SERVER['HTTPS']) ? 'https' : 'http'), $_SERVER['HTTP_HOST'], $path); header('Location: ' . $url); die('You will be redirected to ' . $url); } private function showError(string $message) { http_response_code(400); die($this->tpl->render('error', ['message' => $message])); } private function handleFormActions() { if (array_key_exists('action', $_POST)) { switch ($_POST['action']) { case "create": $pasteId = $this->createNewPaste($_POST); $this->redirect('/' . $pasteId); break; } } } private function createNewPaste(array $params) { if (!array_key_exists('code', $params)) { $this->showError('Something went completely wrong. This should not have happened. :-( Please try again.'); } $language = array_key_exists('language', $params) ? $params['language'] : 'text'; $pasteId = $this->getNewPasteId(); if (is_null($pasteId)) { $this->showError('For some unclear reason I could not generate a new ID for you. :-( Please try again.'); } $content = [ 'language' => $language, 'created' => date('c'), 'creator' => $_SESSION['username'], 'code' => $params['code'], ]; if (file_put_contents($this->dataDir . $pasteId, json_encode($content)) === false) { $this->showError('Your paste could not be created. Sorry about that. :-( Please try again.'); } return $pasteId; } private function getNewPasteId() { $attempts = 3; $pasteId = null; do { $attempts -= 1; $length = mt_rand(8, 12); $hash = sha1(microtime()); $newId = substr($hash, 0, $length); if (!file_exists($this->dataDir . $newId)) { $pasteId = $newId; } } while (is_null($pasteId) && ($attempts > 0)); return $pasteId; } private function showPaste(string $pasteId, bool $showRaw = false) { $filename = $this->dataDir . $pasteId; if (!file_exists($filename)) { $this->showError('Oh no...looks like this paste is gone or never existed. :-('); } $content = json_decode(file_get_contents($filename)); if (is_null($content)) { $this->showError('Oh no...looks like this paste a little more than I can chew right now. :-('); } if ($showRaw) { header("Content-Type: text/plain"); die($content->code); } $this->highlighter->set_source($content->code); $this->highlighter->set_language($content->language); if ($this->highlighter->error() !== false) { $this->showError("This is embarrassing. I failed to render the paste you wanted to open. Sorry. :-("); } echo $this->tpl->render('paste', [ 'pasteId' => $pasteId, 'source' => $this->highlighter->parse_code(), 'header' => 'Code (' . $this->highlighter->get_language_name() . ') pasted on ' . date('Y-m-d, H:i', strtotime($content->created)), 'stylesheet' => $this->highlighter->get_stylesheet()]); } private function showIndex() { $languages = [ 'popular' => [], 'others' => [] ]; foreach (glob(BASE_PATH . '/vendor/geshi/geshi/src/geshi/*.php') as $file) { $language = basename($file, '.php'); if (in_array($language, $this->ignoredLanguages)) continue; include $file; $languageName = $language_data['LANG_NAME']; if (in_array($language, $this->popularLanguages)) { $languages['popular'][$language] = $languageName; } else { $languages['others'][$language] = $languageName; } } asort($languages['popular']); asort($languages['others']); echo $this->tpl->render('index', ['languages' => $languages]); } private function handleOauthLogin() { if (!isset($_GET['code'])) { // If we don't have an authorization code then get one $authUrl = $this->oauthProvider->getAuthorizationUrl(); $_SESSION['oauth2state'] = $this->oauthProvider->getState(); header('Location: ' . $authUrl); die(); } elseif (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) { unset($_SESSION['oauth2state']); $this->showError('Uh! Something went wrong with the authorization. I aborted this for security reasons, but please feel free to try again!'); } else { // Try to get an access token (using the authorization code grant) try { $token = $this->oauthProvider->getAccessToken('authorization_code', [ 'code' => $_GET['code'] ]); // We got an access token, let's now get the user's details $user = $this->oauthProvider->getResourceOwner($token); if (!in_array($user->getNickname(), $this->userWhitelist)) { $this->showError('Sorry, your username (' . $user->getNickname() . ') is not whitelisted and therefore I cannot allow you to create Pastes. :-('); } $_SESSION['username'] = $user->getNickname(); $this->redirect('/'); } catch (\Exception $e) { // Failed to get user details $this->showError('Oh no! Something is wrong with your authorization!'); } } } private function enforceOauthLogin() { if (!array_key_exists('username', $_SESSION)) { echo $this->tpl->render('login_required'); die(); } } }