1 // Copyright (c) 2012 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.
5 #ifndef CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_FILE_SYSTEM_API_H_
6 #define CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_FILE_SYSTEM_API_H_
11 #include "base/files/file.h"
12 #include "base/files/file_path.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/memory/weak_ptr.h"
15 #include "chrome/browser/extensions/chrome_extension_function.h"
16 #include "chrome/browser/extensions/chrome_extension_function_details.h"
17 #include "chrome/common/extensions/api/file_system.h"
18 #include "extensions/browser/extension_function.h"
19 #include "ui/base/ui_base_types.h"
20 #include "ui/shell_dialogs/select_file_dialog.h"
22 #if defined(OS_CHROMEOS)
23 namespace file_manager
{
25 } // namespace file_manager
28 namespace extensions
{
30 class ScopedSkipRequestFileSystemDialog
;
32 namespace file_system_api
{
34 // Methods to get and set the path of the directory containing the last file
35 // chosen by the user in response to a chrome.fileSystem.chooseEntry() call for
36 // the given extension.
38 // Returns an empty path on failure.
39 base::FilePath
GetLastChooseEntryDirectory(const ExtensionPrefs
* prefs
,
40 const std::string
& extension_id
);
42 void SetLastChooseEntryDirectory(ExtensionPrefs
* prefs
,
43 const std::string
& extension_id
,
44 const base::FilePath
& path
);
46 std::vector
<base::FilePath
> GetGrayListedDirectories();
48 #if defined(OS_CHROMEOS)
49 // Dispatches an event about a mounted on unmounted volume in the system to
50 // each extension which can request it.
51 void DispatchVolumeListChangeEvent(Profile
* profile
);
53 // Requests consent for the chrome.fileSystem.requestFileSystem() method.
54 // Interaction with UI and environmental checks (kiosk mode, whitelist) are
55 // provided by a delegate: ConsentProviderDelegate. For testing, it is
56 // TestingConsentProviderDelegate.
57 class ConsentProvider
{
59 enum Consent
{ CONSENT_GRANTED
, CONSENT_REJECTED
, CONSENT_IMPOSSIBLE
};
60 typedef base::Callback
<void(Consent
)> ConsentCallback
;
61 typedef base::Callback
<void(ui::DialogButton
)> ShowDialogCallback
;
63 // Interface for delegating user interaction for granting permissions.
64 class DelegateInterface
{
66 // Shows a dialog for granting permissions.
67 virtual void ShowDialog(const Extension
& extension
,
68 const base::WeakPtr
<file_manager::Volume
>& volume
,
70 const ShowDialogCallback
& callback
) = 0;
72 // Shows a notification about permissions automatically granted access.
73 virtual void ShowNotification(
74 const Extension
& extension
,
75 const base::WeakPtr
<file_manager::Volume
>& volume
,
78 // Checks if the extension was launched in auto-launch kiosk mode.
79 virtual bool IsAutoLaunched(const Extension
& extension
) = 0;
81 // Checks if the extension is a whitelisted component extension or app.
82 virtual bool IsWhitelistedComponent(const Extension
& extension
) = 0;
85 explicit ConsentProvider(DelegateInterface
* delegate
);
88 // Requests consent for granting |writable| permissions to the |volume|
89 // volume by the |extension|. Must be called only if the extension is
90 // grantable, which can be checked with IsGrantable().
91 void RequestConsent(const Extension
& extension
,
92 const base::WeakPtr
<file_manager::Volume
>& volume
,
94 const ConsentCallback
& callback
);
96 // Checks whether the |extension| can be granted access.
97 bool IsGrantable(const Extension
& extension
);
100 DelegateInterface
* const delegate_
;
102 // Converts the clicked button to a consent result and passes it via the
104 void DialogResultToConsent(const ConsentCallback
& callback
,
105 ui::DialogButton button
);
107 DISALLOW_COPY_AND_ASSIGN(ConsentProvider
);
110 // Handles interaction with user as well as environment checks (whitelists,
111 // context of running extensions) for ConsentProvider.
112 class ConsentProviderDelegate
: public ConsentProvider::DelegateInterface
{
114 ConsentProviderDelegate(Profile
* profile
, content::RenderFrameHost
* host
);
115 ~ConsentProviderDelegate();
118 friend ScopedSkipRequestFileSystemDialog
;
120 // Sets a fake result for the user consent dialog. If ui::DIALOG_BUTTON_NONE
122 static void SetAutoDialogButtonForTest(ui::DialogButton button
);
124 // ConsentProvider::DelegateInterface overrides:
125 void ShowDialog(const Extension
& extension
,
126 const base::WeakPtr
<file_manager::Volume
>& volume
,
128 const file_system_api::ConsentProvider::ShowDialogCallback
&
130 void ShowNotification(const Extension
& extension
,
131 const base::WeakPtr
<file_manager::Volume
>& volume
,
132 bool writable
) override
;
133 bool IsAutoLaunched(const Extension
& extension
) override
;
134 bool IsWhitelistedComponent(const Extension
& extension
) override
;
136 Profile
* const profile_
;
137 content::RenderFrameHost
* const host_
;
139 DISALLOW_COPY_AND_ASSIGN(ConsentProviderDelegate
);
143 } // namespace file_system_api
145 class FileSystemGetDisplayPathFunction
: public ChromeSyncExtensionFunction
{
147 DECLARE_EXTENSION_FUNCTION("fileSystem.getDisplayPath",
148 FILESYSTEM_GETDISPLAYPATH
)
151 ~FileSystemGetDisplayPathFunction() override
{}
152 bool RunSync() override
;
155 class FileSystemEntryFunction
: public ChromeAsyncExtensionFunction
{
157 FileSystemEntryFunction();
159 ~FileSystemEntryFunction() override
{}
161 // This is called when writable file entries are being returned. The function
162 // will ensure the files exist, creating them if necessary, and also check
163 // that none of the files are links. If it succeeds it proceeds to
164 // RegisterFileSystemsAndSendResponse, otherwise to HandleWritableFileError.
165 void PrepareFilesForWritableApp(const std::vector
<base::FilePath
>& path
);
167 // This will finish the choose file process. This is either called directly
168 // from FilesSelected, or from WritableFileChecker. It is called on the UI
170 void RegisterFileSystemsAndSendResponse(
171 const std::vector
<base::FilePath
>& path
);
173 // Creates a response dictionary and sets it as the response to be sent.
174 void CreateResponse();
176 // Adds an entry to the response dictionary.
177 void AddEntryToResponse(const base::FilePath
& path
,
178 const std::string
& id_override
);
180 // called on the UI thread if there is a problem checking a writable file.
181 void HandleWritableFileError(const base::FilePath
& error_path
);
183 // Whether multiple entries have been requested.
186 // Whether a directory has been requested.
189 // The dictionary to send as the response.
190 base::DictionaryValue
* response_
;
193 class FileSystemGetWritableEntryFunction
: public FileSystemEntryFunction
{
195 DECLARE_EXTENSION_FUNCTION("fileSystem.getWritableEntry",
196 FILESYSTEM_GETWRITABLEENTRY
)
199 ~FileSystemGetWritableEntryFunction() override
{}
200 bool RunAsync() override
;
203 void CheckPermissionAndSendResponse();
204 void SetIsDirectoryOnFileThread();
206 // The path to the file for which a writable entry has been requested.
207 base::FilePath path_
;
210 class FileSystemIsWritableEntryFunction
: public ChromeSyncExtensionFunction
{
212 DECLARE_EXTENSION_FUNCTION("fileSystem.isWritableEntry",
213 FILESYSTEM_ISWRITABLEENTRY
)
216 ~FileSystemIsWritableEntryFunction() override
{}
217 bool RunSync() override
;
220 class FileSystemChooseEntryFunction
: public FileSystemEntryFunction
{
222 // Allow picker UI to be skipped in testing.
223 static void SkipPickerAndAlwaysSelectPathForTest(base::FilePath
* path
);
224 static void SkipPickerAndAlwaysSelectPathsForTest(
225 std::vector
<base::FilePath
>* paths
);
226 static void SkipPickerAndSelectSuggestedPathForTest();
227 static void SkipPickerAndAlwaysCancelForTest();
228 static void StopSkippingPickerForTest();
229 // Allow directory access confirmation UI to be skipped in testing.
230 static void SkipDirectoryConfirmationForTest();
231 static void AutoCancelDirectoryConfirmationForTest();
232 static void StopSkippingDirectoryConfirmationForTest();
233 // Call this with the directory for test file paths. On Chrome OS, accessed
234 // path needs to be explicitly registered for smooth integration with Google
236 static void RegisterTempExternalFileSystemForTest(const std::string
& name
,
237 const base::FilePath
& path
);
238 DECLARE_EXTENSION_FUNCTION("fileSystem.chooseEntry", FILESYSTEM_CHOOSEENTRY
)
240 typedef std::vector
<linked_ptr
<api::file_system::AcceptOption
>> AcceptOptions
;
242 static void BuildFileTypeInfo(
243 ui::SelectFileDialog::FileTypeInfo
* file_type_info
,
244 const base::FilePath::StringType
& suggested_extension
,
245 const AcceptOptions
* accepts
,
246 const bool* acceptsAllTypes
);
247 static void BuildSuggestion(const std::string
* opt_name
,
248 base::FilePath
* suggested_name
,
249 base::FilePath::StringType
* suggested_extension
);
254 ~FileSystemChooseEntryFunction() override
{}
255 bool RunAsync() override
;
256 void ShowPicker(const ui::SelectFileDialog::FileTypeInfo
& file_type_info
,
257 ui::SelectFileDialog::Type picker_type
);
260 void SetInitialPathOnFileThread(const base::FilePath
& suggested_name
,
261 const base::FilePath
& previous_path
);
263 // FilesSelected and FileSelectionCanceled are called by the file picker.
264 void FilesSelected(const std::vector
<base::FilePath
>& path
);
265 void FileSelectionCanceled();
267 // Check if the chosen directory is or is an ancestor of a sensitive
268 // directory. If so, show a dialog to confirm that the user wants to open the
269 // directory. Calls OnDirectoryAccessConfirmed if the directory isn't
270 // sensitive or the user chooses to open it. Otherwise, calls
271 // FileSelectionCanceled.
272 void ConfirmDirectoryAccessOnFileThread(
273 bool non_native_path
,
274 const std::vector
<base::FilePath
>& paths
,
275 content::WebContents
* web_contents
);
276 void OnDirectoryAccessConfirmed(const std::vector
<base::FilePath
>& paths
);
278 base::FilePath initial_path_
;
281 class FileSystemRetainEntryFunction
: public ChromeAsyncExtensionFunction
{
283 DECLARE_EXTENSION_FUNCTION("fileSystem.retainEntry", FILESYSTEM_RETAINENTRY
)
286 ~FileSystemRetainEntryFunction() override
{}
287 bool RunAsync() override
;
290 // Retains the file entry referenced by |entry_id| in apps::SavedFilesService.
291 // |entry_id| must refer to an entry in an isolated file system. |path| is a
292 // path of the entry. |file_info| is base::File::Info of the entry if it can
294 void RetainFileEntry(const std::string
& entry_id
,
295 const base::FilePath
& path
,
296 scoped_ptr
<base::File::Info
> file_info
);
299 class FileSystemIsRestorableFunction
: public ChromeSyncExtensionFunction
{
301 DECLARE_EXTENSION_FUNCTION("fileSystem.isRestorable", FILESYSTEM_ISRESTORABLE
)
304 ~FileSystemIsRestorableFunction() override
{}
305 bool RunSync() override
;
308 class FileSystemRestoreEntryFunction
: public FileSystemEntryFunction
{
310 DECLARE_EXTENSION_FUNCTION("fileSystem.restoreEntry", FILESYSTEM_RESTOREENTRY
)
313 ~FileSystemRestoreEntryFunction() override
{}
314 bool RunAsync() override
;
317 class FileSystemObserveDirectoryFunction
: public ChromeSyncExtensionFunction
{
319 DECLARE_EXTENSION_FUNCTION("fileSystem.observeDirectory",
320 FILESYSTEM_OBSERVEDIRECTORY
)
323 ~FileSystemObserveDirectoryFunction() override
{}
324 bool RunSync() override
;
327 class FileSystemUnobserveEntryFunction
: public ChromeSyncExtensionFunction
{
329 DECLARE_EXTENSION_FUNCTION("fileSystem.unobserveEntry",
330 FILESYSTEM_UNOBSERVEENTRY
)
333 ~FileSystemUnobserveEntryFunction() override
{}
334 bool RunSync() override
;
337 class FileSystemGetObservedEntriesFunction
338 : public ChromeSyncExtensionFunction
{
340 DECLARE_EXTENSION_FUNCTION("fileSystem.getObservedEntries",
341 FILESYSTEM_GETOBSERVEDENTRIES
);
344 ~FileSystemGetObservedEntriesFunction() override
{}
345 bool RunSync() override
;
348 #if !defined(OS_CHROMEOS)
349 // Stub for non Chrome OS operating systems.
350 class FileSystemRequestFileSystemFunction
: public UIThreadExtensionFunction
{
352 DECLARE_EXTENSION_FUNCTION("fileSystem.requestFileSystem",
353 FILESYSTEM_REQUESTFILESYSTEM
);
356 ~FileSystemRequestFileSystemFunction() override
{}
358 // UIThreadExtensionFunction overrides.
359 ExtensionFunction::ResponseAction
Run() override
;
362 // Stub for non Chrome OS operating systems.
363 class FileSystemGetVolumeListFunction
: public UIThreadExtensionFunction
{
365 DECLARE_EXTENSION_FUNCTION("fileSystem.getVolumeList",
366 FILESYSTEM_GETVOLUMELIST
);
369 ~FileSystemGetVolumeListFunction() override
{}
371 // UIThreadExtensionFunction overrides.
372 ExtensionFunction::ResponseAction
Run() override
;
376 // Requests a file system for the specified volume id.
377 class FileSystemRequestFileSystemFunction
: public UIThreadExtensionFunction
{
379 DECLARE_EXTENSION_FUNCTION("fileSystem.requestFileSystem",
380 FILESYSTEM_REQUESTFILESYSTEM
)
381 FileSystemRequestFileSystemFunction();
384 ~FileSystemRequestFileSystemFunction() override
;
386 // UIThreadExtensionFunction overrides.
387 ExtensionFunction::ResponseAction
Run() override
;
390 // Called when a user grants or rejects permissions for the file system
392 void OnConsentReceived(const base::WeakPtr
<file_manager::Volume
>& volume
,
394 file_system_api::ConsentProvider::Consent result
);
396 ChromeExtensionFunctionDetails chrome_details_
;
399 // Requests a list of available volumes.
400 class FileSystemGetVolumeListFunction
: public UIThreadExtensionFunction
{
402 DECLARE_EXTENSION_FUNCTION("fileSystem.getVolumeList",
403 FILESYSTEM_GETVOLUMELIST
);
404 FileSystemGetVolumeListFunction();
407 ~FileSystemGetVolumeListFunction() override
;
409 // UIThreadExtensionFunction overrides.
410 ExtensionFunction::ResponseAction
Run() override
;
413 ChromeExtensionFunctionDetails chrome_details_
;
417 } // namespace extensions
419 #endif // CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_FILE_SYSTEM_API_H_