mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-04 14:20:58 +00:00
Escape Project Metadata in the Project Page and Restrict Accessory Opening (#15956)
* Escape Project Metadata in the Project Page and Restrict Accessory Opening The Project page rendered the model and profile name, author, description and accessory file names from the 3MF as live HTML. Names, authors and file names are now set as text, and the file list is built from DOM nodes with bound click handlers instead of concatenated markup. Descriptions can legitimately carry rich-text HTML, so they are rebuilt from an inert DOMParser document, keeping only plain formatting tags, http(s) links and http(s) images, with every other attribute dropped. Opening an accessory from the page now only launches regular files that lie inside the project's extracted auxiliary directory. The containment check is a new libslic3r helper, is_absolute_path_within_root, built on is_path_within_root so symlinks leading out of the root are rejected too. * Tighten Project Page Description Rendering and Keep More Formatting Link and image URLs in descriptions must now start with an http or https scheme as written and parse as such with the URL parser. Preview images are built as DOM nodes like the file list, and accessory names show their full text as a tooltip. Descriptions keep more plain formatting: del, ins, figure, figcaption, dl, dt, dd, caption, q, abbr, kbd and wbr, plus alt, title, width and height on images, colspan and rowspan on table cells and start on ordered lists. Numeric attributes must be plain integers. Embedded YouTube players become a link to the video. * Confirm Before Opening Program Attachments and Load Only HTTPS Images Opening a project attachment whose type runs as a program or script (executables, installers, shortcuts, shell and PowerShell scripts, macOS command files and apps, Linux desktop entries) now asks for confirmation first. The check lives in libslic3r as is_executable_file_name and ignores the trailing dots and spaces Windows strips from file names. Images in project descriptions are kept only when they load over https, so opening the Project tab no longer issues plain-http requests. * Open Project Attachments Through One Guarded Helper The Edit Project Info view launched attachments directly, without the checks the project page has. Both now call desktop_open_project_attachment, which checks that the file is inside the auxiliary directory, asks for confirmation where needed and then opens it. The auxiliary root was built through encode_path, which returns code page bytes on Windows, while boost::filesystem reads a narrow string as UTF-8. With a non-ASCII temporary directory the root never matched and no attachment opened. It is now built from the UTF-8 path directly. The list of program extensions could not be kept complete and let unknown types open without a prompt. It is replaced by is_safe_to_open_file_name, a list of plain document, image, model and video types that open directly. Everything else asks first.
This commit is contained in:
@@ -322,3 +322,68 @@ TEST_CASE("is_symlink_target_within_root rejects a target that passes through a
|
||||
CHECK(is_symlink_target_within_root("link", "in/lib.so", root));
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("is_absolute_path_within_root accepts only entries inside the root", "[utils]") {
|
||||
namespace fs = boost::filesystem;
|
||||
ScopedTemporaryDir outer;
|
||||
const fs::path root = outer.path() / "Auxiliaries";
|
||||
fs::create_directories(root / "Others");
|
||||
const fs::path inside = root / "Others" / "note.txt";
|
||||
const fs::path outside = outer.path() / "secret.txt";
|
||||
std::ofstream(inside.string()) << "inside";
|
||||
std::ofstream(outside.string()) << "outside";
|
||||
|
||||
SECTION("a file inside the root") {
|
||||
REQUIRE(is_absolute_path_within_root(inside, root));
|
||||
}
|
||||
SECTION("a path inside the root whose file does not exist yet") {
|
||||
REQUIRE(is_absolute_path_within_root(root / "Others" / "missing.txt", root));
|
||||
}
|
||||
SECTION("the root itself") {
|
||||
REQUIRE_FALSE(is_absolute_path_within_root(root, root));
|
||||
}
|
||||
SECTION("a parent-directory escape spelled under the root") {
|
||||
REQUIRE_FALSE(is_absolute_path_within_root(root / "Others" / ".." / ".." / "secret.txt", root));
|
||||
}
|
||||
SECTION("an absolute path elsewhere") {
|
||||
REQUIRE_FALSE(is_absolute_path_within_root(outside, root));
|
||||
}
|
||||
SECTION("a sibling directory sharing the root's name as a prefix") {
|
||||
const fs::path sibling = outer.path() / "Auxiliaries2" / "note.txt";
|
||||
REQUIRE_FALSE(is_absolute_path_within_root(sibling, root));
|
||||
}
|
||||
SECTION("a relative path") {
|
||||
REQUIRE_FALSE(is_absolute_path_within_root(fs::path("Others") / "note.txt", root));
|
||||
}
|
||||
SECTION("an empty path") {
|
||||
REQUIRE_FALSE(is_absolute_path_within_root(fs::path(), root));
|
||||
}
|
||||
#ifndef _WIN32
|
||||
// Creating symlinks on Windows needs elevated rights or developer mode.
|
||||
SECTION("a symlink inside the root that points outside") {
|
||||
const fs::path link = root / "Others" / "link.txt";
|
||||
fs::create_symlink(outside, link);
|
||||
REQUIRE_FALSE(is_absolute_path_within_root(link, root));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("is_safe_to_open_file_name accepts plain documents, images and models", "[utils]") {
|
||||
const std::string safe = GENERATE(as<std::string>{},
|
||||
"Manual.pdf", "BOM.xlsx", "BOM.csv", "guide.docx", "notes.txt", "README.md", "photo.JPG", "render.png",
|
||||
"assembly.step", "part.stl", "project.3mf", "drawing.dxf", "build.mp4", "setup.exe.pdf", ".pdf");
|
||||
INFO(safe);
|
||||
CHECK(is_safe_to_open_file_name(safe));
|
||||
}
|
||||
|
||||
TEST_CASE("is_safe_to_open_file_name rejects programs and anything it does not know", "[utils]") {
|
||||
const std::string unsafe = GENERATE(as<std::string>{},
|
||||
"setup.exe", "SETUP.EXE", "Manual.pdf.exe", "run.bat", "shortcut.lnk", "site.url", "script.ps1", "help.chm",
|
||||
"tool.jar", "script.py", "Install.command", "install.sh", "launcher.desktop", "Printer.AppImage",
|
||||
// Documents that can carry macros or scripts.
|
||||
"BOM.xls", "BOM.xlsm", "guide.doc", "guide.docm", "sheet.ods", "page.html", "logo.svg", "bundle.zip",
|
||||
// No extension, an unknown one, or a name the desktop would read differently.
|
||||
"readme", "pdf", "data.xyz", "", "...", "Manual.pdf.", "Manual.pdf ", "setup.exe:note.txt", "dir.pdf/readme");
|
||||
INFO(unsafe);
|
||||
CHECK_FALSE(is_safe_to_open_file_name(unsafe));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user