Jelajahi Sumber

Disallow setting non-existent theme (#7722)

Related: https://github.com/FreshRSS/xExtension-Demo/pull/2, https://github.com/FreshRSS/FreshRSS/pull/7559#issuecomment-2858083635

Mostly to make sure that no one is able to break the demo instance
But the issues below could possibly be exploited in other scenarios too:
* Setting a theme like `../../lib/core-extensions/UserJS`: this directory contains `metadata.json` like themes do, so FreshRSS treats it as a theme after setting it and doesn't load any CSS
* Setting a theme like `x dropdown-menu`: the `dropdown-menu` class was able to get injected into the `<body>` element since https://github.com/FreshRSS/FreshRSS/pull/7559 and turn every page blank
Inverle 8 bulan lalu
induk
melakukan
6549932d59
2 mengubah file dengan 10 tambahan dan 1 penghapusan
  1. 4 1
      app/Controllers/configureController.php
  2. 6 0
      app/Models/Themes.php

+ 4 - 1
app/Controllers/configureController.php

@@ -47,7 +47,10 @@ class FreshRSS_configure_Controller extends FreshRSS_ActionController {
 		if (Minz_Request::isPost()) {
 			FreshRSS_Context::userConf()->language = Minz_Request::paramString('language') ?: 'en';
 			FreshRSS_Context::userConf()->timezone = Minz_Request::paramString('timezone');
-			FreshRSS_Context::userConf()->theme = Minz_Request::paramString('theme') ?: FreshRSS_Themes::$defaultTheme;
+			$theme = Minz_Request::paramString('theme') ?: FreshRSS_Themes::$defaultTheme;
+			if (FreshRSS_Themes::exists($theme)) {
+				FreshRSS_Context::userConf()->theme = $theme;
+			}
 			FreshRSS_Context::userConf()->darkMode = Minz_Request::paramString('darkMode') ?: 'auto';
 			FreshRSS_Context::userConf()->content_width = Minz_Request::paramString('content_width') ?: 'thin';
 			FreshRSS_Context::userConf()->topline_read = Minz_Request::paramBoolean('topline_read');

+ 6 - 0
app/Models/Themes.php

@@ -15,6 +15,12 @@ class FreshRSS_Themes extends Minz_Model {
 		));
 	}
 
+	public static function exists(string $theme_id): bool {
+		$theme_dir = PUBLIC_PATH . self::$themesUrl . $theme_id;
+		return str_replace(['..', '/', DIRECTORY_SEPARATOR], '', $theme_id) === $theme_id
+			&& file_exists($theme_dir . '/metadata.json');
+	}
+
 	/** @return array<string,array{id:string,name:string,author:string,description:string,version:float|string,files:array<string>,theme-color?:string|array{dark?:string,light?:string,default?:string}}> */
 	public static function get(): array {
 		$themes_list = self::getList();