浏览代码

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.
Timothy 3 年之前
父节点
当前提交
1c78ff1b9f
共有 2 个文件被更改,包括 79 次插入21 次删除
  1. 2 1
      Userland/Applications/3DFileViewer/CMakeLists.txt
  2. 77 20
      Userland/Applications/3DFileViewer/main.cpp

+ 2 - 1
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)

+ 77 - 20
Userland/Applications/3DFileViewer/main.cpp

@@ -6,6 +6,7 @@
 
 #include <LibCore/ElapsedTimer.h>
 #include <LibCore/File.h>
+#include <LibFileSystemAccessClient/Client.h>
 #include <LibGL/GL/gl.h>
 #include <LibGL/GLContext.h>
 #include <LibGUI/ActionGroup.h>
@@ -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);
+    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->open(Core::OpenMode::ReadOnly) && file->error() != ENOENT) {
+    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;
     }
 
-    if (file->is_device()) {
+    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<Gfx::Bitmap> 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<String> 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();
 }