Index: extensions/browser/api/declarative/rules_registry.cc |
diff --git a/extensions/browser/api/declarative/rules_registry.cc b/extensions/browser/api/declarative/rules_registry.cc |
index dfd9c35260ace0ea706aa383d78d355c8177e57b..8dbeede61ab09ebea8925acf16c27c194efbe338 100644 |
--- a/extensions/browser/api/declarative/rules_registry.cc |
+++ b/extensions/browser/api/declarative/rules_registry.cc |
@@ -19,26 +19,31 @@ |
#include "content/public/browser/notification_source.h" |
#include "extensions/browser/api/declarative/rules_cache_delegate.h" |
#include "extensions/browser/extension_prefs.h" |
+#include "extensions/browser/extension_registry.h" |
#include "extensions/browser/extension_system.h" |
#include "extensions/browser/state_store.h" |
#include "extensions/common/extension.h" |
+#include "extensions/common/manifest_constants.h" |
+ |
+namespace extensions { |
namespace { |
const char kSuccess[] = ""; |
const char kDuplicateRuleId[] = "Duplicate rule ID: %s"; |
+const char kErrorNonRemovableRules[] = "List contains non-removable rules"; |
scoped_ptr<base::Value> RulesToValue( |
- const std::vector<linked_ptr<extensions::RulesRegistry::Rule> >& rules) { |
+ const std::vector<linked_ptr<RulesRegistry::Rule>>& rules) { |
scoped_ptr<base::ListValue> list(new base::ListValue()); |
for (size_t i = 0; i < rules.size(); ++i) |
list->Append(rules[i]->ToValue().release()); |
return list.Pass(); |
} |
-std::vector<linked_ptr<extensions::RulesRegistry::Rule> > RulesFromValue( |
+std::vector<linked_ptr<RulesRegistry::Rule>> RulesFromValue( |
const base::Value* value) { |
- std::vector<linked_ptr<extensions::RulesRegistry::Rule> > rules; |
+ std::vector<linked_ptr<RulesRegistry::Rule>> rules; |
const base::ListValue* list = NULL; |
if (!value || !value->GetAsList(&list)) |
@@ -49,9 +54,67 @@ std::vector<linked_ptr<extensions::RulesRegistry::Rule> > RulesFromValue( |
const base::DictionaryValue* dict = NULL; |
if (!list->GetDictionary(i, &dict)) |
continue; |
- linked_ptr<extensions::RulesRegistry::Rule> rule( |
- new extensions::RulesRegistry::Rule()); |
- if (extensions::RulesRegistry::Rule::Populate(*dict, rule.get())) |
+ linked_ptr<RulesRegistry::Rule> rule(new RulesRegistry::Rule()); |
+ if (RulesRegistry::Rule::Populate(*dict, rule.get())) |
+ rules.push_back(rule); |
+ } |
+ |
+ return rules; |
+} |
+ |
+scoped_ptr<base::ListValue> ConvertListFromManifest( |
+ const base::ListValue* list) { |
+ scoped_ptr<base::ListValue> result(new base::ListValue); |
+ for (base::ListValue::const_iterator it = list->begin(); it != list->end(); |
+ ++it) { |
+ base::DictionaryValue* dictionary = nullptr; |
+ if (!(*it)->GetAsDictionary(&dictionary)) |
+ continue; |
+ std::string type; |
+ if (!dictionary->GetString("type", &type)) |
+ continue; |
+ scoped_ptr<base::DictionaryValue> copy = dictionary->CreateDeepCopy(); |
+ copy->Remove("type", NULL); |
+ copy->SetString("instanceType", type); |
+ result->Append(copy.Pass()); |
+ } |
+ return result.Pass(); |
+} |
+ |
+std::vector<linked_ptr<RulesRegistry::Rule>> RulesFromManifest( |
+ const base::Value* value, |
+ const std::string& event_name) { |
+ std::vector<linked_ptr<RulesRegistry::Rule>> rules; |
+ |
+ const base::ListValue* list = nullptr; |
+ if (!value || !value->GetAsList(&list)) |
+ return rules; |
+ |
+ for (size_t i = 0; i < list->GetSize(); ++i) { |
+ const base::DictionaryValue* dict = nullptr; |
+ if (!list->GetDictionary(i, &dict)) |
+ continue; |
+ std::string event; |
+ if (!dict->GetString("event", &event)) |
+ continue; |
+ if (event_name != event) |
+ continue; |
+ const base::ListValue* list; |
+ if (!dict->GetList("conditions", &list) || !list->GetSize()) |
+ continue; |
+ scoped_ptr<base::ListValue> conditions = ConvertListFromManifest(list); |
+ if (!conditions->GetSize()) |
+ continue; |
+ if (!dict->GetList("actions", &list) || !list->GetSize()) |
+ continue; |
+ scoped_ptr<base::ListValue> actions = ConvertListFromManifest(list); |
+ if (!actions->GetSize()) |
+ continue; |
+ scoped_ptr<base::DictionaryValue> rule_dict(new base::DictionaryValue); |
+ rule_dict->Set("conditions", conditions.Pass()); |
+ rule_dict->Set("actions", actions.Pass()); |
+ linked_ptr<RulesRegistry::Rule> rule(new RulesRegistry::Rule()); |
+ if (RulesRegistry::Rule::Populate(*rule_dict, rule.get())) |
rules.push_back(rule); |
} |
@@ -65,8 +128,6 @@ std::string ToId(int identifier) { |
} // namespace |
-namespace extensions { |
- |
// RulesRegistry |
RulesRegistry::RulesRegistry(content::BrowserContext* browser_context, |
@@ -90,7 +151,8 @@ RulesRegistry::RulesRegistry(content::BrowserContext* browser_context, |
std::string RulesRegistry::AddRulesNoFill( |
const std::string& extension_id, |
- const std::vector<linked_ptr<Rule> >& rules) { |
+ const std::vector<linked_ptr<Rule>>& rules, |
+ bool from_manifest) { |
DCHECK_CURRENTLY_ON(owner_thread()); |
// Verify that all rule IDs are new. |
@@ -100,6 +162,8 @@ std::string RulesRegistry::AddRulesNoFill( |
// Every rule should have a priority assigned. |
DCHECK((*i)->priority); |
RulesDictionaryKey key(extension_id, rule_id); |
+ if (from_manifest) |
+ manifest_rule_ids_.insert(key); |
if (rules_.find(key) != rules_.end()) |
return base::StringPrintf(kDuplicateRuleId, rule_id.c_str()); |
} |
@@ -121,9 +185,9 @@ std::string RulesRegistry::AddRulesNoFill( |
return kSuccess; |
} |
-std::string RulesRegistry::AddRules( |
- const std::string& extension_id, |
- const std::vector<linked_ptr<Rule> >& rules) { |
+std::string RulesRegistry::AddRules(const std::string& extension_id, |
+ const std::vector<linked_ptr<Rule>>& rules, |
+ bool from_manifest) { |
DCHECK_CURRENTLY_ON(owner_thread()); |
std::string error = CheckAndFillInOptionalRules(extension_id, rules); |
@@ -131,7 +195,7 @@ std::string RulesRegistry::AddRules( |
return error; |
FillInOptionalPriorities(rules); |
- return AddRulesNoFill(extension_id, rules); |
+ return AddRulesNoFill(extension_id, rules, from_manifest); |
} |
std::string RulesRegistry::RemoveRules( |
@@ -139,6 +203,14 @@ std::string RulesRegistry::RemoveRules( |
const std::vector<std::string>& rule_identifiers) { |
DCHECK_CURRENTLY_ON(owner_thread()); |
+ // Check if any of the rules are non-removable. |
+ for (RuleId rule_id : rule_identifiers) { |
+ RulesDictionaryKey lookup_key(extension_id, rule_id); |
+ RuleIdSet::iterator itr = manifest_rule_ids_.find(lookup_key); |
+ if (itr != manifest_rule_ids_.end()) |
+ return kErrorNonRemovableRules; |
+ } |
+ |
std::string error = RemoveRulesImpl(extension_id, rule_identifiers); |
if (!error.empty()) |
@@ -175,8 +247,10 @@ std::string RulesRegistry::RemoveAllRulesNoStoreUpdate( |
i != rules_.end();) { |
const RulesDictionaryKey& key = i->first; |
++i; |
- if (key.first == extension_id) |
+ if (key.first == extension_id) { |
rules_.erase(key); |
+ manifest_rule_ids_.erase(key); |
+ } |
} |
RemoveAllUsedRuleIdentifiers(extension_id); |
@@ -224,7 +298,17 @@ void RulesRegistry::OnExtensionUninstalled(const std::string& extension_id) { |
void RulesRegistry::OnExtensionLoaded(const std::string& extension_id) { |
DCHECK_CURRENTLY_ON(owner_thread()); |
- std::vector<linked_ptr<Rule> > rules; |
+ const Extension* extension = |
+ ExtensionRegistry::Get(browser_context()) |
+ ->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING); |
+ const base::ListValue* value = NULL; |
+ if (extension->manifest()->GetList(manifest_keys::kEventRules, &value)) { |
+ std::string error = |
+ AddRules(extension_id, RulesFromManifest(value, event_name_), true); |
+ if (!error.empty()) |
+ LOG(ERROR) << error; |
+ } |
+ std::vector<linked_ptr<Rule>> rules; |
GetAllRules(extension_id, &rules); |
std::string error = AddRulesImpl(extension_id, rules); |
if (!error.empty()) |
@@ -249,7 +333,7 @@ void RulesRegistry::DeserializeAndAddRules( |
scoped_ptr<base::Value> rules) { |
DCHECK_CURRENTLY_ON(owner_thread()); |
- AddRulesNoFill(extension_id, RulesFromValue(rules.get())); |
+ AddRulesNoFill(extension_id, RulesFromValue(rules.get()), false); |
} |
RulesRegistry::~RulesRegistry() { |
@@ -274,13 +358,18 @@ void RulesRegistry::ProcessChangedRules(const std::string& extension_id) { |
std::vector<linked_ptr<Rule> > new_rules; |
GetAllRules(extension_id, &new_rules); |
+ std::vector<linked_ptr<Rule>> rules_to_write; |
+ for (auto rule : new_rules) { |
+ const RuleId& rule_id = *(rule->id); |
+ RulesDictionaryKey key(extension_id, rule_id); |
+ // Only write rules that were added programmatically. |
+ if (manifest_rule_ids_.find(key) == manifest_rule_ids_.end()) |
+ rules_to_write.push_back(rule); |
+ } |
content::BrowserThread::PostTask( |
- content::BrowserThread::UI, |
- FROM_HERE, |
- base::Bind(&RulesCacheDelegate::WriteToStorage, |
- cache_delegate_, |
- extension_id, |
- base::Passed(RulesToValue(new_rules)))); |
+ content::BrowserThread::UI, FROM_HERE, |
+ base::Bind(&RulesCacheDelegate::WriteToStorage, cache_delegate_, |
+ extension_id, base::Passed(RulesToValue(rules_to_write)))); |
} |
void RulesRegistry::MaybeProcessChangedRules(const std::string& extension_id) { |