/** * Handle a request for a file * * @param Request $request HTTP request * @return Response */ public function getResponse(Request $request) { $response = new Response(); $response->prepare($request); $path = implode('/', $request->getUrlSegments()); if (!preg_match('~serve-file/e(\\d+)/l(\\d+)/d([ia])/c([01])/([a-zA-Z0-9\\-_]+)/(.*)$~', $path, $m)) { return $response->setStatusCode(400)->setContent('Malformatted request URL'); } list(, $expires, $last_updated, $disposition, $use_cookie, $mac, $path_from_dataroot) = $m; if ($expires && $expires < time()) { return $response->setStatusCode(403)->setContent('URL has expired'); } $hmac_data = array('expires' => (int) $expires, 'last_updated' => (int) $last_updated, 'disposition' => $disposition, 'path' => $path_from_dataroot, 'use_cookie' => (int) $use_cookie); if ((bool) $use_cookie) { $hmac_data['cookie'] = $this->getCookieValue($request); } ksort($hmac_data); $hmac = $this->crypto->getHmac($hmac_data); if (!$hmac->matchesToken($mac)) { return $response->setStatusCode(403)->setContent('HMAC mistmatch'); } $dataroot = $this->config->getDataPath(); $filenameonfilestore = "{$dataroot}{$path_from_dataroot}"; if (!is_readable($filenameonfilestore)) { return $response->setStatusCode(404)->setContent('File not found'); } $actual_last_updated = filemtime($filenameonfilestore); if ($actual_last_updated != $last_updated) { return $response->setStatusCode(403)->setContent('URL has expired'); } $if_none_match = $request->headers->get('if_none_match'); if (!empty($if_none_match)) { // strip mod_deflate suffixes $request->headers->set('if_none_match', str_replace('-gzip', '', $if_none_match)); } $etag = '"' . $actual_last_updated . '"'; $response->setPublic()->setEtag($etag); if ($response->isNotModified($request)) { return $response; } $public = $use_cookie ? false : true; $content_disposition = $disposition == 'i' ? 'inline' : 'attachment'; $headers = ['Content-Type' => (new MimeTypeDetector())->getType($filenameonfilestore)]; $response = new BinaryFileResponse($filenameonfilestore, 200, $headers, $public, $content_disposition); $sendfile_type = $this->config->getVolatile('X-Sendfile-Type'); if ($sendfile_type) { $request->headers->set('X-Sendfile-Type', $sendfile_type); $mapping = (string) $this->config->getVolatile('X-Accel-Mapping'); $request->headers->set('X-Accel-Mapping', $mapping); $response->trustXSendfileTypeHeader(); } $response->prepare($request); if (empty($expires)) { $expires = strtotime('+1 year'); } $expires_dt = (new DateTime())->setTimestamp($expires); $response->setExpires($expires_dt); $response->setEtag($etag); return $response; }
function testMacAlteredByArrayTypeModification() { $crypto = new ElggCrypto(); $key = 'a very bad key'; $t1 = $crypto->getHmac([12, 34], 'sha256', $key)->getToken(); $t2 = $crypto->getHmac([12, '34'], 'sha256', $key)->getToken(); $this->assertNotEquals($t1, $t2); }
/** * Initialise the site secret (32 bytes: "z" to indicate format + 186-bit key in Base64 URL). * * Used during installation and saves as a datalist. * * Note: Old secrets were hex encoded. * * @return mixed The site secret hash or false * @access private * @todo Move to better file. */ function init_site_secret() { $secret = 'z' . ElggCrypto::getRandomString(31); if (datalist_set('__site_secret__', $secret)) { return $secret; } return FALSE; }
/** * Generate an 8 character Base64 URL salt for the password * * @return string * @access private */ function _elgg_generate_password_salt() { return ElggCrypto::getRandomString(8); }
/** * Initialises the system session and potentially logs the user in * * This function looks for: * * 1. $_SESSION['id'] - if not present, we're logged out, and this is set to 0 * 2. The cookie 'elggperm' - if present, checks it for an authentication * token, validates it, and potentially logs the user in * * @uses $_SESSION * * @return bool * @access private */ function _elgg_session_boot() { global $DB_PREFIX, $CONFIG; // Use database for sessions // HACK to allow access to prefix after object destruction $DB_PREFIX = $CONFIG->dbprefix; if (!isset($CONFIG->use_file_sessions)) { session_set_save_handler("_elgg_session_open", "_elgg_session_close", "_elgg_session_read", "_elgg_session_write", "_elgg_session_destroy", "_elgg_session_gc"); } session_name('Elgg'); session_start(); // Generate a simple token (private from potentially public session id) if (!isset($_SESSION['__elgg_session'])) { $_SESSION['__elgg_session'] = ElggCrypto::getRandomString(32, ElggCrypto::CHARS_HEX); } // test whether we have a user session if (empty($_SESSION['guid'])) { // clear session variables before checking cookie unset($_SESSION['user']); unset($_SESSION['id']); unset($_SESSION['guid']); unset($_SESSION['code']); // is there a remember me cookie if (!empty($_COOKIE['elggperm'])) { // we have a cookie, so try to log the user in $code = $_COOKIE['elggperm']; $code = md5($code); if ($user = get_user_by_code($code)) { // we have a user, log him in $_SESSION['user'] = $user; $_SESSION['id'] = $user->getGUID(); $_SESSION['guid'] = $_SESSION['id']; $_SESSION['code'] = $_COOKIE['elggperm']; } else { if (_elgg_is_legacy_remember_me_token($_COOKIE['elggperm'])) { // may be attempt to brute force legacy low-entropy codes sleep(1); } setcookie("elggperm", "", time() - 86400 * 30, "/"); } } } else { // we have a session and we have already checked the fingerprint // reload the user object from database in case it has changed during the session if ($user = get_user($_SESSION['guid'])) { $_SESSION['user'] = $user; $_SESSION['id'] = $user->getGUID(); $_SESSION['guid'] = $_SESSION['id']; } else { // user must have been deleted with a session active unset($_SESSION['user']); unset($_SESSION['id']); unset($_SESSION['guid']); unset($_SESSION['code']); if (!empty($_COOKIE['elggperm']) && _elgg_is_legacy_remember_me_token($_COOKIE['elggperm'])) { // replace user's old weaker-entropy code with new one $code = _elgg_generate_remember_me_token(); $_SESSION['code'] = $code; $user->code = md5($code); $user->save(); setcookie("elggperm", $code, time() + 86400 * 30, "/"); } } } if (isset($_SESSION['guid'])) { set_last_action($_SESSION['guid']); } elgg_register_action('login', '', 'public'); elgg_register_action('logout'); // Register a default PAM handler register_pam_handler('pam_auth_userpass'); // Initialise the magic session global $SESSION; $SESSION = new ElggSession(); // Finally we ensure that a user who has been banned with an open session is kicked. if (isset($_SESSION['user']) && $_SESSION['user']->isBanned()) { session_destroy(); return false; } return true; }