Browse Source

fix: transparently package bundles as zip archives (#25030)

Shelley Vohr 4 years ago
parent
commit
284c1b9539

+ 1 - 0
BUILD.gn

@@ -386,6 +386,7 @@ source_set("electron_lib") {
     "//third_party/libyuv",
     "//third_party/webrtc_overrides:webrtc_component",
     "//third_party/widevine/cdm:headers",
+    "//third_party/zlib/google:zip",
     "//ui/base/idle",
     "//ui/events:dom_keycode_converter",
     "//ui/gl",

+ 3 - 0
filenames.gni

@@ -371,6 +371,9 @@ filenames = {
     "shell/browser/extended_web_contents_observer.h",
     "shell/browser/feature_list.cc",
     "shell/browser/feature_list.h",
+    "shell/browser/file_select_helper.cc",
+    "shell/browser/file_select_helper.h",
+    "shell/browser/file_select_helper_mac.mm",
     "shell/browser/font_defaults.cc",
     "shell/browser/font_defaults.h",
     "shell/browser/javascript_environment.cc",

+ 270 - 0
shell/browser/file_select_helper.cc

@@ -0,0 +1,270 @@
+// Copyright (c) 2020 Microsoft, Inc. All rights reserved.
+// Use of this source code is governed by the MIT license that can be
+// found in the LICENSE file.
+
+#include <memory>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "shell/browser/file_select_helper.h"
+
+#include "base/bind.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/common/pref_names.h"
+#include "components/prefs/pref_service.h"
+#include "shell/browser/electron_browser_context.h"
+#include "shell/browser/javascript_environment.h"
+#include "shell/browser/ui/file_dialog.h"
+#include "shell/common/gin_converters/callback_converter.h"
+#include "shell/common/gin_converters/file_path_converter.h"
+
+using blink::mojom::FileChooserFileInfo;
+using blink::mojom::FileChooserFileInfoPtr;
+using blink::mojom::FileChooserParams;
+using blink::mojom::NativeFileInfo;
+
+namespace {
+void DeleteFiles(std::vector<base::FilePath> paths) {
+  for (auto& file_path : paths)
+    base::DeleteFile(file_path);
+}
+}  // namespace
+
+FileSelectHelper::FileSelectHelper(
+    content::RenderFrameHost* render_frame_host,
+    scoped_refptr<content::FileSelectListener> listener,
+    FileChooserParams::Mode mode)
+    : render_frame_host_(render_frame_host),
+      listener_(std::move(listener)),
+      mode_(mode) {
+  DCHECK(render_frame_host_);
+  DCHECK(listener_);
+
+  web_contents_ = content::WebContents::FromRenderFrameHost(render_frame_host);
+  DCHECK(web_contents_);
+
+  content::WebContentsObserver::Observe(web_contents_);
+  observer_.Add(render_frame_host_->GetRenderViewHost()->GetWidget());
+}
+
+FileSelectHelper::~FileSelectHelper() = default;
+
+void FileSelectHelper::ShowOpenDialog(
+    const file_dialog::DialogSettings& settings) {
+  v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
+  v8::HandleScope scope(isolate);
+  gin_helper::Promise<gin_helper::Dictionary> promise(isolate);
+
+  auto callback = base::BindOnce(&FileSelectHelper::OnOpenDialogDone,
+                                 weak_ptr_factory_.GetWeakPtr());
+  ignore_result(promise.Then(std::move(callback)));
+
+  file_dialog::ShowOpenDialog(settings, std::move(promise));
+}
+
+void FileSelectHelper::ShowSaveDialog(
+    const file_dialog::DialogSettings& settings) {
+  v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
+  v8::HandleScope scope(isolate);
+  gin_helper::Promise<gin_helper::Dictionary> promise(isolate);
+
+  auto callback = base::BindOnce(&FileSelectHelper::OnSaveDialogDone,
+                                 weak_ptr_factory_.GetWeakPtr());
+  ignore_result(promise.Then(std::move(callback)));
+
+  file_dialog::ShowSaveDialog(settings, std::move(promise));
+}
+
+// net::DirectoryLister::DirectoryListerDelegate
+void FileSelectHelper::OnListFile(
+    const net::DirectoryLister::DirectoryListerData& data) {
+  if (!render_frame_host_ || !web_contents_) {
+    // If the frame or webcontents was destroyed under us. We
+    // must notify |listener_| and release our reference to
+    // ourself. RunFileChooserEnd() performs this.
+    RunFileChooserEnd();
+    return;
+  }
+  // We don't want to return directory paths, only file paths
+  if (data.info.IsDirectory())
+    return;
+
+  lister_paths_.push_back(data.path);
+}
+
+void FileSelectHelper::RunFileChooserEnd() {
+  // If there are temporary files, then this instance needs to stick around
+  // until web_contents_ is destroyed, so that this instance can delete the
+  // temporary files.
+  if (!temporary_files_.empty())
+    return;
+
+  if (listener_)
+    listener_->FileSelectionCanceled();
+
+  render_frame_host_ = nullptr;
+  web_contents_ = nullptr;
+
+  delete this;
+}
+
+// net::DirectoryLister::DirectoryListerDelegate
+void FileSelectHelper::OnListDone(int error) {
+  if (!render_frame_host_ || !web_contents_) {
+    // If the frame or webcontents was destroyed under us. We
+    // must notify |listener_| and release our reference to
+    // ourself. RunFileChooserEnd() performs this.
+    RunFileChooserEnd();
+    return;
+  }
+
+  std::vector<FileChooserFileInfoPtr> file_info;
+  for (const auto& path : lister_paths_)
+    file_info.push_back(FileChooserFileInfo::NewNativeFile(
+        NativeFileInfo::New(path, base::string16())));
+
+  OnFilesSelected(std::move(file_info), lister_base_dir_);
+}
+
+void FileSelectHelper::DeleteTemporaryFiles() {
+  base::ThreadPool::PostTask(
+      FROM_HERE,
+      {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+       base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
+      base::BindOnce(&DeleteFiles, std::move(temporary_files_)));
+}
+
+void FileSelectHelper::EnumerateDirectory() {
+  // Ensure that this fn is only called once
+  DCHECK(!lister_);
+  DCHECK(!lister_base_dir_.empty());
+  DCHECK(lister_paths_.empty());
+
+  lister_ = std::make_unique<net::DirectoryLister>(
+      lister_base_dir_, net::DirectoryLister::NO_SORT_RECURSIVE, this);
+  lister_->Start();
+}
+
+void FileSelectHelper::OnOpenDialogDone(gin_helper::Dictionary result) {
+  bool canceled = true;
+  result.Get("canceled", &canceled);
+
+  if (!render_frame_host_ || canceled) {
+    RunFileChooserEnd();
+  } else {
+    std::vector<base::FilePath> paths;
+    if (result.Get("filePaths", &paths)) {
+      std::vector<ui::SelectedFileInfo> files =
+          ui::FilePathListToSelectedFileInfoList(paths);
+      // If we are uploading a folder we need to enumerate its contents
+      if (mode_ == FileChooserParams::Mode::kUploadFolder &&
+          paths.size() >= 1) {
+        lister_base_dir_ = paths[0];
+        EnumerateDirectory();
+      } else {
+#if defined(OS_MAC)
+        base::ThreadPool::PostTask(
+            FROM_HERE,
+            {base::MayBlock(),
+             base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+            base::BindOnce(&FileSelectHelper::ProcessSelectedFilesMac,
+                           base::Unretained(this), files));
+#else
+        ConvertToFileChooserFileInfoList(files);
+#endif
+      }
+
+      if (render_frame_host_ && !paths.empty()) {
+        auto* browser_context = static_cast<electron::ElectronBrowserContext*>(
+            render_frame_host_->GetProcess()->GetBrowserContext());
+        browser_context->prefs()->SetFilePath(prefs::kSelectFileLastDirectory,
+                                              paths[0].DirName());
+      }
+    }
+  }
+}
+
+void FileSelectHelper::ConvertToFileChooserFileInfoList(
+    const std::vector<ui::SelectedFileInfo>& files) {
+  std::vector<FileChooserFileInfoPtr> file_info;
+
+  for (const auto& file : files) {
+    file_info.push_back(FileChooserFileInfo::NewNativeFile(NativeFileInfo::New(
+        file.local_path, base::FilePath(file.display_name).AsUTF16Unsafe())));
+  }
+
+  OnFilesSelected(std::move(file_info), lister_base_dir_);
+}
+
+void FileSelectHelper::OnSaveDialogDone(gin_helper::Dictionary result) {
+  std::vector<FileChooserFileInfoPtr> file_info;
+  bool canceled = true;
+  result.Get("canceled", &canceled);
+
+  if (!render_frame_host_ || canceled) {
+    RunFileChooserEnd();
+  } else {
+    base::FilePath path;
+    if (result.Get("filePath", &path)) {
+      file_info.push_back(FileChooserFileInfo::NewNativeFile(
+          NativeFileInfo::New(path, path.BaseName().AsUTF16Unsafe())));
+    }
+    // We should only call this if we have not cancelled the dialog.
+    OnFilesSelected(std::move(file_info), base::FilePath());
+  }
+}
+
+void FileSelectHelper::OnFilesSelected(
+    std::vector<FileChooserFileInfoPtr> file_info,
+    base::FilePath base_dir) {
+  if (listener_) {
+    listener_->FileSelected(std::move(file_info), base_dir, mode_);
+    listener_.reset();
+  }
+
+  render_frame_host_ = nullptr;
+
+  delete this;
+}
+
+void FileSelectHelper::RenderWidgetHostDestroyed(
+    content::RenderWidgetHost* widget_host) {
+  render_frame_host_ = nullptr;
+  observer_.Remove(widget_host);
+}
+
+// content::WebContentsObserver:
+void FileSelectHelper::RenderFrameHostChanged(
+    content::RenderFrameHost* old_host,
+    content::RenderFrameHost* new_host) {
+  if (!render_frame_host_)
+    return;
+  // The |old_host| and its children are now pending deletion. Do not give
+  // them file access past this point.
+  if (render_frame_host_ == old_host ||
+      render_frame_host_->IsDescendantOf(old_host)) {
+    render_frame_host_ = nullptr;
+  }
+}
+
+// content::WebContentsObserver:
+void FileSelectHelper::RenderFrameDeleted(
+    content::RenderFrameHost* deleted_host) {
+  if (deleted_host == render_frame_host_)
+    render_frame_host_ = nullptr;
+}
+
+// content::WebContentsObserver:
+void FileSelectHelper::WebContentsDestroyed() {
+  render_frame_host_ = nullptr;
+  web_contents_ = nullptr;
+
+  DeleteTemporaryFiles();
+
+  if (!lister_)
+    delete this;
+}

+ 118 - 0
shell/browser/file_select_helper.h

@@ -0,0 +1,118 @@
+// Copyright (c) 2020 Microsoft, Inc. All rights reserved.
+// Use of this source code is governed by the MIT license that can be
+// found in the LICENSE file.
+
+#ifndef SHELL_BROWSER_FILE_SELECT_HELPER_H_
+#define SHELL_BROWSER_FILE_SELECT_HELPER_H_
+
+#include <memory>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "chrome/common/pref_names.h"
+#include "content/public/browser/file_select_listener.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
+#include "content/public/browser/render_widget_host_observer.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "gin/dictionary.h"
+#include "net/base/directory_lister.h"
+#include "shell/browser/electron_browser_context.h"
+#include "shell/browser/ui/file_dialog.h"
+#include "shell/common/gin_helper/dictionary.h"
+#include "ui/shell_dialogs/selected_file_info.h"
+
+using blink::mojom::FileChooserParams;
+
+class FileSelectHelper : public content::WebContentsObserver,
+                         public content::RenderWidgetHostObserver,
+                         public net::DirectoryLister::DirectoryListerDelegate {
+ public:
+  FileSelectHelper(content::RenderFrameHost* render_frame_host,
+                   scoped_refptr<content::FileSelectListener> listener,
+                   FileChooserParams::Mode mode);
+  ~FileSelectHelper() override;
+
+  // WebDialogHelper::RunFileChooser
+
+  void ShowOpenDialog(const file_dialog::DialogSettings& settings);
+
+  void ShowSaveDialog(const file_dialog::DialogSettings& settings);
+
+ private:
+  // net::DirectoryLister::DirectoryListerDelegate overrides.
+  void OnListFile(
+      const net::DirectoryLister::DirectoryListerData& data) override;
+  void OnListDone(int error) override;
+
+  void DeleteTemporaryFiles();
+
+  void EnumerateDirectory();
+
+  void OnOpenDialogDone(gin_helper::Dictionary result);
+  void OnSaveDialogDone(gin_helper::Dictionary result);
+
+  void OnFilesSelected(
+      std::vector<blink::mojom::FileChooserFileInfoPtr> file_info,
+      base::FilePath base_dir);
+
+  void RunFileChooserEnd();
+
+  void ConvertToFileChooserFileInfoList(
+      const std::vector<ui::SelectedFileInfo>& files);
+
+#if defined(OS_MAC)
+  // Must be called from a MayBlock() task. Each selected file that is a package
+  // will be zipped, and the zip will be passed to the render view host in place
+  // of the package.
+  void ProcessSelectedFilesMac(const std::vector<ui::SelectedFileInfo>& files);
+
+  // Saves the paths of |zipped_files| for later deletion. Passes |files| to the
+  // render view host.
+  void ProcessSelectedFilesMacOnUIThread(
+      const std::vector<ui::SelectedFileInfo>& files,
+      const std::vector<base::FilePath>& zipped_files);
+
+  // Zips the package at |path| into a temporary destination. Returns the
+  // temporary destination, if the zip was successful. Otherwise returns an
+  // empty path.
+  static base::FilePath ZipPackage(const base::FilePath& path);
+#endif  // defined(OS_MAC)
+
+  // content::RenderWidgetHostObserver:
+  void RenderWidgetHostDestroyed(
+      content::RenderWidgetHost* widget_host) override;
+
+  // content::WebContentsObserver:
+  void RenderFrameHostChanged(content::RenderFrameHost* old_host,
+                              content::RenderFrameHost* new_host) override;
+  void RenderFrameDeleted(content::RenderFrameHost* deleted_host) override;
+  void WebContentsDestroyed() override;
+
+  content::RenderFrameHost* render_frame_host_;
+  content::WebContents* web_contents_;
+  scoped_refptr<content::FileSelectListener> listener_;
+  FileChooserParams::Mode mode_;
+
+  ScopedObserver<content::RenderWidgetHost, content::RenderWidgetHostObserver>
+      observer_{this};
+
+  // Temporary files only used on OSX. This class is responsible for deleting
+  // these files when they are no longer needed.
+  std::vector<base::FilePath> temporary_files_;
+
+  // DirectoryLister-specific members
+  std::unique_ptr<net::DirectoryLister> lister_;
+  base::FilePath lister_base_dir_;
+  std::vector<base::FilePath> lister_paths_;
+
+  base::WeakPtrFactory<FileSelectHelper> weak_ptr_factory_{this};
+};
+
+#endif  // SHELL_BROWSER_FILE_SELECT_HELPER_H_

+ 146 - 0
shell/browser/file_select_helper_mac.mm

@@ -0,0 +1,146 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "shell/browser/file_select_helper.h"
+
+#include <Cocoa/Cocoa.h>
+#include <sys/stat.h>
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/mac/foundation_util.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "third_party/zlib/google/zip.h"
+#include "ui/shell_dialogs/selected_file_info.h"
+
+namespace {
+
+// Given the |path| of a package, returns the destination that the package
+// should be zipped to. Returns an empty path on any errors.
+base::FilePath ZipDestination(const base::FilePath& path) {
+  base::FilePath dest;
+
+  if (!base::GetTempDir(&dest)) {
+    // Couldn't get the temporary directory.
+    return base::FilePath();
+  }
+
+  // TMPDIR/<bundleID>/zip_cache/<guid>
+
+  NSString* bundleID = [[NSBundle mainBundle] bundleIdentifier];
+  dest = dest.Append([bundleID fileSystemRepresentation]);
+
+  dest = dest.Append("zip_cache");
+
+  NSString* guid = [[NSProcessInfo processInfo] globallyUniqueString];
+  dest = dest.Append([guid fileSystemRepresentation]);
+
+  return dest;
+}
+
+// Returns the path of the package and its components relative to the package's
+// parent directory.
+std::vector<base::FilePath> RelativePathsForPackage(
+    const base::FilePath& package) {
+  // Get the base directory.
+  base::FilePath base_dir = package.DirName();
+
+  // Add the package as the first relative path.
+  std::vector<base::FilePath> relative_paths;
+  relative_paths.push_back(package.BaseName());
+
+  // Add the components of the package as relative paths.
+  base::FileEnumerator file_enumerator(
+      package, true /* recursive */,
+      base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
+  for (base::FilePath path = file_enumerator.Next(); !path.empty();
+       path = file_enumerator.Next()) {
+    base::FilePath relative_path;
+    bool success = base_dir.AppendRelativePath(path, &relative_path);
+    if (success)
+      relative_paths.push_back(relative_path);
+  }
+
+  return relative_paths;
+}
+
+}  // namespace
+
+base::FilePath FileSelectHelper::ZipPackage(const base::FilePath& path) {
+  base::FilePath dest(ZipDestination(path));
+  if (dest.empty())
+    return dest;
+
+  if (!base::CreateDirectory(dest.DirName()))
+    return base::FilePath();
+
+  base::File file(dest, base::File::FLAG_CREATE | base::File::FLAG_WRITE);
+  if (!file.IsValid())
+    return base::FilePath();
+
+  std::vector<base::FilePath> files_to_zip(RelativePathsForPackage(path));
+  base::FilePath base_dir = path.DirName();
+  bool success = zip::ZipFiles(base_dir, files_to_zip, file.GetPlatformFile());
+
+  int result = -1;
+  if (success)
+    result = fchmod(file.GetPlatformFile(), S_IRUSR);
+
+  return result >= 0 ? dest : base::FilePath();
+}
+
+void FileSelectHelper::ProcessSelectedFilesMac(
+    const std::vector<ui::SelectedFileInfo>& files) {
+  // Make a mutable copy of the input files.
+  std::vector<ui::SelectedFileInfo> files_out(files);
+  std::vector<base::FilePath> temporary_files;
+
+  for (auto& file_info : files_out) {
+    NSString* filename = base::mac::FilePathToNSString(file_info.local_path);
+    BOOL isPackage =
+        [[NSWorkspace sharedWorkspace] isFilePackageAtPath:filename];
+    if (isPackage && base::DirectoryExists(file_info.local_path)) {
+      base::FilePath result = ZipPackage(file_info.local_path);
+
+      if (!result.empty()) {
+        temporary_files.push_back(result);
+        file_info.local_path = result;
+        file_info.file_path = result;
+        file_info.display_name.append(".zip");
+      }
+    }
+  }
+
+  content::GetUIThreadTaskRunner({})->PostTask(
+      FROM_HERE,
+      base::BindOnce(&FileSelectHelper::ProcessSelectedFilesMacOnUIThread,
+                     base::Unretained(this), files_out, temporary_files));
+}
+
+void FileSelectHelper::ProcessSelectedFilesMacOnUIThread(
+    const std::vector<ui::SelectedFileInfo>& files,
+    const std::vector<base::FilePath>& temporary_files) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  if (!temporary_files.empty()) {
+    temporary_files_.insert(temporary_files_.end(), temporary_files.begin(),
+                            temporary_files.end());
+
+    // Typically, |temporary_files| are deleted after |web_contents_| is
+    // destroyed. If |web_contents_| is already NULL, then the temporary files
+    // need to be deleted now.
+    if (!web_contents_) {
+      DeleteTemporaryFiles();
+      RunFileChooserEnd();
+      return;
+    }
+  }
+
+  ConvertToFileChooserFileInfoList(files);
+}

+ 9 - 202
shell/browser/web_dialog_helper.cc

@@ -21,212 +21,19 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "gin/dictionary.h"
-#include "net/base/directory_lister.h"
 #include "net/base/mime_util.h"
 #include "shell/browser/electron_browser_context.h"
-#include "shell/browser/javascript_environment.h"
+#include "shell/browser/file_select_helper.h"
 #include "shell/browser/native_window.h"
 #include "shell/browser/ui/file_dialog.h"
-#include "shell/common/gin_converters/callback_converter.h"
-#include "shell/common/gin_converters/file_path_converter.h"
-#include "shell/common/gin_helper/dictionary.h"
-#include "ui/shell_dialogs/selected_file_info.h"
 
 using blink::mojom::FileChooserFileInfo;
 using blink::mojom::FileChooserFileInfoPtr;
 using blink::mojom::FileChooserParams;
+using blink::mojom::NativeFileInfo;
 
 namespace {
 
-class FileSelectHelper : public base::RefCounted<FileSelectHelper>,
-                         public content::WebContentsObserver,
-                         public net::DirectoryLister::DirectoryListerDelegate {
- public:
-  REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE();
-
-  FileSelectHelper(content::RenderFrameHost* render_frame_host,
-                   scoped_refptr<content::FileSelectListener> listener,
-                   blink::mojom::FileChooserParams::Mode mode)
-      : render_frame_host_(render_frame_host),
-        listener_(std::move(listener)),
-        mode_(mode) {
-    auto* web_contents =
-        content::WebContents::FromRenderFrameHost(render_frame_host);
-    content::WebContentsObserver::Observe(web_contents);
-  }
-
-  void ShowOpenDialog(const file_dialog::DialogSettings& settings) {
-    v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
-    v8::HandleScope scope(isolate);
-    gin_helper::Promise<gin_helper::Dictionary> promise(isolate);
-
-    auto callback = base::BindOnce(&FileSelectHelper::OnOpenDialogDone, this);
-    ignore_result(promise.Then(std::move(callback)));
-
-    file_dialog::ShowOpenDialog(settings, std::move(promise));
-  }
-
-  void ShowSaveDialog(const file_dialog::DialogSettings& settings) {
-    v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
-    v8::HandleScope scope(isolate);
-    gin_helper::Promise<gin_helper::Dictionary> promise(isolate);
-
-    auto callback = base::BindOnce(&FileSelectHelper::OnSaveDialogDone, this);
-    ignore_result(promise.Then(std::move(callback)));
-
-    file_dialog::ShowSaveDialog(settings, std::move(promise));
-  }
-
- private:
-  friend class base::RefCounted<FileSelectHelper>;
-
-  ~FileSelectHelper() override = default;
-
-  // net::DirectoryLister::DirectoryListerDelegate
-  void OnListFile(
-      const net::DirectoryLister::DirectoryListerData& data) override {
-    // We don't want to return directory paths, only file paths
-    if (data.info.IsDirectory())
-      return;
-
-    lister_paths_.push_back(data.path);
-  }
-
-  // net::DirectoryLister::DirectoryListerDelegate
-  void OnListDone(int error) override {
-    std::vector<FileChooserFileInfoPtr> file_info;
-    for (const auto& path : lister_paths_)
-      file_info.push_back(FileChooserFileInfo::NewNativeFile(
-          blink::mojom::NativeFileInfo::New(path, base::string16())));
-
-    OnFilesSelected(std::move(file_info), lister_base_dir_);
-    Release();
-  }
-
-  void EnumerateDirectory() {
-    // Ensure that this fn is only called once
-    DCHECK(!lister_);
-    DCHECK(!lister_base_dir_.empty());
-    DCHECK(lister_paths_.empty());
-
-    lister_ = std::make_unique<net::DirectoryLister>(
-        lister_base_dir_, net::DirectoryLister::NO_SORT_RECURSIVE, this);
-    lister_->Start();
-    // It is difficult for callers to know how long to keep a reference to
-    // this instance.  We AddRef() here to keep the instance alive after we
-    // return to the caller.  Once the directory lister is complete we
-    // Release() & at that point we run OnFilesSelected() which will
-    // deref the last reference held by the listener.
-    AddRef();
-  }
-
-  void OnOpenDialogDone(gin_helper::Dictionary result) {
-    std::vector<FileChooserFileInfoPtr> file_info;
-    bool canceled = true;
-    result.Get("canceled", &canceled);
-    // For certain file chooser modes (kUploadFolder) we need to do some async
-    // work before calling back to the listener.  In that particular case the
-    // listener is called from the directory enumerator.
-    bool ready_to_call_listener = false;
-
-    if (canceled) {
-      OnSelectionCancelled();
-    } else {
-      std::vector<base::FilePath> paths;
-      if (result.Get("filePaths", &paths)) {
-        // If we are uploading a folder we need to enumerate its contents
-        if (mode_ == FileChooserParams::Mode::kUploadFolder &&
-            paths.size() >= 1) {
-          lister_base_dir_ = paths[0];
-          EnumerateDirectory();
-        } else {
-          for (auto& path : paths) {
-            file_info.push_back(FileChooserFileInfo::NewNativeFile(
-                blink::mojom::NativeFileInfo::New(
-                    path, path.BaseName().AsUTF16Unsafe())));
-          }
-
-          ready_to_call_listener = true;
-        }
-
-        if (render_frame_host_ && !paths.empty()) {
-          auto* browser_context =
-              static_cast<electron::ElectronBrowserContext*>(
-                  render_frame_host_->GetProcess()->GetBrowserContext());
-          browser_context->prefs()->SetFilePath(prefs::kSelectFileLastDirectory,
-                                                paths[0].DirName());
-        }
-      }
-      // We should only call this if we have not cancelled the dialog
-      if (ready_to_call_listener)
-        OnFilesSelected(std::move(file_info), lister_base_dir_);
-    }
-  }
-
-  void OnSaveDialogDone(gin_helper::Dictionary result) {
-    std::vector<FileChooserFileInfoPtr> file_info;
-    bool canceled = true;
-    result.Get("canceled", &canceled);
-
-    if (canceled) {
-      OnSelectionCancelled();
-    } else {
-      base::FilePath path;
-      if (result.Get("filePath", &path)) {
-        file_info.push_back(FileChooserFileInfo::NewNativeFile(
-            blink::mojom::NativeFileInfo::New(
-                path, path.BaseName().AsUTF16Unsafe())));
-      }
-      // We should only call this if we have not cancelled the dialog
-      OnFilesSelected(std::move(file_info), base::FilePath());
-    }
-  }
-
-  void OnFilesSelected(std::vector<FileChooserFileInfoPtr> file_info,
-                       base::FilePath base_dir) {
-    if (listener_) {
-      listener_->FileSelected(std::move(file_info), base_dir, mode_);
-      listener_.reset();
-    }
-    render_frame_host_ = nullptr;
-  }
-
-  void OnSelectionCancelled() {
-    if (listener_) {
-      listener_->FileSelectionCanceled();
-      listener_.reset();
-    }
-    render_frame_host_ = nullptr;
-  }
-
-  // content::WebContentsObserver:
-  void RenderFrameHostChanged(content::RenderFrameHost* old_host,
-                              content::RenderFrameHost* new_host) override {
-    if (old_host == render_frame_host_)
-      render_frame_host_ = nullptr;
-  }
-
-  // content::WebContentsObserver:
-  void RenderFrameDeleted(content::RenderFrameHost* deleted_host) override {
-    if (deleted_host == render_frame_host_)
-      render_frame_host_ = nullptr;
-  }
-
-  // content::WebContentsObserver:
-  void WebContentsDestroyed() override { render_frame_host_ = nullptr; }
-
-  content::RenderFrameHost* render_frame_host_;
-  scoped_refptr<content::FileSelectListener> listener_;
-  blink::mojom::FileChooserParams::Mode mode_;
-
-  // DirectoryLister-specific members
-  std::unique_ptr<net::DirectoryLister> lister_;
-  base::FilePath lister_base_dir_;
-  std::vector<base::FilePath> lister_paths_;
-};
-
 file_dialog::Filters GetFileTypesFromAcceptType(
     const std::vector<base::string16>& accept_types) {
   file_dialog::Filters filters;
@@ -305,18 +112,19 @@ WebDialogHelper::~WebDialogHelper() = default;
 void WebDialogHelper::RunFileChooser(
     content::RenderFrameHost* render_frame_host,
     scoped_refptr<content::FileSelectListener> listener,
-    const blink::mojom::FileChooserParams& params) {
+    const FileChooserParams& params) {
   file_dialog::DialogSettings settings;
   settings.force_detached = offscreen_;
   settings.filters = GetFileTypesFromAcceptType(params.accept_types);
   settings.parent_window = window_;
   settings.title = base::UTF16ToUTF8(params.title);
 
-  auto file_select_helper = base::MakeRefCounted<FileSelectHelper>(
-      render_frame_host, std::move(listener), params.mode);
+  auto* fsc =
+      new FileSelectHelper(render_frame_host, std::move(listener), params.mode);
+
   if (params.mode == FileChooserParams::Mode::kSave) {
     settings.default_path = params.default_file_name;
-    file_select_helper->ShowSaveDialog(settings);
+    fsc->ShowSaveDialog(settings);
   } else {
     int flags = file_dialog::OPEN_DIALOG_CREATE_DIRECTORY;
     switch (params.mode) {
@@ -325,7 +133,6 @@ void WebDialogHelper::RunFileChooser(
         FALLTHROUGH;
       case FileChooserParams::Mode::kOpen:
         flags |= file_dialog::OPEN_DIALOG_OPEN_FILE;
-        flags |= file_dialog::OPEN_DIALOG_TREAT_PACKAGE_APP_AS_DIRECTORY;
         break;
       case FileChooserParams::Mode::kUploadFolder:
         flags |= file_dialog::OPEN_DIALOG_OPEN_DIRECTORY;
@@ -340,7 +147,7 @@ void WebDialogHelper::RunFileChooser(
                                 ->GetFilePath(prefs::kSelectFileLastDirectory)
                                 .Append(params.default_file_name);
     settings.properties = flags;
-    file_select_helper->ShowOpenDialog(settings);
+    fsc->ShowOpenDialog(settings);
   }
 }
 
@@ -356,7 +163,7 @@ void WebDialogHelper::EnumerateDirectory(
   std::vector<FileChooserFileInfoPtr> file_info;
   while (!(path = file_enum.Next()).empty()) {
     file_info.push_back(FileChooserFileInfo::NewNativeFile(
-        blink::mojom::NativeFileInfo::New(path, base::string16())));
+        NativeFileInfo::New(path, base::string16())));
   }
 
   listener->FileSelected(std::move(file_info), dir,