1 // Copyright 2019 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 CONTENT_BROWSER_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_MANAGER_IMPL_H_
6 #define CONTENT_BROWSER_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_MANAGER_IMPL_H_
7 
8 #include "base/files/file_path.h"
9 #include "base/memory/weak_ptr.h"
10 #include "base/threading/sequence_bound.h"
11 #include "components/services/storage/public/mojom/native_file_system_context.mojom.h"
12 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
13 #include "content/browser/native_file_system/file_system_chooser.h"
14 #include "content/common/content_export.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/browser/native_file_system_entry_factory.h"
17 #include "content/public/browser/native_file_system_permission_context.h"
18 #include "mojo/public/cpp/bindings/pending_receiver.h"
19 #include "mojo/public/cpp/bindings/pending_remote.h"
20 #include "mojo/public/cpp/bindings/receiver_set.h"
21 #include "mojo/public/cpp/bindings/remote.h"
22 #include "mojo/public/cpp/bindings/unique_receiver_set.h"
23 #include "storage/browser/file_system/file_system_url.h"
24 #include "third_party/blink/public/mojom/native_file_system/native_file_system_file_writer.mojom.h"
25 #include "third_party/blink/public/mojom/native_file_system/native_file_system_manager.mojom.h"
26 #include "third_party/blink/public/mojom/permissions/permission_status.mojom.h"
27 
28 namespace storage {
29 class FileSystemContext;
30 class FileSystemOperationRunner;
31 }  // namespace storage
32 
33 namespace content {
34 class NativeFileSystemFileHandleImpl;
35 class NativeFileSystemDirectoryHandleImpl;
36 class NativeFileSystemTransferTokenImpl;
37 class StoragePartitionImpl;
38 
39 // This is the browser side implementation of the
40 // NativeFileSystemManager mojom interface. This is the main entry point for
41 // the native file system API in the browser process.Instances of this class are
42 // owned by StoragePartitionImpl.
43 //
44 // This class owns all the NativeFileSystemFileHandleImpl,
45 // NativeFileSystemDirectoryHandleImpl and NativeFileSystemTransferTokenImpl
46 // instances for a specific storage partition.
47 //
48 // This class is not thread safe, it must be constructed and used on the UI
49 // thread only.
50 class CONTENT_EXPORT NativeFileSystemManagerImpl
51     : public NativeFileSystemEntryFactory,
52       public blink::mojom::NativeFileSystemManager,
53       public storage::mojom::NativeFileSystemContext {
54  public:
55   using BindingContext = NativeFileSystemEntryFactory::BindingContext;
56 
57   // State that is shared between handles that are derived from each other.
58   // Handles that are created through ChooseEntries or GetSandboxedFileSystem
59   // get new values for these properties, while any handles derived from those
60   // (i.e. children of a directory) will inherit these properties from their
61   // parent.
62   struct CONTENT_EXPORT SharedHandleState {
63     SharedHandleState(
64         scoped_refptr<NativeFileSystemPermissionGrant> read_grant,
65         scoped_refptr<NativeFileSystemPermissionGrant> write_grant,
66         storage::IsolatedContext::ScopedFSHandle file_system);
67     SharedHandleState(const SharedHandleState& other);
68     ~SharedHandleState();
69 
70     // Should never be null. These are the read and write permissions for this
71     // handle.
72     const scoped_refptr<NativeFileSystemPermissionGrant> read_grant;
73     const scoped_refptr<NativeFileSystemPermissionGrant> write_grant;
74     // Can be empty, if this handle is not backed by an isolated file system.
75     const storage::IsolatedContext::ScopedFSHandle file_system;
76   };
77 
78   // The caller is responsible for ensuring that |permission_context| outlives
79   // this instance.
80   NativeFileSystemManagerImpl(
81       scoped_refptr<storage::FileSystemContext> context,
82       scoped_refptr<ChromeBlobStorageContext> blob_context,
83       NativeFileSystemPermissionContext* permission_context,
84       bool off_the_record);
85 
86   void BindReceiver(
87       const BindingContext& binding_context,
88       mojo::PendingReceiver<blink::mojom::NativeFileSystemManager> receiver);
89 
90   void BindInternalsReceiver(
91       mojo::PendingReceiver<storage::mojom::NativeFileSystemContext> receiver);
92 
93   // blink::mojom::NativeFileSystemManager:
94   void GetSandboxedFileSystem(GetSandboxedFileSystemCallback callback) override;
95   void ChooseEntries(
96       blink::mojom::ChooseFileSystemEntryType type,
97       std::vector<blink::mojom::ChooseFileSystemEntryAcceptsOptionPtr> accepts,
98       bool include_accepts_all,
99       ChooseEntriesCallback callback) override;
100   void GetFileHandleFromToken(
101       mojo::PendingRemote<blink::mojom::NativeFileSystemTransferToken> token,
102       mojo::PendingReceiver<blink::mojom::NativeFileSystemFileHandle>
103           file_handle_receiver) override;
104   void GetDirectoryHandleFromToken(
105       mojo::PendingRemote<blink::mojom::NativeFileSystemTransferToken> token,
106       mojo::PendingReceiver<blink::mojom::NativeFileSystemDirectoryHandle>
107           directory_handle_receiver) override;
108 
109   // storage::mojom::NativeFileSystemContext:
110   void SerializeHandle(
111       mojo::PendingRemote<blink::mojom::NativeFileSystemTransferToken> token,
112       SerializeHandleCallback callback) override;
113   void DeserializeHandle(
114       const url::Origin& origin,
115       const std::vector<uint8_t>& bits,
116       mojo::PendingReceiver<blink::mojom::NativeFileSystemTransferToken> token)
117       override;
118 
119   // NativeFileSystemEntryFactory:
120   blink::mojom::NativeFileSystemEntryPtr CreateFileEntryFromPath(
121       const BindingContext& binding_context,
122       const base::FilePath& file_path) override;
123   blink::mojom::NativeFileSystemEntryPtr CreateDirectoryEntryFromPath(
124       const BindingContext& binding_context,
125       const base::FilePath& directory_path) override;
126 
127   // Same as CreateFileEntryFromPath, except informs the permission context that
128   // the returned entry should be writable, because this entry was the result of
129   // a "save" operation.
130   blink::mojom::NativeFileSystemEntryPtr CreateWritableFileEntryFromPath(
131       const BindingContext& binding_context,
132       const base::FilePath& file_path);
133 
134   // Creates a new NativeFileSystemFileHandleImpl for a given url. Assumes the
135   // passed in URL is valid and represents a file.
136   mojo::PendingRemote<blink::mojom::NativeFileSystemFileHandle>
137   CreateFileHandle(const BindingContext& binding_context,
138                    const storage::FileSystemURL& url,
139                    const SharedHandleState& handle_state);
140 
141   // Creates a new NativeFileSystemDirectoryHandleImpl for a given url. Assumes
142   // the passed in URL is valid and represents a directory.
143   mojo::PendingRemote<blink::mojom::NativeFileSystemDirectoryHandle>
144   CreateDirectoryHandle(const BindingContext& context,
145                         const storage::FileSystemURL& url,
146                         const SharedHandleState& handle_state);
147 
148   // Creates a new NativeFileSystemFileWriterImpl for a given target and
149   // swap file URLs. Assumes the passed in URLs are valid and represent files.
150   mojo::PendingRemote<blink::mojom::NativeFileSystemFileWriter>
151   CreateFileWriter(const BindingContext& binding_context,
152                    const storage::FileSystemURL& url,
153                    const storage::FileSystemURL& swap_url,
154                    const SharedHandleState& handle_state);
155 
156   // Create a transfer token for a specific file or directory.
157   void CreateTransferToken(
158       const NativeFileSystemFileHandleImpl& file,
159       mojo::PendingReceiver<blink::mojom::NativeFileSystemTransferToken>
160           receiver);
161   void CreateTransferToken(
162       const NativeFileSystemDirectoryHandleImpl& directory,
163       mojo::PendingReceiver<blink::mojom::NativeFileSystemTransferToken>
164           receiver);
165 
166   // Given a mojom transfer token, looks up the token in our internal list of
167   // valid tokens. Calls the callback with the found token, or nullptr if no
168   // valid token was found.
169   using ResolvedTokenCallback =
170       base::OnceCallback<void(NativeFileSystemTransferTokenImpl*)>;
171   void ResolveTransferToken(
172       mojo::PendingRemote<blink::mojom::NativeFileSystemTransferToken> token,
173       ResolvedTokenCallback callback);
174 
175   void DidResolveTransferTokenForFileHandle(
176       const BindingContext& binding_context,
177       mojo::PendingReceiver<blink::mojom::NativeFileSystemFileHandle>
178           file_handle_receiver,
179       NativeFileSystemTransferTokenImpl* resolved_token);
180   void DidResolveTransferTokenForDirectoryHandle(
181       const BindingContext& binding_context,
182       mojo::PendingReceiver<blink::mojom::NativeFileSystemDirectoryHandle>
183           directory_handle_receiver,
184       NativeFileSystemTransferTokenImpl* resolved_token);
185 
context()186   storage::FileSystemContext* context() {
187     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
188     return context_.get();
189   }
blob_context()190   ChromeBlobStorageContext* blob_context() { return blob_context_.get(); }
191   const base::SequenceBound<storage::FileSystemOperationRunner>&
192   operation_runner();
193 
permission_context()194   NativeFileSystemPermissionContext* permission_context() {
195     return permission_context_;
196   }
197 
is_off_the_record()198   bool is_off_the_record() const { return off_the_record_; }
199 
SetPermissionContextForTesting(NativeFileSystemPermissionContext * permission_context)200   void SetPermissionContextForTesting(
201       NativeFileSystemPermissionContext* permission_context) {
202     permission_context_ = permission_context;
203   }
204 
205   // Remove |token| from |transfer_tokens_|. It is an error to try to remove a
206   // token that doesn't exist.
207   void RemoveToken(const base::UnguessableToken& token);
208 
209  private:
210   friend class NativeFileSystemFileHandleImpl;
211 
212   ~NativeFileSystemManagerImpl() override;
213   void DidOpenSandboxedFileSystem(const BindingContext& binding_context,
214                                   GetSandboxedFileSystemCallback callback,
215                                   const GURL& root,
216                                   const std::string& filesystem_name,
217                                   base::File::Error result);
218 
219   void DidChooseEntries(const BindingContext& binding_context,
220                         const FileSystemChooser::Options& options,
221                         ChooseEntriesCallback callback,
222                         blink::mojom::NativeFileSystemErrorPtr result,
223                         std::vector<base::FilePath> entries);
224   void DidVerifySensitiveDirectoryAccess(
225       const BindingContext& binding_context,
226       const FileSystemChooser::Options& options,
227       ChooseEntriesCallback callback,
228       std::vector<base::FilePath> entries,
229       NativeFileSystemPermissionContext::SensitiveDirectoryResult result);
230   void DidCreateOrTruncateSaveFile(const BindingContext& binding_context,
231                                    const base::FilePath& path,
232                                    ChooseEntriesCallback callback,
233                                    bool success);
234   void DidChooseDirectory(
235       const BindingContext& binding_context,
236       const base::FilePath& path,
237       ChooseEntriesCallback callback,
238       NativeFileSystemPermissionContext::PermissionStatus permission);
239 
240   void CreateTransferTokenImpl(
241       const storage::FileSystemURL& url,
242       const SharedHandleState& handle_state,
243       bool is_directory,
244       mojo::PendingReceiver<blink::mojom::NativeFileSystemTransferToken>
245           receiver);
246   void DoResolveTransferToken(
247       mojo::Remote<blink::mojom::NativeFileSystemTransferToken>,
248       ResolvedTokenCallback callback,
249       const base::UnguessableToken& token);
250 
251   void DidResolveForSerializeHandle(
252       SerializeHandleCallback callback,
253       NativeFileSystemTransferTokenImpl* resolved_token);
254 
255   // Creates a FileSystemURL which corresponds to a FilePath and Origin.
256   struct FileSystemURLAndFSHandle {
257     storage::FileSystemURL url;
258     std::string base_name;
259     storage::IsolatedContext::ScopedFSHandle file_system;
260   };
261   FileSystemURLAndFSHandle CreateFileSystemURLFromPath(
262       const url::Origin& origin,
263       const base::FilePath& path);
264 
265   blink::mojom::NativeFileSystemEntryPtr CreateFileEntryFromPathImpl(
266       const BindingContext& binding_context,
267       const base::FilePath& file_path,
268       NativeFileSystemPermissionContext::UserAction user_action);
269 
270   SEQUENCE_CHECKER(sequence_checker_);
271 
272   const scoped_refptr<storage::FileSystemContext> context_;
273   const scoped_refptr<ChromeBlobStorageContext> blob_context_;
274   base::SequenceBound<storage::FileSystemOperationRunner> operation_runner_;
275   NativeFileSystemPermissionContext* permission_context_;
276 
277   // All the mojo receivers for this NativeFileSystemManager itself. Keeps
278   // track of associated origin and other state as well to not have to rely on
279   // the renderer passing that in, and to be able to do security checks around
280   // transferability etc.
281   mojo::ReceiverSet<blink::mojom::NativeFileSystemManager, BindingContext>
282       receivers_;
283 
284   mojo::ReceiverSet<storage::mojom::NativeFileSystemContext>
285       internals_receivers_;
286 
287   // All the receivers for file and directory handles that have references to
288   // them.
289   mojo::UniqueReceiverSet<blink::mojom::NativeFileSystemFileHandle>
290       file_receivers_;
291   mojo::UniqueReceiverSet<blink::mojom::NativeFileSystemDirectoryHandle>
292       directory_receivers_;
293   mojo::UniqueReceiverSet<blink::mojom::NativeFileSystemFileWriter>
294       writer_receivers_;
295 
296   bool off_the_record_;
297 
298   // NativeFileSystemTransferTokenImpl owns a Transfer token receiver and is
299   // removed from this map when the mojo connection is closed.
300   std::map<base::UnguessableToken,
301            std::unique_ptr<NativeFileSystemTransferTokenImpl>>
302       transfer_tokens_;
303 
304   base::WeakPtrFactory<NativeFileSystemManagerImpl> weak_factory_{this};
305   DISALLOW_COPY_AND_ASSIGN(NativeFileSystemManagerImpl);
306 };
307 
308 }  // namespace content
309 
310 #endif  // CONTENT_BROWSER_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_MANAGER_IMPL_H_
311