diff --git a/lib/SP/Html/Html.php b/lib/SP/Html/Html.php
index eeb4072e5..172e7f1e4 100644
--- a/lib/SP/Html/Html.php
+++ b/lib/SP/Html/Html.php
@@ -184,19 +184,19 @@ public static function stripTags(string $text): string
*/
public static function getSafeUrl(string $url): string
{
- $match = preg_match('#^(([a-z]+)://[\w._-]+)(?:/(.*))?#i', $url, $urlParts);
+ $urlParts = parse_url($url);
- if ($match !== 1) {
- return htmlspecialchars($url, ENT_QUOTES);
+ if ($urlParts === false) {
+ return 'malformed_url';
}
- switch (count($urlParts)) {
- case 3:
- return htmlspecialchars($urlParts[1], ENT_QUOTES).'/'.urlencode($urlParts[2]);
- case 2:
- return htmlspecialchars($urlParts[1], ENT_QUOTES);
- default:
- return htmlspecialchars($url, ENT_QUOTES);
- }
+ return preg_replace_callback(
+ '/[^:\/@?&=#%\w]+/u',
+ function ($matches)
+ {
+ return urlencode($matches[0]);
+ },
+ $url
+ );
}
}
diff --git a/lib/SP/Services/Install/Installer.php b/lib/SP/Services/Install/Installer.php
index 956b79d40..abc8a665a 100644
--- a/lib/SP/Services/Install/Installer.php
+++ b/lib/SP/Services/Install/Installer.php
@@ -60,9 +60,9 @@ final class Installer extends Service
/**
* sysPass' version and build number
*/
- const VERSION = [3, 2, 9];
+ const VERSION = [3, 2, 10];
const VERSION_TEXT = '3.2';
- const BUILD = 22062501;
+ const BUILD = 22070101;
/**
* @var DatabaseSetupInterface
diff --git a/tests/SP/Html/HtmlTest.php b/tests/SP/Html/HtmlTest.php
new file mode 100644
index 000000000..16f0cd639
--- /dev/null
+++ b/tests/SP/Html/HtmlTest.php
@@ -0,0 +1,72 @@
+.
+ */
+
+namespace SP\Tests\Html;
+
+use Faker\Factory;
+use PHPUnit\Framework\TestCase;
+use SP\Html\Html;
+
+/**
+ * Class HtmlTest
+ */
+class HtmlTest extends TestCase
+{
+ private static $faker;
+
+ public static function setUpBeforeClass(): void
+ {
+ parent::setUpBeforeClass();
+
+ self::$faker = Factory::create();
+ }
+
+
+ public function testGetSafeUrlOk()
+ {
+ $url = self::$faker->url;
+
+ $this->assertEquals($url, Html::getSafeUrl($url));
+ }
+
+ /**
+ * @dataProvider urlProvider
+ * @return void
+ */
+ public function testGetSafeUrlEncoded(string $url)
+ {
+ $this->assertEquals(0, preg_match('/["<>]+/', Html::getSafeUrl($url)));
+ }
+
+ private function urlProvider(): array
+ {
+ return [
+ ['https://foo.com/'],
+ ['https://foo.com/>'],
+ ['https://foo.com/">'],
+ ['https://foo.com/"%20onClick="alert(\'TEST\'")'],
+ ['https://foo.com/" onClick="alert(\'TEST\')"'],
+ ];
+ }
+}