diff --git a/lib/classes/CSRFProtection.php b/lib/classes/CSRFProtection.php index 440919efe92318f144bf51f0af44dfc8933a8863..56d6e4cc836786841ba34b02fe982fcadd01573b 100644 --- a/lib/classes/CSRFProtection.php +++ b/lib/classes/CSRFProtection.php @@ -44,6 +44,35 @@ class CSRFProtection const AJAX_TOKEN = 'HTTP_X_CSRF_TOKEN'; + protected static $storage = null; + + /** + * Set a storage to use. + * + * @param $storage + */ + public static function setStorage(&$storage): void + { + self::$storage = &$storage; + } + + /** + * Returns a reference to the used storage. + * + * @return array|null + */ + public static function &getStorage() + { + if (!isset(self::$storage)) { + // w/o a session, throw an exception since we cannot use it + if (session_id() === '') { + throw new SessionRequiredException(); + } + + self::$storage = $_SESSION; + } + return self::$storage; + } /** * This checks the request and throws an InvalidSecurityTokenException if @@ -118,17 +147,14 @@ class CSRFProtection */ public static function token() { - // w/o a session, throw an exception - if (session_id() === '') { - throw new SessionRequiredException(); - } + $storage = &self::getStorage(); // create a token, if there is none - if (!isset($_SESSION[self::TOKEN])) { - $_SESSION[self::TOKEN] = base64_encode(random_bytes(32)); + if (!isset($storage[self::TOKEN])) { + $storage[self::TOKEN] = base64_encode(random_bytes(32)); } - return $_SESSION[self::TOKEN]; + return $storage[self::TOKEN]; } /** diff --git a/lib/classes/StudipCoreFormat.php b/lib/classes/StudipCoreFormat.php index 4d4b14b855fe4952027e0edfc4fec333f3a6f791..24c4ddcdf62e17e074f47c4320bb18264222b8b0 100644 --- a/lib/classes/StudipCoreFormat.php +++ b/lib/classes/StudipCoreFormat.php @@ -515,8 +515,6 @@ class StudipCoreFormat extends TextFormat $email = $matches[2]; $domain = $matches[3]; - $intern = $domain === $_SERVER['HTTP_HOST']; - return sprintf('<a href="mailto:%1$s">%2$s</a>', $email, $link_text @@ -567,6 +565,7 @@ class StudipCoreFormat extends TextFormat $intern = false; if ( in_array($pu['scheme'], ['http', 'https']) + && isset($_SERVER['HTTP_HOST']) && ( !isset($pu['host']) || $pu['host'] === $_SERVER['HTTP_HOST'] diff --git a/lib/classes/StudipPDO.class.php b/lib/classes/StudipPDO.class.php index 3fe07188efb152f50d033fe867e66166447d2852..08012b105456b947d18b24e3372f2d7c8f813673 100644 --- a/lib/classes/StudipPDO.class.php +++ b/lib/classes/StudipPDO.class.php @@ -83,6 +83,7 @@ class StudipPDO extends PDO // split string into parts at quotes and backslash $parts = preg_split('/([\\\\"\'])/', $statement, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); $result = ''; + $quote_chr = null; for ($part = current($parts); $part !== false; $part = next($parts)) { // inside quotes, "" is ", '' is ' and \x is x diff --git a/lib/classes/Visibility.php b/lib/classes/Visibility.php index ce191d2ab8f4d8a81b917ea4fa029dc752fe8b80..1b8723011523852c6c1269117b08035befa0bc49 100644 --- a/lib/classes/Visibility.php +++ b/lib/classes/Visibility.php @@ -500,8 +500,8 @@ class Visibility */ private static function getUser(&$user) { - if ($user == null) { - $user = $GLOBALS['user']->user_id; + if (!$user && User::findCurrent()) { + $user = User::findCurrent()->id; } } diff --git a/lib/models/CronjobSchedule.class.php b/lib/models/CronjobSchedule.class.php index 6fcb68ff9651936362af1eff40ab6b7131c498c3..4304be1717948f7ec5012e83fbc7ac50fc8d2cfe 100644 --- a/lib/models/CronjobSchedule.class.php +++ b/lib/models/CronjobSchedule.class.php @@ -130,7 +130,7 @@ class CronjobSchedule extends SimpleORMap } if (in_array($type, ['after_initialize', 'after_store']) && is_string($this->parameters)) { $parameters = json_decode($this->parameters, true) ?: []; - if ($this->task->valid) { + if ($this->task && $this->task->valid) { $default_parameters = $this->task->extractDefaultParameters(); foreach ($default_parameters as $key => $value) { if (!isset($parameters[$key])) { diff --git a/lib/models/SimpleORMap.class.php b/lib/models/SimpleORMap.class.php index 3ff4cc083287d0c08a24f3cbf7ca6380e6272517..8f951b4abc33d03e8d498fada7ce1fc436393a22 100644 --- a/lib/models/SimpleORMap.class.php +++ b/lib/models/SimpleORMap.class.php @@ -863,7 +863,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate if (is_array($id_or_object)) { $pk = static::pk(); $key_values = []; - foreach($pk as $key) { + foreach ($pk as $key) { if (array_key_exists($key, $id_or_object)) { $key_values[] = $id_or_object[$key]; } @@ -874,6 +874,8 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate } else { $id = $key_values; } + } else { + $id = null; } } else { $id = $id_or_object; diff --git a/lib/visual.inc.php b/lib/visual.inc.php index 30f99497519c416ebed424481e0513725953bd31..5cef921b16dbf8e147bbfdc13cbca3d4e61e2566 100644 --- a/lib/visual.inc.php +++ b/lib/visual.inc.php @@ -294,9 +294,9 @@ function isLinkIntern($url) { return true; } - return in_array($pum['scheme'] ?? null, ['https', 'http', NULL], true) - && in_array($pum['host'] ?? null, [$_SERVER['SERVER_NAME'], NULL], true) - && in_array($pum['port'] ?? null, [$_SERVER['SERVER_PORT'], NULL], true) + return in_array($pum['scheme'] ?? null, ['https', 'http', null], true) + && in_array($pum['host'] ?? null, [$_SERVER['SERVER_NAME'] ?? null, null], true) + && in_array($pum['port'] ?? null, [$_SERVER['SERVER_PORT'] ?? null, null], true) && mb_strpos($pum['path'] ?? '', $GLOBALS['CANONICAL_RELATIVE_PATH_STUDIP']) === 0; } diff --git a/tests/unit/lib/classes/CsrfProtectionTest.php b/tests/unit/lib/classes/CsrfProtectionTest.php index 1a74598188b1e231328244316b691643d55edd7a..69bc7a61960a4e21e3e10d6c3021205fe3f95e66 100644 --- a/tests/unit/lib/classes/CsrfProtectionTest.php +++ b/tests/unit/lib/classes/CsrfProtectionTest.php @@ -12,27 +12,18 @@ class CSRFProtectionTokenTest extends \Codeception\Test\Unit { - private $original_session; + use CsrfProtectionSessionTrait; function setUp(): void { - if (session_id() === '') { - session_id("test-session"); - } - $this->original_session = $_SESSION; - $_SESSION = []; - } - - function tearDown(): void - { - $_SESSION = $this->original_session; + $this->initializeTokenStorage(); } function testTokenGeneration() { - $this->assertEquals(sizeof($_SESSION), 0); + $this->assertEquals(count($this->storage), 0); CSRFProtection::token(); - $this->assertEquals(sizeof($_SESSION), 1); + $this->assertEquals(count($this->storage), 1); } function testTokenIdentity() @@ -44,7 +35,7 @@ class CSRFProtectionTokenTest extends \Codeception\Test\Unit { $token1 = CSRFProtection::token(); - $_SESSION = []; + $this->storage = []; $token2 = CSRFProtection::token(); @@ -66,16 +57,17 @@ class CSRFProtectionTokenTest extends \Codeception\Test\Unit class CSRFRequestTest extends \Codeception\Test\Unit { + use CsrfProtectionSessionTrait; + private $original_state; private $token; function setUp(): void { - if (session_id() === '') { - session_id("test-session"); - } - $this->original_state = [$_SESSION, $_POST, $_SERVER]; - $_SESSION = []; + $this->initializeTokenStorage(); + + $this->original_state = [$_POST, $_SERVER]; + $_POST = []; $this->token = CSRFProtection::token(); $_SERVER['HTTP_X_REQUESTED_WITH'] = null; @@ -83,7 +75,7 @@ class CSRFRequestTest extends \Codeception\Test\Unit function tearDown(): void { - list($_SESSION, $_POST, $_SERVER) = $this->original_state; + [$_POST, $_SERVER] = $this->original_state; } function testInvalidUnsafeRequest() @@ -96,7 +88,7 @@ class CSRFRequestTest extends \Codeception\Test\Unit function testValidUnsafeRequest() { $_SERVER['REQUEST_METHOD'] = 'POST'; - $_POST['security_token'] = $this->token; + $_POST[CSRFProtection::TOKEN] = $this->token; CSRFProtection::verifyUnsafeRequest(); $this->assertTrue(true); } @@ -134,3 +126,13 @@ class CSRFRequestTest extends \Codeception\Test\Unit $this->assertTrue(true); } } + +trait CsrfProtectionSessionTrait +{ + protected $storage = []; + + protected function initializeTokenStorage() + { + CSRFProtection::setStorage($this->storage); + } +} diff --git a/tests/unit/lib/classes/MigrationTest.php b/tests/unit/lib/classes/MigrationTest.php index dd78ac7ed7df67e1de1f426202a13989db736dd1..444ebf2fe8e5d5ebcdb3bdbd3da52d289be10c46 100644 --- a/tests/unit/lib/classes/MigrationTest.php +++ b/tests/unit/lib/classes/MigrationTest.php @@ -58,7 +58,7 @@ class MigrationTest extends \Codeception\Test\Unit public function get($branch = 0) { - return $this->versions[$branch]; + return $this->versions[$branch] ?? 0; } public function set($version, $branch = 0) diff --git a/tests/unit/lib/classes/TextFormatTest.php b/tests/unit/lib/classes/TextFormatTest.php index 2174bb9dd56a7212e57d3952cccb3f9bb9f558e8..0d5007621bab3c480b0731885c6e516f9ac4abc4 100644 --- a/tests/unit/lib/classes/TextFormatTest.php +++ b/tests/unit/lib/classes/TextFormatTest.php @@ -101,6 +101,7 @@ function markupList($markup, $matches) $rows = explode("\n", rtrim($matches[0])); $indent = 0; + $result = ''; foreach ($rows as $row) { list($level, $text) = explode(' ', $row, 2); $level = mb_strlen($level);