1 // Copyright 2014 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 #include "extensions/common/manifest_handlers/webview_info.h"
6
7 #include "base/memory/scoped_ptr.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/values.h"
12 #include "extensions/common/error_utils.h"
13 #include "extensions/common/manifest.h"
14 #include "extensions/common/manifest_constants.h"
15
16 namespace extensions {
17
18 namespace keys = extensions::manifest_keys;
19 namespace errors = extensions::manifest_errors;
20
21 namespace {
22
GetResourcesInfo(const Extension & extension)23 const WebviewInfo* GetResourcesInfo(
24 const Extension& extension) {
25 return static_cast<WebviewInfo*>(
26 extension.GetManifestData(keys::kWebviewAccessibleResources));
27 }
28
29 } // namespace
30
31 // A PartitionItem represents a set of accessible resources given a partition
32 // ID pattern.
33 class PartitionItem {
34 public:
PartitionItem(const std::string & partition_pattern)35 explicit PartitionItem(const std::string& partition_pattern)
36 : partition_pattern_(partition_pattern) {
37 }
38
~PartitionItem()39 virtual ~PartitionItem() {
40 }
41
Matches(const std::string & partition_id) const42 bool Matches(const std::string& partition_id) const {
43 return MatchPattern(partition_id, partition_pattern_);
44 }
45
46 // Adds a pattern to the set. Returns true if a new pattern was inserted,
47 // false if the pattern was already in the set.
AddPattern(const URLPattern & pattern)48 bool AddPattern(const URLPattern& pattern) {
49 return accessible_resources_.AddPattern(pattern);
50 }
51
accessible_resources() const52 const URLPatternSet& accessible_resources() const {
53 return accessible_resources_;
54 }
55 private:
56 // A pattern string that matches partition IDs.
57 const std::string partition_pattern_;
58 // A URL pattern set of resources accessible to the given
59 // |partition_pattern_|.
60 URLPatternSet accessible_resources_;
61 };
62
63
WebviewInfo()64 WebviewInfo::WebviewInfo() {
65 }
66
~WebviewInfo()67 WebviewInfo::~WebviewInfo() {
68 }
69
70 // static
IsResourceWebviewAccessible(const Extension * extension,const std::string & partition_id,const std::string & relative_path)71 bool WebviewInfo::IsResourceWebviewAccessible(
72 const Extension* extension,
73 const std::string& partition_id,
74 const std::string& relative_path) {
75 if (!extension)
76 return false;
77
78 const WebviewInfo* info = GetResourcesInfo(*extension);
79 if (!info)
80 return false;
81
82 for (size_t i = 0; i < info->partition_items_.size(); ++i) {
83 const PartitionItem* const item = info->partition_items_[i];
84 if (item->Matches(partition_id) &&
85 extension->ResourceMatches(item->accessible_resources(),
86 relative_path)) {
87 return true;
88 }
89 }
90
91 return false;
92 }
93
AddPartitionItem(scoped_ptr<PartitionItem> item)94 void WebviewInfo::AddPartitionItem(scoped_ptr<PartitionItem> item) {
95 partition_items_.push_back(item.release());
96 }
97
WebviewHandler()98 WebviewHandler::WebviewHandler() {
99 }
100
~WebviewHandler()101 WebviewHandler::~WebviewHandler() {
102 }
103
Parse(Extension * extension,base::string16 * error)104 bool WebviewHandler::Parse(Extension* extension, base::string16* error) {
105 scoped_ptr<WebviewInfo> info(new WebviewInfo());
106
107 const base::DictionaryValue* dict_value = NULL;
108 if (!extension->manifest()->GetDictionary(keys::kWebview,
109 &dict_value)) {
110 *error = base::ASCIIToUTF16(errors::kInvalidWebview);
111 return false;
112 }
113
114 const base::ListValue* partition_list = NULL;
115 if (!dict_value->GetList(keys::kWebviewPartitions, &partition_list)) {
116 *error = base::ASCIIToUTF16(errors::kInvalidWebviewPartitionsList);
117 return false;
118 }
119
120 // The partition list must have at least one entry.
121 if (partition_list->GetSize() == 0) {
122 *error = base::ASCIIToUTF16(errors::kInvalidWebviewPartitionsList);
123 return false;
124 }
125
126 for (size_t i = 0; i < partition_list->GetSize(); ++i) {
127 const base::DictionaryValue* partition = NULL;
128 if (!partition_list->GetDictionary(i, &partition)) {
129 *error = ErrorUtils::FormatErrorMessageUTF16(
130 errors::kInvalidWebviewPartition, base::IntToString(i));
131 return false;
132 }
133
134 std::string partition_pattern;
135 if (!partition->GetString(keys::kWebviewName, &partition_pattern)) {
136 *error = ErrorUtils::FormatErrorMessageUTF16(
137 errors::kInvalidWebviewPartitionName, base::IntToString(i));
138 return false;
139 }
140
141 const base::ListValue* url_list = NULL;
142 if (!partition->GetList(keys::kWebviewAccessibleResources,
143 &url_list)) {
144 *error = base::ASCIIToUTF16(
145 errors::kInvalidWebviewAccessibleResourcesList);
146 return false;
147 }
148
149 // The URL list should have at least one entry.
150 if (url_list->GetSize() == 0) {
151 *error = base::ASCIIToUTF16(
152 errors::kInvalidWebviewAccessibleResourcesList);
153 return false;
154 }
155
156 scoped_ptr<PartitionItem> partition_item(
157 new PartitionItem(partition_pattern));
158
159 for (size_t i = 0; i < url_list->GetSize(); ++i) {
160 std::string relative_path;
161 if (!url_list->GetString(i, &relative_path)) {
162 *error = ErrorUtils::FormatErrorMessageUTF16(
163 errors::kInvalidWebviewAccessibleResource, base::IntToString(i));
164 return false;
165 }
166 URLPattern pattern(URLPattern::SCHEME_EXTENSION,
167 Extension::GetResourceURL(extension->url(),
168 relative_path).spec());
169 partition_item->AddPattern(pattern);
170 }
171 info->AddPartitionItem(partition_item.Pass());
172 }
173
174 extension->SetManifestData(keys::kWebviewAccessibleResources, info.release());
175 return true;
176 }
177
Keys() const178 const std::vector<std::string> WebviewHandler::Keys() const {
179 return SingleKey(keys::kWebview);
180 }
181
182 } // namespace extensions
183