diff options
Diffstat (limited to 'chromium/chrome/common/apps/platform_apps')
19 files changed, 1410 insertions, 0 deletions
diff --git a/chromium/chrome/common/apps/platform_apps/OWNERS b/chromium/chrome/common/apps/platform_apps/OWNERS new file mode 100644 index 00000000000..42444bcd16d --- /dev/null +++ b/chromium/chrome/common/apps/platform_apps/OWNERS @@ -0,0 +1,2 @@ +per-file *_messages*.h=set noparent +per-file *_messages*.h=file://ipc/SECURITY_OWNERS diff --git a/chromium/chrome/common/apps/platform_apps/api/arc_apps_private.idl b/chromium/chrome/common/apps/platform_apps/api/arc_apps_private.idl new file mode 100644 index 00000000000..1a3dd23237c --- /dev/null +++ b/chromium/chrome/common/apps/platform_apps/api/arc_apps_private.idl @@ -0,0 +1,33 @@ +// Copyright 2018 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. + +// Use the <code>chrome.arcAppsPrivate</code> API to manage ARC apps. +[platforms=("chromeos"), nodoc] +namespace arcAppsPrivate { + + dictionary AppInfo { + // The app package name. + DOMString packageName; + }; + + callback VoidCallback = void (); + callback GetLaunchableAppsCallback = void (AppInfo[] appsInfo); + + interface Functions { + // Returns info of the installed ARC apps that are launchable, including + // ready and non-ready apps. + static void getLaunchableApps(GetLaunchableAppsCallback callback); + + // Launches the ARC app with its package name. The app is launched + // immediately if it's ready, otherwise it will be launched when it becomes + // ready. The callback is called as soon as the launch is scheduled. + static void launchApp(DOMString packageName, + optional VoidCallback callback); + }; + + interface Events { + // Fires when a new app can be launched via $(ref:launchApp). + static void onInstalled(AppInfo app_info); + }; +}; diff --git a/chromium/chrome/common/apps/platform_apps/api/browser.idl b/chromium/chrome/common/apps/platform_apps/api/browser.idl new file mode 100644 index 00000000000..971164bd068 --- /dev/null +++ b/chromium/chrome/common/apps/platform_apps/api/browser.idl @@ -0,0 +1,26 @@ +// 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. + +// Use the <code>chrome.browser</code> API to interact with the Chrome browser +// associated with the current application and Chrome profile. +namespace browser { + // Options for the $(ref:openTab) function. + dictionary OpenTabOptions { + // The URL to navigate to when the new tab is initially opened. + DOMString url; + }; + + callback Callback = void(); + + interface Functions { + // Opens a new tab in a browser window associated with the current + // application and Chrome profile. If no browser window for the Chrome + // profile is opened, a new one is opened prior to creating the new tab. + // |options|: Configures how the tab should be opened. + // |callback|: Called when the tab was successfully created, or failed to + // be created. If failed, $(ref:runtime.lastError) will be set. + static void openTab(OpenTabOptions options, + optional Callback callback); + }; +}; diff --git a/chromium/chrome/common/apps/platform_apps/api/media_galleries.idl b/chromium/chrome/common/apps/platform_apps/api/media_galleries.idl new file mode 100644 index 00000000000..ebbb1f35db3 --- /dev/null +++ b/chromium/chrome/common/apps/platform_apps/api/media_galleries.idl @@ -0,0 +1,255 @@ +// Copyright (c) 2012 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. + + +// Use the <code>chrome.mediaGalleries</code> API to access media files (audio, +// images, video) from the user's local disks (with the user's consent). +namespace mediaGalleries { + + [inline_doc] enum GalleryChangeType { + // The contents of the gallery have changed. + contents_changed, + // The watch has been dropped because the device has been detached, + // the gallery permission has been removed, or any other reason. + watch_dropped + }; + + [inline_doc] enum GetMediaFileSystemsInteractivity { + // Do not act interactively. + no, + // Ask the user to manage permitted media galleries. + yes, + // Ask the user to manage permitted galleries only if the return set would + // otherwise be empty. + if_needed + }; + + [inline_doc] enum GetMetadataType { + // Retrieve the mime type, metadata tags, and attached images. + all, + // Retrieve only the mime type and the metadata tags. + mimeTypeAndTags, + // Retrieve only the mime type. + mimeTypeOnly + }; + + [nodefine, inline_doc] enum ScanProgressType { + // The scan started. + start, + // The scan was cancelled. + cancel, + // The scan finished but none of the result have been added, + // addScanResults() has to be called to ask the user for permission. + finish, + // The scan encountered an error and could not proceed. + error + }; + + [inline_doc] dictionary GalleryChangeDetails { + // Type of change event. + GalleryChangeType type; + + // Identifies the modified gallery. + DOMString galleryId; + }; + + [inline_doc] dictionary MediaFileSystemsDetails { + // Whether to prompt the user for permission to additional media galleries + // before returning the permitted set. Default is silent. If the value + // 'yes' is passed, or if the application has not been granted access to + // any media galleries and the value 'if_needed' is passed, then the + // media gallery configuration dialog will be displayed. + GetMediaFileSystemsInteractivity? interactive; + }; + + [inline_doc] dictionary MediaMetadataOptions { + // Specifies which subset of the metadata to retrieve. Defaults to 'all' + // if the option is omitted. + GetMetadataType? metadataType; + }; + + callback MediaFileSystemsCallback = + void ([instanceOf=DOMFileSystem] object[] mediaFileSystems); + + callback AddUserFolderCallback = + void ([instanceOf=DOMFileSystem] object[] mediaFileSystems, + DOMString selectedFileSystemName); + + [nodefine] callback DropPermissionForMediaFileSystemCallback = void (); + + [inline_doc] dictionary MediaFileSystemMetadata { + // The name of the file system. + DOMString name; + + // A unique and persistent id for the media gallery. + DOMString galleryId; + + // If the media gallery is on a removable device, a unique id for the + // device while the device is online. + DOMString? deviceId; + + // True if the media gallery is on a removable device. + boolean isRemovable; + + // True if the device the media gallery is on was detected as a media + // device. i.e. a PTP or MTP device, or a DCIM directory is present. + boolean isMediaDevice; + + // True if the device is currently available. + boolean isAvailable; + }; + + [nodefine, inline_doc] dictionary ScanProgressDetails { + // The type of progress event, i.e. start, finish, etc. + ScanProgressType type; + + // The number of Galleries found. + long? galleryCount; + + // Appoximate number of media files found; some file types can be either + // audio or video and are included in both counts. + long? audioCount; + long? imageCount; + long? videoCount; + }; + + callback MediaFileSystemsMetadataCallback = + void (MediaFileSystemMetadata[] metadata); + + dictionary StreamInfo { + // Describes format of container or codec of stream, i.e. "mp3", "h264". + DOMString type; + + // An unfiltered string->string dictionary of tags for the stream. + object tags; + }; + + dictionary MediaMetadata { + // The browser sniffed mime type. + DOMString mimeType; + + // Defined for video. In pixels. + long? height; + long? width; + + // Defined for audio and video. In seconds. + double? duration; + + // Defined for video. In degrees. + long? rotation; + + // Defined for audio and video. + DOMString? album; + DOMString? artist; + DOMString? comment; + DOMString? copyright; + long? disc; + DOMString? genre; + DOMString? language; + DOMString? title; + long? track; + + // All the metadata in the media file. For formats with multiple streams, + // stream order will be preserved. Container metadata is the first element. + StreamInfo[] rawTags; + + // The images embedded in the media file's metadata. This is most often + // used for album art or video thumbnails. + [instanceOf=Blob] object[] attachedImages; + }; + + callback MediaMetadataCallback = void (MediaMetadata metadata); + + // A dictionary that describes the add gallery watch request results. + dictionary AddGalleryWatchResult { + DOMString galleryId; + boolean success; + }; + + callback AddGalleryWatchCallback = void (AddGalleryWatchResult result); + [nodefine] callback GetAllGalleryWatchCallback = + void (DOMString[] galleryIds); + + interface Functions { + // Get the media galleries configured in this user agent. If none are + // configured or available, the callback will receive an empty array. + static void getMediaFileSystems(optional MediaFileSystemsDetails details, + MediaFileSystemsCallback callback); + + // Present a directory picker to the user and add the selected directory + // as a gallery. If the user cancels the picker, selectedFileSystemName + // will be empty. + // A user gesture is required for the dialog to display. Without a user + // gesture, the callback will run as though the user canceled. + static void addUserSelectedFolder(AddUserFolderCallback callback); + + // Give up access to a given media gallery. + [nodefine, deprecated="The user can manually drop access to galleries + via the permissions dialog."] + static void dropPermissionForMediaFileSystem( + DOMString galleryId, + optional DropPermissionForMediaFileSystemCallback callback); + + // Start a scan of the user's hard disks for directories containing media. + // The scan may take a long time so progress and completion is communicated + // by events. No permission is granted as a result of the scan, see + // addScanResults. + [nodefine, deprecated="The mediaGalleries API no longer supports scanning."] + static void startMediaScan(); + + // Cancel any pending media scan. Well behaved apps should provide a way + // for the user to cancel scans they start. + [nodefine, deprecated="The mediaGalleries API no longer supports scanning."] + static void cancelMediaScan(); + + // Show the user the scan results and let them add any or all of them as + // galleries. This should be used after the 'finish' onScanProgress() + // event has happened. All galleries the app has access to are returned, not + // just the newly added galleries. + [nodefine, deprecated="The mediaGalleries API no longer supports scanning."] + static void addScanResults(MediaFileSystemsCallback callback); + + // Get metadata about a specific media file system. + [nocompile] static MediaFileSystemMetadata getMediaFileSystemMetadata( + [instanceOf=DOMFileSystem] object mediaFileSystem); + + // Get metadata for all available media galleries. + [nodefine, deprecated="Use getMediaFileSystemMetadata instead."] + static void getAllMediaFileSystemMetadata( + MediaFileSystemsMetadataCallback callback); + + // Gets the media-specific metadata for a media file. This should work + // for files in media galleries as well as other DOM filesystems. + static void getMetadata([instanceOf=Blob] object mediaFile, + optional MediaMetadataOptions options, + MediaMetadataCallback callback); + + // Adds a gallery watch for the gallery with the specified gallery ID. + // The given callback is then fired with a success or failure result. + static void addGalleryWatch(DOMString galleryId, + AddGalleryWatchCallback callback); + + // Removes a gallery watch for the gallery with the specified gallery ID. + static void removeGalleryWatch(DOMString galleryId); + + // Notifies which galleries are being watched via the given callback. + [nodefine, deprecated="Applications should store their own gallery watches + as they are added."] + static void getAllGalleryWatch(GetAllGalleryWatchCallback callback); + + // Removes all gallery watches. + [nodefine, deprecated="Use removeGalleryWatch instead."] + static void removeAllGalleryWatch(); + }; + + interface Events { + // Fired when a media gallery is changed or a gallery watch is dropped. + static void onGalleryChanged(GalleryChangeDetails details); + + // The pending media scan has changed state. See details for more + // information. + [nodefine, deprecated="The mediaGalleries API no longer supports scanning."] + static void onScanProgress(ScanProgressDetails details); + }; +}; diff --git a/chromium/chrome/common/apps/platform_apps/api/music_manager_private.idl b/chromium/chrome/common/apps/platform_apps/api/music_manager_private.idl new file mode 100644 index 00000000000..b6d13fba921 --- /dev/null +++ b/chromium/chrome/common/apps/platform_apps/api/music_manager_private.idl @@ -0,0 +1,16 @@ +// Copyright 2013 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. + +// musicManagerPrivate. +namespace musicManagerPrivate { + + callback GetDeviceIdCallback = void (DOMString device_id); + + interface Functions { + // Returns an identifier stable across users and reboots. + // + // |callback| : Called with the stable identifier value. + static void getDeviceId(GetDeviceIdCallback callback); + }; +}; diff --git a/chromium/chrome/common/apps/platform_apps/api/sync_file_system.idl b/chromium/chrome/common/apps/platform_apps/api/sync_file_system.idl new file mode 100644 index 00000000000..711625661e9 --- /dev/null +++ b/chromium/chrome/common/apps/platform_apps/api/sync_file_system.idl @@ -0,0 +1,199 @@ +// Copyright (c) 2012 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. + +// Use the <code>chrome.syncFileSystem</code> API to save and synchronize data +// on Google Drive. This API is NOT for accessing arbitrary user docs stored in +// Google Drive. It provides app-specific syncable storage for offline and +// caching usage so that the same data can be available across different +// clients. Read <a href="app_storage.html">Manage Data</a> for more on using +// this API. +namespace syncFileSystem { + enum SyncAction { + added, updated, deleted + }; + + enum ServiceStatus { + // The sync service is being initialized (e.g. restoring data from the + // database, checking connectivity and authenticating to the service etc). + initializing, + + // The sync service is up and running. + running, + + // The sync service is not synchronizing files because the remote service + // needs to be authenticated by the user to proceed. + authentication_required, + + // The sync service is not synchronizing files because the remote service + // is (temporarily) unavailable due to some recoverable errors, e.g. + // network is offline, the remote service is down or not + // reachable etc. More details should be given by |description| parameter + // in OnServiceInfoUpdated (which could contain service-specific details). + temporary_unavailable, + + // The sync service is disabled and the content will never sync. + // (E.g. this could happen when the user has no account on + // the remote service or the sync service has had an unrecoverable + // error.) + disabled + }; + + enum FileStatus { + // Not conflicting and has no pending local changes. + synced, + + // Has one or more pending local changes that haven't been synchronized. + pending, + + // File conflicts with remote version and must be resolved manually. + conflicting + }; + + enum SyncDirection { + local_to_remote, remote_to_local + }; + + enum ConflictResolutionPolicy { + last_write_win, manual + }; + + dictionary FileInfo { + // <code>fileEntry</code> for the target file whose status has changed. + // Contains name and path information of synchronized file. + // On file deletion, + // <code>fileEntry</code> information will still be available + // but file will no longer exist. + [instanceOf=Entry] object fileEntry; + + // Resulting file status after $(ref:onFileStatusChanged) event. + // The status value can be <code>'synced'</code>, + // <code>'pending'</code> or <code>'conflicting'</code>. + FileStatus status; + + // Sync action taken to fire $(ref:onFileStatusChanged) event. + // The action value can be + // <code>'added'</code>, <code>'updated'</code> or <code>'deleted'</code>. + // Only applies if status is <code>'synced'</code>. + SyncAction? action; + + // Sync direction for the $(ref:onFileStatusChanged) event. + // Sync direction value can be + // <code>'local_to_remote'</code> or <code>'remote_to_local'</code>. + // Only applies if status is <code>'synced'</code>. + SyncDirection? direction; + }; + + dictionary FileStatusInfo { + // One of the Entry's originally given to getFileStatuses. + [instanceOf=Entry] object fileEntry; + + // The status value can be <code>'synced'</code>, + // <code>'pending'</code> or <code>'conflicting'</code>. + FileStatus status; + + // Optional error that is only returned if there was a problem retrieving + // the FileStatus for the given file. + DOMString? error; + }; + + dictionary StorageInfo { + long usageBytes; + long quotaBytes; + }; + + dictionary ServiceInfo { + ServiceStatus state; + DOMString description; + }; + + // A callback type for requestFileSystem. + callback GetFileSystemCallback = + void ([instanceOf=DOMFileSystem] object fileSystem); + + // A callback type for getUsageAndQuota. + callback QuotaAndUsageCallback = void (StorageInfo info); + + // Returns true if operation was successful. + callback DeleteFileSystemCallback = void (boolean result); + + // A callback type for getFileStatus. + callback GetFileStatusCallback = void (FileStatus status); + + // A callback type for getFileStatuses. + callback GetFileStatusesCallback = void (FileStatusInfo[] status); + + // A callback type for getServiceStatus. + callback GetServiceStatusCallback = void (ServiceStatus status); + + // A callback type for getConflictResolutionPolicy. + callback GetConflictResolutionPolicyCallback = + void (ConflictResolutionPolicy policy); + + // A generic result callback to indicate success or failure. + callback ResultCallback = void (); + + interface Functions { + // Returns a syncable filesystem backed by Google Drive. + // The returned <code>DOMFileSystem</code> instance can be operated on + // in the same way as the Temporary and Persistant file systems (see + // <a href="http://dev.w3.org/2009/dap/file-system/file-dir-sys.html"> + // http://dev.w3.org/2009/dap/file-system/file-dir-sys.html</a>). + // + // Calling this multiple times from + // the same app will return the same handle to the same file system. + // + // Note this call can fail. For example, if the user is not signed in to + // Chrome or if there is no network operation. To handle these errors it is + // important chrome.runtime.lastError is checked in the callback. + static void requestFileSystem(GetFileSystemCallback callback); + + // Sets the default conflict resolution policy + // for the <code>'syncable'</code> file storage for the app. + // By default it is set to <code>'last_write_win'</code>. + // When conflict resolution policy is set to <code>'last_write_win'</code> + // conflicts for existing files are automatically resolved next time + // the file is updated. + // |callback| can be optionally given to know if the request has + // succeeded or not. + static void setConflictResolutionPolicy( + ConflictResolutionPolicy policy, + optional ResultCallback callback); + + // Gets the current conflict resolution policy. + static void getConflictResolutionPolicy( + GetConflictResolutionPolicyCallback callback); + + // Returns the current usage and quota in bytes + // for the <code>'syncable'</code> file storage for the app. + static void getUsageAndQuota([instanceOf=DOMFileSystem] object fileSystem, + QuotaAndUsageCallback callback); + + // Returns the $(ref:FileStatus) for the given <code>fileEntry</code>. + // The status value can be <code>'synced'</code>, + // <code>'pending'</code> or <code>'conflicting'</code>. + // Note that <code>'conflicting'</code> state only happens when + // the service's conflict resolution policy is set to <code>'manual'</code>. + static void getFileStatus([instanceOf=Entry] object fileEntry, + GetFileStatusCallback callback); + + // Returns each $(ref:FileStatus) for the given <code>fileEntry</code> array. + // Typically called with the result from dirReader.readEntries(). + static void getFileStatuses(object[] fileEntries, + GetFileStatusesCallback callback); + + // Returns the current sync backend status. + static void getServiceStatus(GetServiceStatusCallback callback); + }; + + interface Events { + // Fired when an error or other status change has happened in the + // sync backend (for example, when the sync is temporarily disabled due to + // network or authentication error). + static void onServiceStatusChanged(ServiceInfo detail); + + // Fired when a file has been updated by the background sync service. + static void onFileStatusChanged(FileInfo detail); + }; + +}; diff --git a/chromium/chrome/common/apps/platform_apps/api/webstore_widget_private.idl b/chromium/chrome/common/apps/platform_apps/api/webstore_widget_private.idl new file mode 100644 index 00000000000..ea0d07a6778 --- /dev/null +++ b/chromium/chrome/common/apps/platform_apps/api/webstore_widget_private.idl @@ -0,0 +1,24 @@ +// Copyright 2015 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. + +// webstoreWidgetPrivate API. +// This is a private API used to install apps via Chrome Web Store widget - for +// example in Files app to install file system provider services. +[platforms=("chromeos")] +namespace webstoreWidgetPrivate { + +// Callback that does not take arguments. +callback SimpleCallback = void(); + +interface Functions { + // Requests to install a webstore item. + // |item_id| The id of the item to install. + // |silentInstallation| False to show installation prompt. True not to show. + // Can be set to true only for a subset of installation requests. + static void installWebstoreItem(DOMString itemId, + boolean silentInstallation, + SimpleCallback callback); +}; + +}; diff --git a/chromium/chrome/common/apps/platform_apps/chrome_apps_api_permissions.cc b/chromium/chrome/common/apps/platform_apps/chrome_apps_api_permissions.cc new file mode 100644 index 00000000000..99e1f557bb7 --- /dev/null +++ b/chromium/chrome/common/apps/platform_apps/chrome_apps_api_permissions.cc @@ -0,0 +1,45 @@ +// Copyright 2018 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 "chrome/common/apps/platform_apps/chrome_apps_api_permissions.h" + +#include <memory> + +#include "chrome/common/apps/platform_apps/media_galleries_permission.h" + +namespace chrome_apps_api_permissions { +namespace { + +template <typename T> +std::unique_ptr<extensions::APIPermission> CreateAPIPermission( + const extensions::APIPermissionInfo* permission) { + return std::make_unique<T>(permission); +} + +// WARNING: If you are modifying a permission message in this list, be sure to +// add the corresponding permission message rule to +// ChromePermissionMessageProvider::GetPermissionMessages as well. +constexpr extensions::APIPermissionInfo::InitInfo permissions_to_register[] = { + {extensions::APIPermission::kArcAppsPrivate, "arcAppsPrivate"}, + {extensions::APIPermission::kBrowser, "browser"}, + {extensions::APIPermission::kFirstRunPrivate, "firstRunPrivate", + extensions::APIPermissionInfo::kFlagCannotBeOptional}, + {extensions::APIPermission::kMusicManagerPrivate, "musicManagerPrivate", + extensions::APIPermissionInfo::kFlagCannotBeOptional}, + {extensions::APIPermission::kMediaGalleries, "mediaGalleries", + extensions::APIPermissionInfo::kFlagNone, + &CreateAPIPermission<chrome_apps::MediaGalleriesPermission>}, + {extensions::APIPermission::kPointerLock, "pointerLock"}, + {extensions::APIPermission::kSyncFileSystem, "syncFileSystem"}, + {extensions::APIPermission::kWebstoreWidgetPrivate, "webstoreWidgetPrivate", + extensions::APIPermissionInfo::kFlagCannotBeOptional}, +}; + +} // namespace + +base::span<const extensions::APIPermissionInfo::InitInfo> GetPermissionInfos() { + return base::make_span(permissions_to_register); +} + +} // namespace chrome_apps_api_permissions diff --git a/chromium/chrome/common/apps/platform_apps/chrome_apps_api_permissions.h b/chromium/chrome/common/apps/platform_apps/chrome_apps_api_permissions.h new file mode 100644 index 00000000000..eec3cad6d55 --- /dev/null +++ b/chromium/chrome/common/apps/platform_apps/chrome_apps_api_permissions.h @@ -0,0 +1,19 @@ +// Copyright 2018 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. + +#ifndef CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_API_PERMISSIONS_H_ +#define CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_API_PERMISSIONS_H_ + +#include "base/containers/span.h" +#include "extensions/common/permissions/api_permission.h" + +namespace chrome_apps_api_permissions { + +// Returns the information necessary to construct Chrome app-specific +// APIPermissions. +base::span<const extensions::APIPermissionInfo::InitInfo> GetPermissionInfos(); + +} // namespace chrome_apps_api_permissions + +#endif // CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_API_PERMISSIONS_H_ diff --git a/chromium/chrome/common/apps/platform_apps/chrome_apps_api_provider.cc b/chromium/chrome/common/apps/platform_apps/chrome_apps_api_provider.cc new file mode 100644 index 00000000000..1f7de94c949 --- /dev/null +++ b/chromium/chrome/common/apps/platform_apps/chrome_apps_api_provider.cc @@ -0,0 +1,65 @@ +// Copyright 2018 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 "chrome/common/apps/platform_apps/chrome_apps_api_provider.h" + +#include "chrome/common/apps/platform_apps/api/api_features.h" +#include "chrome/common/apps/platform_apps/api/generated_schemas.h" +#include "chrome/common/apps/platform_apps/api/permission_features.h" +#include "chrome/common/apps/platform_apps/chrome_apps_api_permissions.h" +#include "chrome/grit/common_resources.h" +#include "extensions/common/alias.h" +#include "extensions/common/features/json_feature_provider_source.h" +#include "extensions/common/permissions/permissions_info.h" + +namespace chrome_apps { + +ChromeAppsAPIProvider::ChromeAppsAPIProvider() {} +ChromeAppsAPIProvider::~ChromeAppsAPIProvider() = default; + +void ChromeAppsAPIProvider::AddAPIFeatures( + extensions::FeatureProvider* provider) { + AddChromeAppsAPIFeatures(provider); +} + +void ChromeAppsAPIProvider::AddManifestFeatures( + extensions::FeatureProvider* provider) { + // No Chrome-apps-specific manifest features (yet). +} + +void ChromeAppsAPIProvider::AddPermissionFeatures( + extensions::FeatureProvider* provider) { + AddChromeAppsPermissionFeatures(provider); +} + +void ChromeAppsAPIProvider::AddBehaviorFeatures( + extensions::FeatureProvider* provider) { + // No Chrome-apps-specific manifest features. +} + +void ChromeAppsAPIProvider::AddAPIJSONSources( + extensions::JSONFeatureProviderSource* json_source) { + json_source->LoadJSON(IDR_CHROME_APP_API_FEATURES); +} + +bool ChromeAppsAPIProvider::IsAPISchemaGenerated(const std::string& name) { + return api::ChromeAppsGeneratedSchemas::IsGenerated(name); +} + +base::StringPiece ChromeAppsAPIProvider::GetAPISchema(const std::string& name) { + return api::ChromeAppsGeneratedSchemas::Get(name); +} + +void ChromeAppsAPIProvider::RegisterPermissions( + extensions::PermissionsInfo* permissions_info) { + permissions_info->RegisterPermissions( + chrome_apps_api_permissions::GetPermissionInfos(), + base::span<const extensions::Alias>()); +} + +void ChromeAppsAPIProvider::RegisterManifestHandlers() { + // No apps-specific manifest handlers (yet). +} + +} // namespace chrome_apps diff --git a/chromium/chrome/common/apps/platform_apps/chrome_apps_api_provider.h b/chromium/chrome/common/apps/platform_apps/chrome_apps_api_provider.h new file mode 100644 index 00000000000..b5312b85422 --- /dev/null +++ b/chromium/chrome/common/apps/platform_apps/chrome_apps_api_provider.h @@ -0,0 +1,36 @@ +// Copyright 2018 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. + +#ifndef CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_API_PROVIDER_H_ +#define CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_API_PROVIDER_H_ + +#include "extensions/common/extensions_api_provider.h" + +namespace chrome_apps { + +class ChromeAppsAPIProvider : public extensions::ExtensionsAPIProvider { + public: + ChromeAppsAPIProvider(); + ~ChromeAppsAPIProvider() override; + + // ExtensionsAPIProvider: + void AddAPIFeatures(extensions::FeatureProvider* provider) override; + void AddManifestFeatures(extensions::FeatureProvider* provider) override; + void AddPermissionFeatures(extensions::FeatureProvider* provider) override; + void AddBehaviorFeatures(extensions::FeatureProvider* provider) override; + void AddAPIJSONSources( + extensions::JSONFeatureProviderSource* json_source) override; + bool IsAPISchemaGenerated(const std::string& name) override; + base::StringPiece GetAPISchema(const std::string& name) override; + void RegisterPermissions( + extensions::PermissionsInfo* permissions_info) override; + void RegisterManifestHandlers() override; + + private: + DISALLOW_COPY_AND_ASSIGN(ChromeAppsAPIProvider); +}; + +} // namespace chrome_apps + +#endif // CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_API_PROVIDER_H_ diff --git a/chromium/chrome/common/apps/platform_apps/chrome_apps_message_generator.cc b/chromium/chrome/common/apps/platform_apps/chrome_apps_message_generator.cc new file mode 100644 index 00000000000..e22ff4b8edd --- /dev/null +++ b/chromium/chrome/common/apps/platform_apps/chrome_apps_message_generator.cc @@ -0,0 +1,30 @@ +// Copyright 2018 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. + +// Get basic type definitions. +#define IPC_MESSAGE_IMPL +#include "chrome/common/apps/platform_apps/chrome_apps_message_generator.h" + +// Generate constructors. +#include "ipc/struct_constructor_macros.h" +#include "chrome/common/apps/platform_apps/chrome_apps_message_generator.h" + +// Generate param traits write methods. +#include "ipc/param_traits_write_macros.h" +namespace IPC { +#include "chrome/common/apps/platform_apps/chrome_apps_message_generator.h" +} // namespace IPC + +// Generate param traits read methods. +#include "ipc/param_traits_read_macros.h" +namespace IPC { +#include "chrome/common/apps/platform_apps/chrome_apps_message_generator.h" +} // namespace IPC + +// Generate param traits log methods. +#include "ipc/param_traits_log_macros.h" +namespace IPC { +#include "chrome/common/apps/platform_apps/chrome_apps_message_generator.h" +} // namespace IPC + diff --git a/chromium/chrome/common/apps/platform_apps/chrome_apps_message_generator.h b/chromium/chrome/common/apps/platform_apps/chrome_apps_message_generator.h new file mode 100644 index 00000000000..1903b73d9b5 --- /dev/null +++ b/chromium/chrome/common/apps/platform_apps/chrome_apps_message_generator.h @@ -0,0 +1,11 @@ +// Copyright 2018 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. + +// Multiply-included file, hence no include guard. + +#undef CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_MESSAGES_H_ +#include "chrome/common/apps/platform_apps/chrome_apps_messages.h" +#ifndef CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_MESSAGES_H_ +#error "Failed to include header chrome/common/apps/platform_apps/chrome_apps_messages.h" +#endif diff --git a/chromium/chrome/common/apps/platform_apps/chrome_apps_messages.h b/chromium/chrome/common/apps/platform_apps/chrome_apps_messages.h new file mode 100644 index 00000000000..f8138b4fc56 --- /dev/null +++ b/chromium/chrome/common/apps/platform_apps/chrome_apps_messages.h @@ -0,0 +1,15 @@ +// Copyright 2018 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. + +#ifndef CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_MESSAGES_H_ +#define CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_MESSAGES_H_ + +#include "chrome/common/apps/platform_apps/media_galleries_permission_data.h" +#include "ipc/ipc_message_macros.h" + +IPC_STRUCT_TRAITS_BEGIN(chrome_apps::MediaGalleriesPermissionData) + IPC_STRUCT_TRAITS_MEMBER(permission()) +IPC_STRUCT_TRAITS_END() + +#endif // CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_MESSAGES_H_ diff --git a/chromium/chrome/common/apps/platform_apps/media_galleries_permission.cc b/chromium/chrome/common/apps/platform_apps/media_galleries_permission.cc new file mode 100644 index 00000000000..372145687f4 --- /dev/null +++ b/chromium/chrome/common/apps/platform_apps/media_galleries_permission.cc @@ -0,0 +1,157 @@ +// 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 "chrome/common/apps/platform_apps/media_galleries_permission.h" + +#include <stddef.h> + +#include <set> +#include <string> + +#include "base/logging.h" +#include "base/strings/utf_string_conversions.h" +#include "extensions/common/permissions/permissions_info.h" +#include "ui/base/l10n/l10n_util.h" + +namespace chrome_apps { + +namespace { + +// copyTo permission requires delete permission as a prerequisite. +// delete permission requires read permission as a prerequisite. +bool IsValidPermissionSet(bool has_read, + bool has_copy_to, + bool has_delete, + std::string* error) { + if (has_copy_to) { + if (has_read && has_delete) + return true; + if (error) + *error = "copyTo permission requires read and delete permissions"; + return false; + } + if (has_delete) { + if (has_read) + return true; + if (error) + *error = "delete permission requires read permission"; + return false; + } + return true; +} + +} // namespace + +const char MediaGalleriesPermission::kAllAutoDetectedPermission[] = + "allAutoDetected"; +const char MediaGalleriesPermission::kReadPermission[] = "read"; +const char MediaGalleriesPermission::kCopyToPermission[] = "copyTo"; +const char MediaGalleriesPermission::kDeletePermission[] = "delete"; + +MediaGalleriesPermission::MediaGalleriesPermission( + const extensions::APIPermissionInfo* info) + : SetDisjunctionPermission<MediaGalleriesPermissionData, + MediaGalleriesPermission>(info) {} + +MediaGalleriesPermission::~MediaGalleriesPermission() {} + +bool MediaGalleriesPermission::FromValue( + const base::Value* value, + std::string* error, + std::vector<std::string>* unhandled_permissions) { + size_t unhandled_permissions_count = 0; + if (unhandled_permissions) + unhandled_permissions_count = unhandled_permissions->size(); + bool parsed_ok = SetDisjunctionPermission< + MediaGalleriesPermissionData, + MediaGalleriesPermission>::FromValue(value, error, unhandled_permissions); + if (unhandled_permissions) { + for (size_t i = unhandled_permissions_count; + i < unhandled_permissions->size(); i++) { + (*unhandled_permissions)[i] = + "{\"mediaGalleries\": [" + (*unhandled_permissions)[i] + "]}"; + } + } + if (!parsed_ok) + return false; + + bool has_read = false; + bool has_copy_to = false; + bool has_delete = false; + for (auto it = data_set_.cbegin(); it != data_set_.cend(); ++it) { + if (it->permission() == kAllAutoDetectedPermission) { + continue; + } + if (it->permission() == kReadPermission) { + has_read = true; + continue; + } + if (it->permission() == kCopyToPermission) { + has_copy_to = true; + continue; + } + if (it->permission() == kDeletePermission) { + has_delete = true; + continue; + } + + // No other permissions, so reaching this means + // MediaGalleriesPermissionData is probably out of sync in some way. + // Fail so developers notice this. + NOTREACHED(); + return false; + } + + return IsValidPermissionSet(has_read, has_copy_to, has_delete, error); +} + +extensions::PermissionIDSet MediaGalleriesPermission::GetPermissions() const { + extensions::PermissionIDSet result; + + bool has_all_auto_detected = false; + bool has_read = false; + bool has_copy_to = false; + bool has_delete = false; + + for (const MediaGalleriesPermissionData& data : data_set_) { + if (data.permission() == kAllAutoDetectedPermission) + has_all_auto_detected = true; + else if (data.permission() == kReadPermission) + has_read = true; + else if (data.permission() == kCopyToPermission) + has_copy_to = true; + else if (data.permission() == kDeletePermission) + has_delete = true; + } + + if (!IsValidPermissionSet(has_read, has_copy_to, has_delete, nullptr)) { + NOTREACHED(); + return result; + } + + // If |has_all_auto_detected| is false, then Chrome will prompt the user at + // runtime when the extension calls the getMediaGalleries API. + if (!has_all_auto_detected) + return result; + // No access permission case. + if (!has_read) + return result; + + // Separate PermissionMessage IDs for read, copyTo, and delete. Otherwise an + // extension can silently gain new access capabilities. + result.insert(extensions::APIPermission::kMediaGalleriesAllGalleriesRead); + + // For copyTo and delete, the proper combined permission message will be + // derived in ChromePermissionMessageProvider::GetWarningMessages(), such + // that the user get 1 entry for all media galleries access permissions, + // rather than several separate entries. + if (has_copy_to) + result.insert(extensions::APIPermission::kMediaGalleriesAllGalleriesCopyTo); + if (has_delete) + result.insert(extensions::APIPermission::kMediaGalleriesAllGalleriesDelete); + + return result; +} + +} // namespace chrome_apps diff --git a/chromium/chrome/common/apps/platform_apps/media_galleries_permission.h b/chromium/chrome/common/apps/platform_apps/media_galleries_permission.h new file mode 100644 index 00000000000..c5792fdab85 --- /dev/null +++ b/chromium/chrome/common/apps/platform_apps/media_galleries_permission.h @@ -0,0 +1,63 @@ +// 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. + +#ifndef CHROME_COMMON_APPS_PLATFORM_APPS_MEDIA_GALLERIES_PERMISSION_H_ +#define CHROME_COMMON_APPS_PLATFORM_APPS_MEDIA_GALLERIES_PERMISSION_H_ + +#include "chrome/common/apps/platform_apps/chrome_apps_messages.h" +#include "chrome/common/apps/platform_apps/media_galleries_permission_data.h" +#include "extensions/common/permissions/api_permission.h" +#include "extensions/common/permissions/set_disjunction_permission.h" + +namespace chrome_apps { + +// Media Galleries permissions are as follows: +// <media-galleries-permission-pattern> +// := <access> | <access> 'allAutoDetected' | 'allAutoDetected' | +// <access> 'scan' | 'scan' +// <access> := 'read' | 'read' <access> | 'read' <secondary-access> +// <secondary-access> +// := 'delete' | 'delete' <secondary-access> | +// 'delete' <tertiary-access> +// <tertiary-access> +// := 'copyTo' | 'copyTo' <tertiary-access> +// An example of a line for mediaGalleries permissions in a manifest file: +// {"mediaGalleries": "read delete"}, +// We also allow a permission without any sub-permissions: +// "mediaGalleries", +// TODO(devlin): Move this class to chrome/common/apps/platform_apps. +class MediaGalleriesPermission + : public extensions::SetDisjunctionPermission<MediaGalleriesPermissionData, + MediaGalleriesPermission> { + public: + struct CheckParam : public extensions::APIPermission::CheckParam { + explicit CheckParam(const std::string& permission) + : permission(permission) {} + const std::string permission; + }; + + explicit MediaGalleriesPermission(const extensions::APIPermissionInfo* info); + ~MediaGalleriesPermission() override; + + // SetDisjunctionPermission overrides. + // MediaGalleriesPermission does additional checks to make sure the + // permissions do not contain unknown values. + bool FromValue(const base::Value* value, + std::string* error, + std::vector<std::string>* unhandled_permissions) override; + + // extensions::APIPermission overrides. + extensions::PermissionIDSet GetPermissions() const override; + + // Permission strings. + static const char kAllAutoDetectedPermission[]; + static const char kScanPermission[]; + static const char kReadPermission[]; + static const char kCopyToPermission[]; + static const char kDeletePermission[]; +}; + +} // namespace chrome_apps + +#endif // CHROME_COMMON_APPS_PLATFORM_APPS_MEDIA_GALLERIES_PERMISSION_H_ diff --git a/chromium/chrome/common/apps/platform_apps/media_galleries_permission_data.cc b/chromium/chrome/common/apps/platform_apps/media_galleries_permission_data.cc new file mode 100644 index 00000000000..148abbac461 --- /dev/null +++ b/chromium/chrome/common/apps/platform_apps/media_galleries_permission_data.cc @@ -0,0 +1,60 @@ +// 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 "chrome/common/apps/platform_apps/media_galleries_permission_data.h" + +#include "base/strings/string_util.h" +#include "base/values.h" +#include "chrome/common/apps/platform_apps/media_galleries_permission.h" + +namespace chrome_apps { + +MediaGalleriesPermissionData::MediaGalleriesPermissionData() {} + +bool MediaGalleriesPermissionData::Check( + const extensions::APIPermission::CheckParam* param) const { + if (!param) + return false; + + const MediaGalleriesPermission::CheckParam& specific_param = + *static_cast<const MediaGalleriesPermission::CheckParam*>(param); + return permission_ == specific_param.permission; +} + +std::unique_ptr<base::Value> MediaGalleriesPermissionData::ToValue() const { + return std::make_unique<base::Value>(permission_); +} + +bool MediaGalleriesPermissionData::FromValue(const base::Value* value) { + if (!value) + return false; + + std::string raw_permission; + if (!value->GetAsString(&raw_permission)) + return false; + + std::string permission; + base::TrimWhitespaceASCII(raw_permission, base::TRIM_ALL, &permission); + + if (permission == MediaGalleriesPermission::kAllAutoDetectedPermission || + permission == MediaGalleriesPermission::kReadPermission || + permission == MediaGalleriesPermission::kCopyToPermission || + permission == MediaGalleriesPermission::kDeletePermission) { + permission_ = permission; + return true; + } + return false; +} + +bool MediaGalleriesPermissionData::operator<( + const MediaGalleriesPermissionData& rhs) const { + return permission_ < rhs.permission_; +} + +bool MediaGalleriesPermissionData::operator==( + const MediaGalleriesPermissionData& rhs) const { + return permission_ == rhs.permission_; +} + +} // namespace chrome_apps diff --git a/chromium/chrome/common/apps/platform_apps/media_galleries_permission_data.h b/chromium/chrome/common/apps/platform_apps/media_galleries_permission_data.h new file mode 100644 index 00000000000..495cb48d4be --- /dev/null +++ b/chromium/chrome/common/apps/platform_apps/media_galleries_permission_data.h @@ -0,0 +1,50 @@ +// 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. + +#ifndef CHROME_COMMON_APPS_PLATFORM_APPS_MEDIA_GALLERIES_PERMISSION_DATA_H_ +#define CHROME_COMMON_APPS_PLATFORM_APPS_MEDIA_GALLERIES_PERMISSION_DATA_H_ + +#include <memory> +#include <string> + +#include "extensions/common/permissions/api_permission.h" + +namespace base { +class Value; +} + +namespace chrome_apps { + +// A MediaGalleriesPermissionData instance represents a single part of the +// MediaGalleriesPermission. e.g. "read" or "allAutoDetected". +class MediaGalleriesPermissionData { + public: + MediaGalleriesPermissionData(); + + // Check if |param| (which must be a MediaGalleriesPermission::CheckParam) + // matches the encapsulated attribute. + bool Check(const extensions::APIPermission::CheckParam* param) const; + + // Convert |this| into a base::Value. + std::unique_ptr<base::Value> ToValue() const; + + // Populate |this| from a base::Value. + bool FromValue(const base::Value* value); + + bool operator<(const MediaGalleriesPermissionData& rhs) const; + bool operator==(const MediaGalleriesPermissionData& rhs) const; + + std::string permission() const { return permission_; } + + // This accessor is provided for IPC_STRUCT_TRAITS_MEMBER. Please think + // twice before using it for anything else. + std::string& permission() { return permission_; } + + private: + std::string permission_; +}; + +} // namespace chrome_apps + +#endif // CHROME_COMMON_APPS_PLATFORM_APPS_MEDIA_GALLERIES_PERMISSION_DATA_H_ diff --git a/chromium/chrome/common/apps/platform_apps/media_galleries_permission_unittest.cc b/chromium/chrome/common/apps/platform_apps/media_galleries_permission_unittest.cc new file mode 100644 index 00000000000..d8fbc24b8be --- /dev/null +++ b/chromium/chrome/common/apps/platform_apps/media_galleries_permission_unittest.cc @@ -0,0 +1,304 @@ +// Copyright (c) 2013 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. + +// These tests make sure MediaGalleriesPermission values are parsed correctly. + +#include <memory> + +#include "base/values.h" +#include "chrome/common/apps/platform_apps/media_galleries_permission.h" +#include "chrome/common/apps/platform_apps/media_galleries_permission_data.h" +#include "extensions/common/permissions/api_permission.h" +#include "extensions/common/permissions/permissions_info.h" +#include "testing/gtest/include/gtest/gtest.h" + +using content::SocketPermissionRequest; +using extensions::SocketPermissionData; + +namespace chrome_apps { + +namespace { + +void CheckFromValue(extensions::APIPermission* permission, + base::ListValue* value, + bool success_expected) { + std::string error; + std::vector<std::string> unhandled; + EXPECT_EQ(success_expected, permission->FromValue(value, &error, &unhandled)); + EXPECT_EQ(success_expected, error.empty()); + EXPECT_TRUE(unhandled.empty()); +} + +TEST(MediaGalleriesPermissionTest, GoodValues) { + const extensions::APIPermissionInfo* permission_info = + extensions::PermissionsInfo::GetInstance()->GetByID( + extensions::APIPermission::kMediaGalleries); + + std::unique_ptr<extensions::APIPermission> permission( + permission_info->CreateAPIPermission()); + + // access_type + all_detected + std::unique_ptr<base::ListValue> value(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission); + value->AppendString(MediaGalleriesPermission::kReadPermission); + CheckFromValue(permission.get(), value.get(), true); + + value.reset(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission); + value->AppendString(MediaGalleriesPermission::kCopyToPermission); + value->AppendString(MediaGalleriesPermission::kReadPermission); + value->AppendString(MediaGalleriesPermission::kDeletePermission); + CheckFromValue(permission.get(), value.get(), true); + + // all_detected + value.reset(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission); + CheckFromValue(permission.get(), value.get(), true); + + // access_type + value.reset(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kReadPermission); + CheckFromValue(permission.get(), value.get(), true); + + value.reset(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kDeletePermission); + value->AppendString(MediaGalleriesPermission::kReadPermission); + CheckFromValue(permission.get(), value.get(), true); + + value.reset(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kCopyToPermission); + value->AppendString(MediaGalleriesPermission::kDeletePermission); + value->AppendString(MediaGalleriesPermission::kReadPermission); + CheckFromValue(permission.get(), value.get(), true); + + // Repeats do not make a difference. + value.reset(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission); + value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission); + CheckFromValue(permission.get(), value.get(), true); + + value.reset(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission); + value->AppendString(MediaGalleriesPermission::kReadPermission); + value->AppendString(MediaGalleriesPermission::kReadPermission); + value->AppendString(MediaGalleriesPermission::kDeletePermission); + value->AppendString(MediaGalleriesPermission::kDeletePermission); + value->AppendString(MediaGalleriesPermission::kDeletePermission); + CheckFromValue(permission.get(), value.get(), true); +} + +TEST(MediaGalleriesPermissionTest, BadValues) { + const extensions::APIPermissionInfo* permission_info = + extensions::PermissionsInfo::GetInstance()->GetByID( + extensions::APIPermission::kMediaGalleries); + + std::unique_ptr<extensions::APIPermission> permission( + permission_info->CreateAPIPermission()); + + // copyTo and delete without read + std::unique_ptr<base::ListValue> value(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kCopyToPermission); + CheckFromValue(permission.get(), value.get(), false); + + value.reset(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kDeletePermission); + CheckFromValue(permission.get(), value.get(), false); + + value.reset(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission); + value->AppendString(MediaGalleriesPermission::kCopyToPermission); + value->AppendString(MediaGalleriesPermission::kDeletePermission); + CheckFromValue(permission.get(), value.get(), false); + + // copyTo without delete + value.reset(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission); + value->AppendString(MediaGalleriesPermission::kCopyToPermission); + value->AppendString(MediaGalleriesPermission::kReadPermission); + CheckFromValue(permission.get(), value.get(), false); + + // Repeats do not make a difference. + value.reset(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kCopyToPermission); + value->AppendString(MediaGalleriesPermission::kCopyToPermission); + CheckFromValue(permission.get(), value.get(), false); + + value.reset(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission); + value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission); + value->AppendString(MediaGalleriesPermission::kCopyToPermission); + value->AppendString(MediaGalleriesPermission::kDeletePermission); + value->AppendString(MediaGalleriesPermission::kDeletePermission); + CheckFromValue(permission.get(), value.get(), false); +} + +TEST(MediaGalleriesPermissionTest, UnknownValues) { + std::string error; + std::vector<std::string> unhandled; + const extensions::APIPermissionInfo* permission_info = + extensions::PermissionsInfo::GetInstance()->GetByID( + extensions::APIPermission::kMediaGalleries); + + std::unique_ptr<extensions::APIPermission> permission( + permission_info->CreateAPIPermission()); + + // A good one and an unknown one. + std::unique_ptr<base::ListValue> value(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kReadPermission); + value->AppendString("Unknown"); + EXPECT_TRUE(permission->FromValue(value.get(), &error, &unhandled)); + EXPECT_TRUE(error.empty()); + EXPECT_EQ(1U, unhandled.size()); + error.clear(); + unhandled.clear(); + + // Multiple unknown permissions. + value.reset(new base::ListValue()); + value->AppendString("Unknown1"); + value->AppendString("Unknown2"); + EXPECT_TRUE(permission->FromValue(value.get(), &error, &unhandled)); + EXPECT_TRUE(error.empty()); + EXPECT_EQ(2U, unhandled.size()); + error.clear(); + unhandled.clear(); + + // Unnknown with a NULL argument. + value.reset(new base::ListValue()); + value->AppendString("Unknown1"); + EXPECT_FALSE(permission->FromValue(value.get(), &error, NULL)); + EXPECT_FALSE(error.empty()); + error.clear(); +} + +TEST(MediaGalleriesPermissionTest, Equal) { + const extensions::APIPermissionInfo* permission_info = + extensions::PermissionsInfo::GetInstance()->GetByID( + extensions::APIPermission::kMediaGalleries); + + std::unique_ptr<extensions::APIPermission> permission1( + permission_info->CreateAPIPermission()); + std::unique_ptr<extensions::APIPermission> permission2( + permission_info->CreateAPIPermission()); + + std::unique_ptr<base::ListValue> value(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission); + value->AppendString(MediaGalleriesPermission::kReadPermission); + ASSERT_TRUE(permission1->FromValue(value.get(), NULL, NULL)); + + value.reset(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kReadPermission); + value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission); + ASSERT_TRUE(permission2->FromValue(value.get(), NULL, NULL)); + EXPECT_TRUE(permission1->Equal(permission2.get())); + + value.reset(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kReadPermission); + value->AppendString(MediaGalleriesPermission::kReadPermission); + value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission); + ASSERT_TRUE(permission2->FromValue(value.get(), NULL, NULL)); + EXPECT_TRUE(permission1->Equal(permission2.get())); + + value.reset(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kReadPermission); + value->AppendString(MediaGalleriesPermission::kDeletePermission); + ASSERT_TRUE(permission1->FromValue(value.get(), NULL, NULL)); + + value.reset(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kDeletePermission); + value->AppendString(MediaGalleriesPermission::kReadPermission); + ASSERT_TRUE(permission2->FromValue(value.get(), NULL, NULL)); + EXPECT_TRUE(permission1->Equal(permission2.get())); + + value.reset(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kReadPermission); + value->AppendString(MediaGalleriesPermission::kCopyToPermission); + value->AppendString(MediaGalleriesPermission::kDeletePermission); + ASSERT_TRUE(permission1->FromValue(value.get(), NULL, NULL)); + + value.reset(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kDeletePermission); + value->AppendString(MediaGalleriesPermission::kCopyToPermission); + value->AppendString(MediaGalleriesPermission::kReadPermission); + ASSERT_TRUE(permission2->FromValue(value.get(), NULL, NULL)); + EXPECT_TRUE(permission1->Equal(permission2.get())); +} + +TEST(MediaGalleriesPermissionTest, NotEqual) { + const extensions::APIPermissionInfo* permission_info = + extensions::PermissionsInfo::GetInstance()->GetByID( + extensions::APIPermission::kMediaGalleries); + + std::unique_ptr<extensions::APIPermission> permission1( + permission_info->CreateAPIPermission()); + std::unique_ptr<extensions::APIPermission> permission2( + permission_info->CreateAPIPermission()); + + std::unique_ptr<base::ListValue> value(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission); + value->AppendString(MediaGalleriesPermission::kReadPermission); + ASSERT_TRUE(permission1->FromValue(value.get(), NULL, NULL)); + + value.reset(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission); + value->AppendString(MediaGalleriesPermission::kReadPermission); + value->AppendString(MediaGalleriesPermission::kDeletePermission); + value->AppendString(MediaGalleriesPermission::kCopyToPermission); + ASSERT_TRUE(permission2->FromValue(value.get(), NULL, NULL)); + EXPECT_FALSE(permission1->Equal(permission2.get())); +} + +TEST(MediaGalleriesPermissionTest, ToFromValue) { + const extensions::APIPermissionInfo* permission_info = + extensions::PermissionsInfo::GetInstance()->GetByID( + extensions::APIPermission::kMediaGalleries); + + std::unique_ptr<extensions::APIPermission> permission1( + permission_info->CreateAPIPermission()); + std::unique_ptr<extensions::APIPermission> permission2( + permission_info->CreateAPIPermission()); + + std::unique_ptr<base::ListValue> value(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission); + value->AppendString(MediaGalleriesPermission::kReadPermission); + ASSERT_TRUE(permission1->FromValue(value.get(), NULL, NULL)); + + std::unique_ptr<base::Value> vtmp(permission1->ToValue()); + ASSERT_TRUE(vtmp); + ASSERT_TRUE(permission2->FromValue(vtmp.get(), NULL, NULL)); + EXPECT_TRUE(permission1->Equal(permission2.get())); + + value.reset(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kReadPermission); + value->AppendString(MediaGalleriesPermission::kDeletePermission); + value->AppendString(MediaGalleriesPermission::kCopyToPermission); + ASSERT_TRUE(permission1->FromValue(value.get(), NULL, NULL)); + + vtmp = permission1->ToValue(); + ASSERT_TRUE(vtmp); + ASSERT_TRUE(permission2->FromValue(vtmp.get(), NULL, NULL)); + EXPECT_TRUE(permission1->Equal(permission2.get())); + + value.reset(new base::ListValue()); + value->AppendString(MediaGalleriesPermission::kReadPermission); + value->AppendString(MediaGalleriesPermission::kDeletePermission); + ASSERT_TRUE(permission1->FromValue(value.get(), NULL, NULL)); + + vtmp = permission1->ToValue(); + ASSERT_TRUE(vtmp); + ASSERT_TRUE(permission2->FromValue(vtmp.get(), NULL, NULL)); + EXPECT_TRUE(permission1->Equal(permission2.get())); + + value.reset(new base::ListValue()); + // without sub-permission + ASSERT_TRUE(permission1->FromValue(NULL, NULL, NULL)); + + vtmp = permission1->ToValue(); + ASSERT_TRUE(vtmp); + ASSERT_TRUE(permission2->FromValue(vtmp.get(), NULL, NULL)); + EXPECT_TRUE(permission1->Equal(permission2.get())); +} + +} // namespace + +} // namespace chrome_apps |