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.
4
5#ifndef CHROME_BROWSER_EXTENSIONS_API_DEVELOPER_PRIVATE_DEVELOPER_PRIVATE_API_H_
6#define CHROME_BROWSER_EXTENSIONS_API_DEVELOPER_PRIVATE_DEVELOPER_PRIVATE_API_H_
7
8#include <set>
9
10#include "base/files/file.h"
11#include "base/scoped_observer.h"
12#include "chrome/browser/extensions/api/developer_private/entry_picker.h"
13#include "chrome/browser/extensions/api/file_system/file_system_api.h"
14#include "chrome/browser/extensions/chrome_extension_function.h"
15#include "chrome/browser/extensions/error_console/error_console.h"
16#include "chrome/browser/extensions/extension_install_prompt.h"
17#include "chrome/browser/extensions/extension_uninstall_dialog.h"
18#include "chrome/browser/extensions/pack_extension_job.h"
19#include "chrome/browser/extensions/requirements_checker.h"
20#include "content/public/browser/notification_observer.h"
21#include "content/public/browser/notification_registrar.h"
22#include "content/public/browser/render_view_host.h"
23#include "extensions/browser/browser_context_keyed_api_factory.h"
24#include "extensions/browser/event_router.h"
25#include "extensions/browser/extension_registry_observer.h"
26#include "storage/browser/fileapi/file_system_context.h"
27#include "storage/browser/fileapi/file_system_operation.h"
28#include "ui/shell_dialogs/select_file_dialog.h"
29
30class Profile;
31
32namespace extensions {
33
34class ExtensionError;
35class ExtensionRegistry;
36class ExtensionSystem;
37class ManagementPolicy;
38
39namespace api {
40
41class EntryPicker;
42class EntryPickerClient;
43
44namespace developer_private {
45
46struct ItemInfo;
47struct ItemInspectView;
48struct ProjectInfo;
49
50}  // namespace developer_private
51
52}  // namespace api
53
54namespace developer = api::developer_private;
55
56typedef std::vector<linked_ptr<developer::ItemInfo> > ItemInfoList;
57typedef std::vector<linked_ptr<developer::ProjectInfo> > ProjectInfoList;
58typedef std::vector<linked_ptr<developer::ItemInspectView> >
59    ItemInspectViewList;
60
61class DeveloperPrivateEventRouter : public content::NotificationObserver,
62                                    public ExtensionRegistryObserver,
63                                    public ErrorConsole::Observer {
64 public:
65  explicit DeveloperPrivateEventRouter(Profile* profile);
66  virtual ~DeveloperPrivateEventRouter();
67
68  // Add or remove an ID to the list of extensions subscribed to events.
69  void AddExtensionId(const std::string& extension_id);
70  void RemoveExtensionId(const std::string& extension_id);
71
72 private:
73  // content::NotificationObserver implementation.
74  virtual void Observe(int type,
75                       const content::NotificationSource& source,
76                       const content::NotificationDetails& details) OVERRIDE;
77
78  // ExtensionRegistryObserver implementation.
79  virtual void OnExtensionLoaded(content::BrowserContext* browser_context,
80                                 const Extension* extension) OVERRIDE;
81  virtual void OnExtensionUnloaded(
82      content::BrowserContext* browser_context,
83      const Extension* extension,
84      UnloadedExtensionInfo::Reason reason) OVERRIDE;
85  virtual void OnExtensionWillBeInstalled(
86      content::BrowserContext* browser_context,
87      const Extension* extension,
88      bool is_update,
89      bool from_ephemeral,
90      const std::string& old_name) OVERRIDE;
91  virtual void OnExtensionUninstalled(
92      content::BrowserContext* browser_context,
93      const Extension* extension,
94      extensions::UninstallReason reason) OVERRIDE;
95
96  // ErrorConsole::Observer implementation.
97  virtual void OnErrorAdded(const ExtensionError* error) OVERRIDE;
98
99  content::NotificationRegistrar registrar_;
100
101  ScopedObserver<extensions::ExtensionRegistry,
102                 extensions::ExtensionRegistryObserver>
103      extension_registry_observer_;
104
105  Profile* profile_;
106
107  // The set of IDs of the Extensions that have subscribed to DeveloperPrivate
108  // events. Since the only consumer of the DeveloperPrivate API is currently
109  // the Apps Developer Tool (which replaces the chrome://extensions page), we
110  // don't want to send information about the subscribing extension in an
111  // update. In particular, we want to avoid entering a loop, which could happen
112  // when, e.g., the Apps Developer Tool throws an error.
113  std::set<std::string> extension_ids_;
114
115  DISALLOW_COPY_AND_ASSIGN(DeveloperPrivateEventRouter);
116};
117
118// The profile-keyed service that manages the DeveloperPrivate API.
119class DeveloperPrivateAPI : public BrowserContextKeyedAPI,
120                            public EventRouter::Observer {
121 public:
122  static BrowserContextKeyedAPIFactory<DeveloperPrivateAPI>*
123      GetFactoryInstance();
124
125  // Convenience method to get the DeveloperPrivateAPI for a profile.
126  static DeveloperPrivateAPI* Get(content::BrowserContext* context);
127
128  explicit DeveloperPrivateAPI(content::BrowserContext* context);
129  virtual ~DeveloperPrivateAPI();
130
131  void SetLastUnpackedDirectory(const base::FilePath& path);
132
133  base::FilePath& GetLastUnpackedDirectory() {
134    return last_unpacked_directory_;
135  }
136
137  // KeyedService implementation
138  virtual void Shutdown() OVERRIDE;
139
140  // EventRouter::Observer implementation.
141  virtual void OnListenerAdded(const EventListenerInfo& details) OVERRIDE;
142  virtual void OnListenerRemoved(const EventListenerInfo& details) OVERRIDE;
143
144 private:
145  friend class BrowserContextKeyedAPIFactory<DeveloperPrivateAPI>;
146
147  // BrowserContextKeyedAPI implementation.
148  static const char* service_name() { return "DeveloperPrivateAPI"; }
149  static const bool kServiceRedirectedInIncognito = true;
150  static const bool kServiceIsNULLWhileTesting = true;
151
152  void RegisterNotifications();
153
154  Profile* profile_;
155
156  // Used to start the load |load_extension_dialog_| in the last directory that
157  // was loaded.
158  base::FilePath last_unpacked_directory_;
159
160  // Created lazily upon OnListenerAdded.
161  scoped_ptr<DeveloperPrivateEventRouter> developer_private_event_router_;
162
163  DISALLOW_COPY_AND_ASSIGN(DeveloperPrivateAPI);
164};
165
166namespace api {
167
168class DeveloperPrivateAutoUpdateFunction : public ChromeSyncExtensionFunction {
169 public:
170  DECLARE_EXTENSION_FUNCTION("developerPrivate.autoUpdate",
171                             DEVELOPERPRIVATE_AUTOUPDATE)
172
173 protected:
174  virtual ~DeveloperPrivateAutoUpdateFunction();
175
176  // ExtensionFunction:
177  virtual bool RunSync() OVERRIDE;
178};
179
180class DeveloperPrivateGetItemsInfoFunction
181    : public ChromeAsyncExtensionFunction {
182 public:
183  DECLARE_EXTENSION_FUNCTION("developerPrivate.getItemsInfo",
184                             DEVELOPERPRIVATE_GETITEMSINFO)
185
186 protected:
187  virtual ~DeveloperPrivateGetItemsInfoFunction();
188
189  // ExtensionFunction:
190  virtual bool RunAsync() OVERRIDE;
191
192 private:
193  scoped_ptr<developer::ItemInfo> CreateItemInfo(const Extension& item,
194                                                 bool item_is_enabled);
195
196  void GetIconsOnFileThread(
197      ItemInfoList item_list,
198      std::map<std::string, ExtensionResource> itemIdToIconResourceMap);
199
200  // Helper that lists the current inspectable html pages for the extension.
201  void GetInspectablePagesForExtensionProcess(
202      const Extension* extension,
203      const std::set<content::RenderViewHost*>& views,
204      ItemInspectViewList* result);
205
206  ItemInspectViewList GetInspectablePagesForExtension(
207      const Extension* extension,
208      bool extension_is_enabled);
209
210  void GetAppWindowPagesForExtensionProfile(const Extension* extension,
211                                            ItemInspectViewList* result);
212
213  linked_ptr<developer::ItemInspectView> constructInspectView(
214      const GURL& url,
215      int render_process_id,
216      int render_view_id,
217      bool incognito,
218      bool generated_background_page);
219};
220
221class DeveloperPrivateInspectFunction : public ChromeSyncExtensionFunction {
222 public:
223  DECLARE_EXTENSION_FUNCTION("developerPrivate.inspect",
224                             DEVELOPERPRIVATE_INSPECT)
225
226 protected:
227  virtual ~DeveloperPrivateInspectFunction();
228
229  // ExtensionFunction:
230  virtual bool RunSync() OVERRIDE;
231};
232
233class DeveloperPrivateAllowFileAccessFunction
234    : public ChromeSyncExtensionFunction {
235 public:
236  DECLARE_EXTENSION_FUNCTION("developerPrivate.allowFileAccess",
237                             DEVELOPERPRIVATE_ALLOWFILEACCESS);
238
239 protected:
240  virtual ~DeveloperPrivateAllowFileAccessFunction();
241
242  // ExtensionFunction:
243  virtual bool RunSync() OVERRIDE;
244};
245
246class DeveloperPrivateAllowIncognitoFunction
247    : public ChromeSyncExtensionFunction {
248 public:
249  DECLARE_EXTENSION_FUNCTION("developerPrivate.allowIncognito",
250                             DEVELOPERPRIVATE_ALLOWINCOGNITO);
251
252 protected:
253  virtual ~DeveloperPrivateAllowIncognitoFunction();
254
255  // ExtensionFunction:
256  virtual bool RunSync() OVERRIDE;
257};
258
259class DeveloperPrivateReloadFunction : public ChromeSyncExtensionFunction {
260 public:
261  DECLARE_EXTENSION_FUNCTION("developerPrivate.reload",
262                             DEVELOPERPRIVATE_RELOAD);
263
264 protected:
265  virtual ~DeveloperPrivateReloadFunction();
266
267  // ExtensionFunction:
268  virtual bool RunSync() OVERRIDE;
269};
270
271class DeveloperPrivateShowPermissionsDialogFunction
272    : public ChromeSyncExtensionFunction,
273      public ExtensionInstallPrompt::Delegate {
274 public:
275  DECLARE_EXTENSION_FUNCTION("developerPrivate.showPermissionsDialog",
276                             DEVELOPERPRIVATE_PERMISSIONS);
277
278  DeveloperPrivateShowPermissionsDialogFunction();
279 protected:
280  virtual ~DeveloperPrivateShowPermissionsDialogFunction();
281
282  // ExtensionFunction:
283  virtual bool RunSync() OVERRIDE;
284
285  // Overridden from ExtensionInstallPrompt::Delegate
286  virtual void InstallUIProceed() OVERRIDE;
287  virtual void InstallUIAbort(bool user_initiated) OVERRIDE;
288
289  scoped_ptr<ExtensionInstallPrompt> prompt_;
290  std::string extension_id_;
291};
292
293class DeveloperPrivateEnableFunction
294    : public ChromeSyncExtensionFunction,
295      public base::SupportsWeakPtr<DeveloperPrivateEnableFunction> {
296 public:
297  DECLARE_EXTENSION_FUNCTION("developerPrivate.enable",
298                             DEVELOPERPRIVATE_ENABLE);
299
300  DeveloperPrivateEnableFunction();
301
302 protected:
303  virtual ~DeveloperPrivateEnableFunction();
304
305  // Callback for requirements checker.
306  void OnRequirementsChecked(const std::string& extension_id,
307                             std::vector<std::string> requirements_errors);
308  // ExtensionFunction:
309  virtual bool RunSync() OVERRIDE;
310
311 private:
312  scoped_ptr<RequirementsChecker> requirements_checker_;
313};
314
315class DeveloperPrivateChooseEntryFunction : public ChromeAsyncExtensionFunction,
316                                            public EntryPickerClient {
317 protected:
318  virtual ~DeveloperPrivateChooseEntryFunction();
319  virtual bool RunAsync() OVERRIDE;
320  bool ShowPicker(ui::SelectFileDialog::Type picker_type,
321                  const base::FilePath& last_directory,
322                  const base::string16& select_title,
323                  const ui::SelectFileDialog::FileTypeInfo& info,
324                  int file_type_index);
325
326  // EntryPickerClient functions.
327  virtual void FileSelected(const base::FilePath& path) = 0;
328  virtual void FileSelectionCanceled() = 0;
329};
330
331
332class DeveloperPrivateLoadUnpackedFunction
333    : public DeveloperPrivateChooseEntryFunction {
334 public:
335  DECLARE_EXTENSION_FUNCTION("developerPrivate.loadUnpacked",
336                             DEVELOPERPRIVATE_LOADUNPACKED);
337
338 protected:
339  virtual ~DeveloperPrivateLoadUnpackedFunction();
340  virtual bool RunAsync() OVERRIDE;
341
342  // EntryPickerCLient implementation.
343  virtual void FileSelected(const base::FilePath& path) OVERRIDE;
344  virtual void FileSelectionCanceled() OVERRIDE;
345};
346
347class DeveloperPrivateChoosePathFunction
348    : public DeveloperPrivateChooseEntryFunction {
349 public:
350  DECLARE_EXTENSION_FUNCTION("developerPrivate.choosePath",
351                             DEVELOPERPRIVATE_CHOOSEPATH);
352
353 protected:
354  virtual ~DeveloperPrivateChoosePathFunction();
355  virtual bool RunAsync() OVERRIDE;
356
357  // EntryPickerClient functions.
358  virtual void FileSelected(const base::FilePath& path) OVERRIDE;
359  virtual void FileSelectionCanceled() OVERRIDE;
360};
361
362class DeveloperPrivatePackDirectoryFunction
363    : public ChromeAsyncExtensionFunction,
364      public PackExtensionJob::Client {
365
366 public:
367  DECLARE_EXTENSION_FUNCTION("developerPrivate.packDirectory",
368                             DEVELOPERPRIVATE_PACKDIRECTORY);
369
370  DeveloperPrivatePackDirectoryFunction();
371
372  // ExtensionPackJob::Client implementation.
373  virtual void OnPackSuccess(const base::FilePath& crx_file,
374                             const base::FilePath& key_file) OVERRIDE;
375  virtual void OnPackFailure(const std::string& error,
376                             ExtensionCreator::ErrorType error_type) OVERRIDE;
377
378 protected:
379  virtual ~DeveloperPrivatePackDirectoryFunction();
380  virtual bool RunAsync() OVERRIDE;
381
382 private:
383  scoped_refptr<PackExtensionJob> pack_job_;
384  std::string item_path_str_;
385  std::string key_path_str_;
386};
387
388class DeveloperPrivateIsProfileManagedFunction
389    : public ChromeSyncExtensionFunction {
390 public:
391  DECLARE_EXTENSION_FUNCTION("developerPrivate.isProfileManaged",
392                             DEVELOPERPRIVATE_ISPROFILEMANAGED);
393
394 protected:
395  virtual ~DeveloperPrivateIsProfileManagedFunction();
396
397  // ExtensionFunction:
398  virtual bool RunSync() OVERRIDE;
399};
400
401class DeveloperPrivateLoadDirectoryFunction
402    : public ChromeAsyncExtensionFunction {
403 public:
404  DECLARE_EXTENSION_FUNCTION("developerPrivate.loadDirectory",
405                             DEVELOPERPRIVATE_LOADUNPACKEDCROS);
406
407  DeveloperPrivateLoadDirectoryFunction();
408
409 protected:
410  virtual ~DeveloperPrivateLoadDirectoryFunction();
411
412  // ExtensionFunction:
413  virtual bool RunAsync() OVERRIDE;
414
415  bool LoadByFileSystemAPI(const storage::FileSystemURL& directory_url);
416
417  void ClearExistingDirectoryContent(const base::FilePath& project_path);
418
419  void ReadDirectoryByFileSystemAPI(const base::FilePath& project_path,
420                                    const base::FilePath& destination_path);
421
422  void ReadDirectoryByFileSystemAPICb(
423      const base::FilePath& project_path,
424      const base::FilePath& destination_path,
425      base::File::Error result,
426      const storage::FileSystemOperation::FileEntryList& file_list,
427      bool has_more);
428
429  void SnapshotFileCallback(
430      const base::FilePath& target_path,
431      base::File::Error result,
432      const base::File::Info& file_info,
433      const base::FilePath& platform_path,
434      const scoped_refptr<storage::ShareableFileReference>& file_ref);
435
436  void CopyFile(const base::FilePath& src_path,
437                const base::FilePath& dest_path);
438
439  void Load();
440
441  scoped_refptr<storage::FileSystemContext> context_;
442
443  // syncfs url representing the root of the folder to be copied.
444  std::string project_base_url_;
445
446  // physical path on disc of the folder to be copied.
447  base::FilePath project_base_path_;
448
449 private:
450  int pending_copy_operations_count_;
451
452  // This is set to false if any of the copyFile operations fail on
453  // call of the API. It is returned as a response of the API call.
454  bool success_;
455};
456
457class DeveloperPrivateRequestFileSourceFunction
458    : public ChromeAsyncExtensionFunction {
459 public:
460  DECLARE_EXTENSION_FUNCTION("developerPrivate.requestFileSource",
461                             DEVELOPERPRIVATE_REQUESTFILESOURCE);
462
463  DeveloperPrivateRequestFileSourceFunction();
464
465 protected:
466  virtual ~DeveloperPrivateRequestFileSourceFunction();
467
468  // ExtensionFunction:
469  virtual bool RunAsync() OVERRIDE;
470
471 private:
472  void LaunchCallback(const base::DictionaryValue& results);
473};
474
475class DeveloperPrivateOpenDevToolsFunction
476    : public ChromeAsyncExtensionFunction {
477 public:
478  DECLARE_EXTENSION_FUNCTION("developerPrivate.openDevTools",
479                             DEVELOPERPRIVATE_OPENDEVTOOLS);
480
481  DeveloperPrivateOpenDevToolsFunction();
482
483 protected:
484  virtual ~DeveloperPrivateOpenDevToolsFunction();
485
486  // ExtensionFunction:
487  virtual bool RunAsync() OVERRIDE;
488};
489
490}  // namespace api
491
492}  // namespace extensions
493
494#endif  // CHROME_BROWSER_EXTENSIONS_API_DEVELOPER_PRIVATE_DEVELOPER_PRIVATE_API_H_
495