From 1c78ff1b9fbecf12d02f9435b6b5b963d7db808f Mon Sep 17 00:00:00 2001 From: Timothy Date: Wed, 18 Aug 2021 23:33:09 +1000 Subject: [PATCH] 3DFileViewer: Use unveil and FileSystemAccessServer This will restrict 3DFileViewer's access to the file system. 3DFileViewer loads a texture based on the path of the model loaded, this will request access to the texture file before loading. --- .../Applications/3DFileViewer/CMakeLists.txt | 3 +- Userland/Applications/3DFileViewer/main.cpp | 101 ++++++++++++++---- 2 files changed, 81 insertions(+), 23 deletions(-) diff --git a/Userland/Applications/3DFileViewer/CMakeLists.txt b/Userland/Applications/3DFileViewer/CMakeLists.txt index 88abb914d6..1a9b2c0233 100644 --- a/Userland/Applications/3DFileViewer/CMakeLists.txt +++ b/Userland/Applications/3DFileViewer/CMakeLists.txt @@ -2,6 +2,7 @@ serenity_component( 3DFileViewer RECOMMENDED TARGETS 3DFileViewer + DEPENDS FileSystemAccessServer ) set(SOURCES @@ -11,4 +12,4 @@ set(SOURCES ) serenity_app(3DFileViewer ICON app-3d-file-viewer) -target_link_libraries(3DFileViewer LibGUI LibGL) +target_link_libraries(3DFileViewer LibGUI LibGL LibFileSystemAccessClient) diff --git a/Userland/Applications/3DFileViewer/main.cpp b/Userland/Applications/3DFileViewer/main.cpp index a3bae3e2d4..d1ae0549ea 100644 --- a/Userland/Applications/3DFileViewer/main.cpp +++ b/Userland/Applications/3DFileViewer/main.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -33,7 +34,9 @@ class GLContextWidget final : public GUI::Frame { C_OBJECT(GLContextWidget); public: - bool load(const String& fname); + bool load_path(String const& fname); + bool load_fd_and_close(int fd, String const& fname); + bool load_file(Core::File& file, String const& fname); void toggle_rotate_x() { m_rotate_x = !m_rotate_x; } void toggle_rotate_y() { m_rotate_y = !m_rotate_y; } void toggle_rotate_z() { m_rotate_z = !m_rotate_z; } @@ -191,26 +194,43 @@ void GLContextWidget::timer_event(Core::TimerEvent&) m_cycles++; } -bool GLContextWidget::load(const String& filename) +bool GLContextWidget::load_path(String const& filename) { auto file = Core::File::construct(filename); - if (!file->filename().ends_with(".obj")) { - GUI::MessageBox::show(window(), String::formatted("Opening \"{}\" failed: invalid file type", filename), "Error", GUI::MessageBox::Type::Error); - return false; - } - if (!file->open(Core::OpenMode::ReadOnly) && file->error() != ENOENT) { GUI::MessageBox::show(window(), String::formatted("Opening \"{}\" failed: {}", filename, strerror(errno)), "Error", GUI::MessageBox::Type::Error); return false; } - if (file->is_device()) { + return load_file(file, filename); +} + +bool GLContextWidget::load_fd_and_close(int fd, String const& filename) +{ + auto file = Core::File::construct(); + + if (!file->open(fd, Core::OpenMode::ReadOnly, Core::File::ShouldCloseFileDescriptor::Yes) && file->error() != ENOENT) { + GUI::MessageBox::show(window(), String::formatted("Opening \"{}\" failed: {}", filename, strerror(errno)), "Error", GUI::MessageBox::Type::Error); + return false; + } + + return load_file(file, filename); +} + +bool GLContextWidget::load_file(Core::File& file, String const& filename) +{ + if (!filename.ends_with(".obj")) { + GUI::MessageBox::show(window(), String::formatted("Opening \"{}\" failed: invalid file type", filename), "Error", GUI::MessageBox::Type::Error); + return false; + } + + if (file.is_device()) { GUI::MessageBox::show(window(), String::formatted("Opening \"{}\" failed: Can't open device files", filename), "Error", GUI::MessageBox::Type::Error); return false; } - if (file->is_directory()) { + if (file.is_directory()) { GUI::MessageBox::show(window(), String::formatted("Opening \"{}\" failed: Can't open directories", filename), "Error", GUI::MessageBox::Type::Error); return false; } @@ -226,8 +246,21 @@ bool GLContextWidget::load(const String& filename) builder.append(filename.split('.').at(0)); builder.append(".bmp"); + String texture_path = Core::File::absolute_path(builder.string_view()); + // Attempt to open the texture file from disk - auto texture_image = Gfx::Bitmap::try_load_from_file(builder.string_view()); + RefPtr texture_image; + if (Core::File::exists(texture_path)) { + texture_image = Gfx::Bitmap::try_load_from_file(texture_path); + } else { + auto result = FileSystemAccessClient::Client::the().request_file(window()->window_id(), builder.string_view(), Core::OpenMode::ReadOnly); + + if (result.error != 0) { + return false; + } + + texture_image = Gfx::Bitmap::try_load_from_fd_and_close(*result.fd, *result.chosen_file); + } GLuint tex; glGenTextures(1, &tex); @@ -249,11 +282,36 @@ int main(int argc, char** argv) { auto app = GUI::Application::construct(argc, argv); - if (pledge("stdio thread recvfd sendfd rpath", nullptr) < 0) { + if (pledge("stdio thread recvfd sendfd rpath unix", nullptr) < 0) { perror("pledge"); return 1; } + if (unveil("/tmp/portal/filesystemaccess", "rw") < 0) { + perror("unveil"); + return 1; + } + + if (unveil("/home/anon/Documents/3D Models/teapot.obj", "r") < 0) { + perror("unveil"); + return 1; + } + + if (unveil("/home/anon/Documents/3D Models/teapot.bmp", "r") < 0) { + perror("unveil"); + return 1; + } + + if (unveil("/res", "r") < 0) { + perror("unveil"); + return 1; + } + + if (unveil(nullptr, nullptr) < 0) { + perror("unveil"); + return 1; + } + // Construct the main window auto window = GUI::Window::construct(); auto app_icon = GUI::Icon::default_icon("app-3d-file-viewer"); @@ -273,20 +331,16 @@ int main(int argc, char** argv) auto& file_menu = window->add_menu("&File"); - auto load_model = [&](StringView const& filename) { - if (widget.load(filename)) { - auto canonical_path = Core::File::real_path_for(filename); - window->set_title(String::formatted("{} - 3D File Viewer", canonical_path)); - } - }; - file_menu.add_action(GUI::CommonActions::make_open_action([&](auto&) { - Optional open_path = GUI::FilePicker::get_open_filepath(window); + auto result = FileSystemAccessClient::Client::the().open_file(window->window_id()); - if (!open_path.has_value()) + if (result.error != 0) return; - load_model(open_path.value()); + if (widget.load_fd_and_close(*result.fd, *result.chosen_file)) { + auto canonical_path = Core::File::absolute_path(*result.chosen_file); + window->set_title(String::formatted("{} - 3D File Viewer", canonical_path)); + } })); file_menu.add_separator(); file_menu.add_action(GUI::CommonActions::make_quit_action([&](auto&) { @@ -465,7 +519,10 @@ int main(int argc, char** argv) window->show(); auto filename = argc > 1 ? argv[1] : "/home/anon/Documents/3D Models/teapot.obj"; - load_model(filename); + if (widget.load_path(filename)) { + auto canonical_path = Core::File::absolute_path(filename); + window->set_title(String::formatted("{} - 3D File Viewer", canonical_path)); + } return app->exec(); }