168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// found in the LICENSE file.
468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "extensions/common/permissions/media_galleries_permission.h"
668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include <set>
868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include <string>
968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
1068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "base/logging.h"
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/common/permissions/permissions_info.h"
1368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "grit/extensions_strings.h"
1468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
1568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace {
1768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
1868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// copyTo permission requires delete permission as a prerequisite.
1968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// delete permission requires read permission as a prerequisite.
2068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)bool IsValidPermissionSet(bool has_read, bool has_copy_to, bool has_delete,
2168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                          std::string* error) {
2268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (has_copy_to) {
2368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (has_read && has_delete)
2468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      return true;
2568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (error)
2668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      *error = "copyTo permission requires read and delete permissions";
2768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return false;
2868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
2968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (has_delete) {
3068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (has_read)
3168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      return true;
3268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (error)
3368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      *error = "delete permission requires read permission";
3468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return false;
3568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
3668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return true;
3768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
3868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
3968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}  // namespace
4068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
4168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)namespace extensions {
4268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
4368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char MediaGalleriesPermission::kAllAutoDetectedPermission[] =
4468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "allAutoDetected";
4568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char MediaGalleriesPermission::kScanPermission[] = "scan";
4668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char MediaGalleriesPermission::kReadPermission[] = "read";
4768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char MediaGalleriesPermission::kCopyToPermission[] = "copyTo";
4868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char MediaGalleriesPermission::kDeletePermission[] = "delete";
4968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
5068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)MediaGalleriesPermission::MediaGalleriesPermission(
5168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const APIPermissionInfo* info)
5268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  : SetDisjunctionPermission<MediaGalleriesPermissionData,
5368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                             MediaGalleriesPermission>(info) {
5468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
5568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
5668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)MediaGalleriesPermission::~MediaGalleriesPermission() {
5768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
5868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
5968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)bool MediaGalleriesPermission::FromValue(
6068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const base::Value* value,
6168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    std::string* error,
6268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    std::vector<std::string>* unhandled_permissions) {
6368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  size_t unhandled_permissions_count = 0;
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (unhandled_permissions)
6568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    unhandled_permissions_count = unhandled_permissions->size();
6668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  bool parsed_ok =
6768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      SetDisjunctionPermission<MediaGalleriesPermissionData,
6868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                               MediaGalleriesPermission>::FromValue(
6968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                   value, error, unhandled_permissions);
7068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (unhandled_permissions) {
7168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    for (size_t i = unhandled_permissions_count;
7268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)         i < unhandled_permissions->size();
7368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)         i++) {
7468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      (*unhandled_permissions)[i] =
7568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          "{\"mediaGalleries\": [" + (*unhandled_permissions)[i] + "]}";
7668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
7768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
7868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!parsed_ok)
7968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return false;
8068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
8168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  bool has_read = false;
8268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  bool has_copy_to = false;
8368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  bool has_delete = false;
84  for (std::set<MediaGalleriesPermissionData>::const_iterator it =
85      data_set_.begin(); it != data_set_.end(); ++it) {
86    if (it->permission() == kAllAutoDetectedPermission ||
87        it->permission() == kScanPermission) {
88      continue;
89    }
90    if (it->permission() == kReadPermission) {
91      has_read = true;
92      continue;
93    }
94    if (it->permission() == kCopyToPermission) {
95      has_copy_to = true;
96      continue;
97    }
98    if (it->permission() == kDeletePermission) {
99      has_delete = true;
100      continue;
101    }
102
103    // No other permissions, so reaching this means
104    // MediaGalleriesPermissionData is probably out of sync in some way.
105    // Fail so developers notice this.
106    NOTREACHED();
107    return false;
108  }
109
110  return IsValidPermissionSet(has_read, has_copy_to, has_delete, error);
111}
112
113PermissionMessages MediaGalleriesPermission::GetMessages() const {
114  DCHECK(HasMessages());
115  PermissionMessages result;
116
117  bool has_all_auto_detected = false;
118  bool has_read = false;
119  bool has_copy_to = false;
120  bool has_delete = false;
121
122  for (std::set<MediaGalleriesPermissionData>::const_iterator it =
123      data_set_.begin(); it != data_set_.end(); ++it) {
124    if (it->permission() == kAllAutoDetectedPermission)
125      has_all_auto_detected = true;
126    else if (it->permission() == kReadPermission)
127      has_read = true;
128    else if (it->permission() == kCopyToPermission)
129      has_copy_to = true;
130    else if (it->permission() == kDeletePermission)
131      has_delete = true;
132  }
133
134  if (!IsValidPermissionSet(has_read, has_copy_to, has_delete, NULL)) {
135    NOTREACHED();
136    return result;
137  }
138
139  // If |has_all_auto_detected| is false, then Chrome will prompt the user at
140  // runtime when the extension call the getMediaGalleries API.
141  if (!has_all_auto_detected)
142    return result;
143  // No access permission case.
144  if (!has_read)
145    return result;
146
147  // Separate PermissionMessage IDs for read, copyTo, and delete. Otherwise an
148  // extension can silently gain new access capabilities.
149  result.push_back(PermissionMessage(
150      PermissionMessage::kMediaGalleriesAllGalleriesRead,
151      l10n_util::GetStringUTF16(
152          IDS_EXTENSION_PROMPT_WARNING_MEDIA_GALLERIES_READ)));
153
154  // For copyTo and delete, the proper combined permission message will be
155  // derived in ChromePermissionMessageProvider::GetWarningMessages(), such
156  // that the user get 1 entry for all media galleries access permissions,
157  // rather than several separate entries.
158  if (has_copy_to) {
159    result.push_back(PermissionMessage(
160        PermissionMessage::kMediaGalleriesAllGalleriesCopyTo,
161        base::string16()));
162  }
163  if (has_delete) {
164    result.push_back(PermissionMessage(
165        PermissionMessage::kMediaGalleriesAllGalleriesDelete,
166        base::string16()));
167  }
168  return result;
169}
170
171}  // namespace extensions
172