From c32cd78bc4dba5a460a47a2d9e46029e49476149 Mon Sep 17 00:00:00 2001 From: Gaspar Capello Date: Wed, 10 Apr 2024 17:43:46 -0300 Subject: [PATCH] Don't allow to install third-party themes that override the default one (fix #4226) This fix 1) hides user themes whose name is the same as the default, and are present in the user folders (i.e. 'extensions' and 'data/themes' folders), and 2) does't allow to install themes with the same content/ID of the default aseprite-theme (fix #4226) --- data/strings/en.ini | 2 ++ src/app/commands/cmd_options.cpp | 48 +++++++++++++++++++++++++++++++- src/app/extensions.cpp | 14 ++++++++-- src/app/extensions.h | 7 +++-- 4 files changed, 65 insertions(+), 6 deletions(-) diff --git a/data/strings/en.ini b/data/strings/en.ini index 3b3735720..6deef83af 100644 --- a/data/strings/en.ini +++ b/data/strings/en.ini @@ -62,6 +62,7 @@ deleting_tilemaps_will_delete_tilesets = Warning\n< Save As" menu option in that case.\n||&OK cannot_open_file = Problem< {2}%\n<< UI Scaling: {3}% -> {4}%\n<extensions().getCompressedExtensionInfo(filename); + // Check if the filename corresponds to aseprite-default theme + if (base::string_to_lower(info.name) == + Extensions::kAsepriteDefaultThemeName) { + ui::Alert::show( + fmt::format(Strings::alerts_cannot_install_default_extension())); + return false; + } + // Install? if (ui::Alert::show(Strings::alerts_install_extension(filename)) != 1) return false; @@ -1378,7 +1390,8 @@ private: if (!ext->isEnabled()) continue; - if (ext->themes().empty()) + if (ext->themes().empty() || + isExtensionADuplicatedDefaultTheme(ext)) continue; if (first) { @@ -1410,6 +1423,9 @@ private: extensionsList()->addChild(sep); for (auto e : App::instance()->extensions()) { if (e->category() == category) { + if (category == Extension::Category::Themes && + isExtensionADuplicatedDefaultTheme(e)) + continue; ExtensionItem* item = new ExtensionItem(e); extensionsList()->addChild(item); hasItems = true; @@ -1571,6 +1587,11 @@ private: // package.json file. ExtensionInfo info = exts.getCompressedExtensionInfo(filename); + if (info.themeId == "default") { + ui::Alert::show( + fmt::format(Strings::alerts_cannot_open_theme())); + return; + } // Check if the extension already exist for (auto ext : exts) { if (base::string_to_lower(ext->name()) != @@ -1749,6 +1770,17 @@ private: return paths; } + static base::paths getUserDirPaths(const base::paths& dirNames) { + ResourceFinder rf; + for (auto& fn : dirNames) + rf.includeUserDir(fn.c_str()); + + base::paths paths; + while (rf.next()) + paths.push_back(base::normalize_path(rf.filename())); + return paths; + } + void updateCategoryVisibility() { bool visibleCategories[int(Extension::Category::Max)]; for (auto& v : visibleCategories) @@ -1764,6 +1796,20 @@ private: } } + // Function to determine if the input extension is the default theme + static bool isExtensionADuplicatedDefaultTheme(const Extension* e) { + if (!e->isDefaultTheme()) + return false; + auto userThemePaths = + getUserDirPaths({"extensions", skin::SkinTheme::kThemesFolderName}); + for (auto& p : userThemePaths) { + // Has the user path (p) the same path of the extension (e->path())? + if (std::strncmp(e->path().c_str(), p.c_str(), p.size()) == 0) + return true; + } + return false; + } + #ifdef LAF_WINDOWS void onTabletAPIChange() { const bool pointerApi = tabletApiWindowsPointer()->isSelected(); diff --git a/src/app/extensions.cpp b/src/app/extensions.cpp index 768a9435e..9061b1d6a 100644 --- a/src/app/extensions.cpp +++ b/src/app/extensions.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2020-2023 Igara Studio S.A. +// Copyright (C) 2020-2024 Igara Studio S.A. // Copyright (C) 2017-2018 David Capello // // This program is distributed under the terms of @@ -51,12 +51,13 @@ namespace app { +const char* Extensions::kAsepriteDefaultThemeName = "aseprite-theme"; + namespace { const char* kPackageJson = "package.json"; const char* kInfoJson = "__info.json"; const char* kPrefLua = "__pref.lua"; -const char* kAsepriteDefaultThemeExtensionName = "aseprite-theme"; class ReadArchive { public: @@ -283,6 +284,8 @@ void Extension::addTheme(const std::string& id, const std::string& path, const std::string& variant) { + if (id == "default" && !isDefaultTheme()) + return; m_themes[id] = ThemeInfo(path, variant); updateCategory(Category::Themes); } @@ -519,7 +522,7 @@ bool Extension::isCurrentTheme() const bool Extension::isDefaultTheme() const { - return (name() == kAsepriteDefaultThemeExtensionName); + return name() == Extensions::kAsepriteDefaultThemeName; } void Extension::updateCategory(const Category newCategory) @@ -1003,6 +1006,11 @@ ExtensionInfo Extensions::getCompressedExtensionInfo(const std::string& zipFn) std::string err; auto json = json11::Json::parse(out.str(), err); if (err.empty()) { + if (json["contributes"].is_object()) { + auto themes = json["contributes"]["themes"]; + if (themes.is_array() && themes[0].is_object()) + info.themeId = themes[0]["id"].string_value(); + } info.name = json["name"].string_value(); info.version = json["version"].string_value(); info.dstPath = base::join_path(m_userExtensionsPath, info.name); diff --git a/src/app/extensions.h b/src/app/extensions.h index 072ecfbd6..df4018ae8 100644 --- a/src/app/extensions.h +++ b/src/app/extensions.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2020-2023 Igara Studio S.A. +// Copyright (C) 2020-2024 Igara Studio S.A. // Copyright (C) 2017-2018 David Capello // // This program is distributed under the terms of @@ -30,6 +30,7 @@ namespace app { class Extensions; struct ExtensionInfo { + std::string themeId; std::string name; std::string version; std::string dstPath; @@ -54,6 +55,8 @@ namespace app { Max }; + bool isDefaultTheme() const; + class DitheringMatrixInfo { public: DitheringMatrixInfo(); @@ -150,7 +153,6 @@ namespace app { void uninstall(const DeletePluginPref delPref); void uninstallFiles(const std::string& path, const DeletePluginPref delPref); - bool isDefaultTheme() const; void updateCategory(const Category newCategory); #ifdef ENABLE_SCRIPTING void initScripts(); @@ -196,6 +198,7 @@ namespace app { public: typedef std::vector List; typedef List::iterator iterator; + static const char* kAsepriteDefaultThemeName; Extensions(); ~Extensions();