1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef EXTENSIONS_BROWSER_API_FILE_SYSTEM_FILE_SYSTEM_API_H_
6 #define EXTENSIONS_BROWSER_API_FILE_SYSTEM_FILE_SYSTEM_API_H_
7 
8 #include <memory>
9 #include <string>
10 #include <vector>
11 
12 #include "base/files/file.h"
13 #include "base/files/file_path.h"
14 #include "base/macros.h"
15 #include "base/values.h"
16 #include "build/build_config.h"
17 #include "extensions/browser/extension_function.h"
18 #include "extensions/common/api/file_system.h"
19 #include "ui/shell_dialogs/select_file_dialog.h"
20 
21 namespace content {
22 class WebContents;
23 }  // namespace content
24 
25 namespace extensions {
26 class ExtensionPrefs;
27 
28 namespace file_system_api {
29 
30 // Methods to get and set the path of the directory containing the last file
31 // chosen by the user in response to a chrome.fileSystem.chooseEntry() call for
32 // the given extension.
33 
34 // Returns an empty path on failure.
35 base::FilePath GetLastChooseEntryDirectory(const ExtensionPrefs* prefs,
36                                            const std::string& extension_id);
37 
38 void SetLastChooseEntryDirectory(ExtensionPrefs* prefs,
39                                  const std::string& extension_id,
40                                  const base::FilePath& path);
41 
42 }  // namespace file_system_api
43 
44 class FileSystemGetDisplayPathFunction : public ExtensionFunction {
45  public:
46   DECLARE_EXTENSION_FUNCTION("fileSystem.getDisplayPath",
47                              FILESYSTEM_GETDISPLAYPATH)
48 
49  protected:
~FileSystemGetDisplayPathFunction()50   ~FileSystemGetDisplayPathFunction() override {}
51   ResponseAction Run() override;
52 };
53 
54 class FileSystemEntryFunction : public ExtensionFunction {
55  protected:
56   FileSystemEntryFunction();
57 
~FileSystemEntryFunction()58   ~FileSystemEntryFunction() override {}
59 
60   // This is called when writable file entries are being returned. The function
61   // will ensure the files exist, creating them if necessary, and also check
62   // that none of the files are links. If it succeeds it proceeds to
63   // RegisterFileSystemsAndSendResponse, otherwise to HandleWritableFileError.
64   void PrepareFilesForWritableApp(const std::vector<base::FilePath>& path);
65 
66   // This will finish the choose file process. This is either called directly
67   // from FilesSelected, or from WritableFileChecker. It is called on the UI
68   // thread.
69   void RegisterFileSystemsAndSendResponse(
70       const std::vector<base::FilePath>& path);
71 
72   // Creates a result dictionary.
73   std::unique_ptr<base::DictionaryValue> CreateResult();
74 
75   // Adds an entry to the result dictionary.
76   void AddEntryToResult(const base::FilePath& path,
77                         const std::string& id_override,
78                         base::DictionaryValue* result);
79 
80   // called on the UI thread if there is a problem checking a writable file.
81   void HandleWritableFileError(const base::FilePath& error_path);
82 
83   // Whether multiple entries have been requested.
84   bool multiple_;
85 
86   // Whether a directory has been requested.
87   bool is_directory_;
88 };
89 
90 class FileSystemGetWritableEntryFunction : public FileSystemEntryFunction {
91  public:
92   DECLARE_EXTENSION_FUNCTION("fileSystem.getWritableEntry",
93                              FILESYSTEM_GETWRITABLEENTRY)
94 
95  protected:
~FileSystemGetWritableEntryFunction()96   ~FileSystemGetWritableEntryFunction() override {}
97   ResponseAction Run() override;
98 
99  private:
100   void CheckPermissionAndSendResponse();
101   void SetIsDirectoryAsync();
102 
103   // The path to the file for which a writable entry has been requested.
104   base::FilePath path_;
105 };
106 
107 class FileSystemIsWritableEntryFunction : public ExtensionFunction {
108  public:
109   DECLARE_EXTENSION_FUNCTION("fileSystem.isWritableEntry",
110                              FILESYSTEM_ISWRITABLEENTRY)
111 
112  protected:
~FileSystemIsWritableEntryFunction()113   ~FileSystemIsWritableEntryFunction() override {}
114   ResponseAction Run() override;
115 };
116 
117 class FileSystemChooseEntryFunction : public FileSystemEntryFunction {
118  public:
119   // Allow picker UI to be skipped in testing.
120   static void SkipPickerAndAlwaysSelectPathForTest(base::FilePath* path);
121   static void SkipPickerAndAlwaysSelectPathsForTest(
122       std::vector<base::FilePath>* paths);
123   static void SkipPickerAndSelectSuggestedPathForTest();
124   static void SkipPickerAndAlwaysCancelForTest();
125   static void StopSkippingPickerForTest();
126   // Allow directory access confirmation UI to be skipped in testing.
127   static void SkipDirectoryConfirmationForTest();
128   static void AutoCancelDirectoryConfirmationForTest();
129   static void StopSkippingDirectoryConfirmationForTest();
130   // Call this with the directory for test file paths. On Chrome OS, accessed
131   // path needs to be explicitly registered for smooth integration with Google
132   // Drive support.
133   static void RegisterTempExternalFileSystemForTest(const std::string& name,
134                                                     const base::FilePath& path);
135   DECLARE_EXTENSION_FUNCTION("fileSystem.chooseEntry", FILESYSTEM_CHOOSEENTRY)
136 
137   typedef std::vector<api::file_system::AcceptOption> AcceptOptions;
138 
139   static void BuildFileTypeInfo(
140       ui::SelectFileDialog::FileTypeInfo* file_type_info,
141       const base::FilePath::StringType& suggested_extension,
142       const AcceptOptions* accepts,
143       const bool* acceptsAllTypes);
144   static void BuildSuggestion(const std::string* opt_name,
145                               base::FilePath* suggested_name,
146                               base::FilePath::StringType* suggested_extension);
147 
148  protected:
~FileSystemChooseEntryFunction()149   ~FileSystemChooseEntryFunction() override {}
150   ResponseAction Run() override;
151   void ShowPicker(const ui::SelectFileDialog::FileTypeInfo& file_type_info,
152                   ui::SelectFileDialog::Type picker_type);
153 
154  private:
155   void SetInitialPathAndShowPicker(
156       const base::FilePath& previous_path,
157       const base::FilePath& suggested_name,
158       const ui::SelectFileDialog::FileTypeInfo& file_type_info,
159       ui::SelectFileDialog::Type picker_type,
160       bool is_path_non_native_directory);
161 
162   // FilesSelected and FileSelectionCanceled are called by the file picker.
163   void FilesSelected(const std::vector<base::FilePath>& paths);
164   void FileSelectionCanceled();
165 
166   // Check if the chosen directory is or is an ancestor of a sensitive
167   // directory. If so, calls ConfirmSensitiveDirectoryAccess. Otherwise, calls
168   // OnDirectoryAccessConfirmed.
169   void ConfirmDirectoryAccessAsync(bool non_native_path,
170                                    const std::vector<base::FilePath>& paths,
171                                    content::WebContents* web_contents);
172 
173   // Shows a dialog to confirm whether the user wants to open the directory.
174   // Calls OnDirectoryAccessConfirmed or FileSelectionCanceled.
175   void ConfirmSensitiveDirectoryAccess(const std::vector<base::FilePath>& paths,
176                                        content::WebContents* web_contents);
177 
178   void OnDirectoryAccessConfirmed(const std::vector<base::FilePath>& paths);
179 
180   base::FilePath initial_path_;
181 };
182 
183 class FileSystemRetainEntryFunction : public ExtensionFunction {
184  public:
185   DECLARE_EXTENSION_FUNCTION("fileSystem.retainEntry", FILESYSTEM_RETAINENTRY)
186 
187  protected:
~FileSystemRetainEntryFunction()188   ~FileSystemRetainEntryFunction() override {}
189   ResponseAction Run() override;
190 
191  private:
192   // Retains the file entry referenced by |entry_id| in apps::SavedFilesService.
193   // |entry_id| must refer to an entry in an isolated file system.  |path| is a
194   // path of the entry.  |file_info| is base::File::Info of the entry if it can
195   // be obtained.
196   void RetainFileEntry(const std::string& entry_id,
197                        const base::FilePath& path,
198                        std::unique_ptr<base::File::Info> file_info);
199 };
200 
201 class FileSystemIsRestorableFunction : public ExtensionFunction {
202  public:
203   DECLARE_EXTENSION_FUNCTION("fileSystem.isRestorable", FILESYSTEM_ISRESTORABLE)
204 
205  protected:
~FileSystemIsRestorableFunction()206   ~FileSystemIsRestorableFunction() override {}
207   ResponseAction Run() override;
208 };
209 
210 class FileSystemRestoreEntryFunction : public FileSystemEntryFunction {
211  public:
212   DECLARE_EXTENSION_FUNCTION("fileSystem.restoreEntry", FILESYSTEM_RESTOREENTRY)
213 
214  protected:
~FileSystemRestoreEntryFunction()215   ~FileSystemRestoreEntryFunction() override {}
216   ResponseAction Run() override;
217 };
218 
219 #if !defined(OS_CHROMEOS)
220 // Stub for non Chrome OS operating systems.
221 class FileSystemRequestFileSystemFunction : public ExtensionFunction {
222  public:
223   DECLARE_EXTENSION_FUNCTION("fileSystem.requestFileSystem",
224                              FILESYSTEM_REQUESTFILESYSTEM)
225 
226  protected:
~FileSystemRequestFileSystemFunction()227   ~FileSystemRequestFileSystemFunction() override {}
228 
229   // ExtensionFunction overrides.
230   ExtensionFunction::ResponseAction Run() override;
231 };
232 
233 // Stub for non Chrome OS operating systems.
234 class FileSystemGetVolumeListFunction : public ExtensionFunction {
235  public:
236   DECLARE_EXTENSION_FUNCTION("fileSystem.getVolumeList",
237                              FILESYSTEM_GETVOLUMELIST)
238 
239  protected:
~FileSystemGetVolumeListFunction()240   ~FileSystemGetVolumeListFunction() override {}
241 
242   // ExtensionFunction overrides.
243   ExtensionFunction::ResponseAction Run() override;
244 };
245 
246 #else
247 // Requests a file system for the specified volume id.
248 class FileSystemRequestFileSystemFunction : public ExtensionFunction {
249  public:
250   DECLARE_EXTENSION_FUNCTION("fileSystem.requestFileSystem",
251                              FILESYSTEM_REQUESTFILESYSTEM)
252   FileSystemRequestFileSystemFunction();
253 
254  protected:
255   ~FileSystemRequestFileSystemFunction() override;
256 
257   // ExtensionFunction overrides.
258   ExtensionFunction::ResponseAction Run() override;
259 
260  private:
261   // Called when a user grants or rejects permissions for the file system
262   // access.
263   void OnGotFileSystem(const std::string& id, const std::string& path);
264   void OnError(const std::string& error);
265 };
266 
267 // Requests a list of available volumes.
268 class FileSystemGetVolumeListFunction : public ExtensionFunction {
269  public:
270   DECLARE_EXTENSION_FUNCTION("fileSystem.getVolumeList",
271                              FILESYSTEM_GETVOLUMELIST)
272   FileSystemGetVolumeListFunction();
273 
274  protected:
275   ~FileSystemGetVolumeListFunction() override;
276 
277   // ExtensionFunction overrides.
278   ExtensionFunction::ResponseAction Run() override;
279 
280  private:
281   void OnGotVolumeList(const std::vector<api::file_system::Volume>& volumes);
282   void OnError(const std::string& error);
283 };
284 #endif
285 
286 }  // namespace extensions
287 
288 #endif  // EXTENSIONS_BROWSER_API_FILE_SYSTEM_FILE_SYSTEM_API_H_
289