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#include "chrome/browser/extensions/api/preference/preference_helpers.h"
6
7#include "base/json/json_writer.h"
8#include "base/prefs/pref_service.h"
9#include "base/values.h"
10#include "chrome/browser/extensions/api/preference/preference_api.h"
11#include "chrome/browser/extensions/extension_service.h"
12#include "chrome/browser/extensions/extension_util.h"
13#include "chrome/browser/profiles/profile.h"
14#include "extensions/browser/event_router.h"
15#include "extensions/browser/extension_prefs.h"
16#include "extensions/browser/extension_system.h"
17#include "extensions/common/manifest_handlers/incognito_info.h"
18#include "extensions/common/permissions/permissions_data.h"
19
20namespace extensions {
21namespace preference_helpers {
22
23namespace {
24
25const char kIncognitoPersistent[] = "incognito_persistent";
26const char kIncognitoSessionOnly[] = "incognito_session_only";
27const char kRegular[] = "regular";
28const char kRegularOnly[] = "regular_only";
29
30const char kLevelOfControlKey[] = "levelOfControl";
31
32const char kNotControllable[] = "not_controllable";
33const char kControlledByOtherExtensions[] = "controlled_by_other_extensions";
34const char kControllableByThisExtension[] = "controllable_by_this_extension";
35const char kControlledByThisExtension[] = "controlled_by_this_extension";
36
37}  // namespace
38
39bool StringToScope(const std::string& s,
40                   ExtensionPrefsScope* scope) {
41  if (s == kRegular)
42    *scope = kExtensionPrefsScopeRegular;
43  else if (s == kRegularOnly)
44    *scope = kExtensionPrefsScopeRegularOnly;
45  else if (s == kIncognitoPersistent)
46    *scope = kExtensionPrefsScopeIncognitoPersistent;
47  else if (s == kIncognitoSessionOnly)
48    *scope = kExtensionPrefsScopeIncognitoSessionOnly;
49  else
50    return false;
51  return true;
52}
53
54const char* GetLevelOfControl(
55    Profile* profile,
56    const std::string& extension_id,
57    const std::string& browser_pref,
58    bool incognito) {
59  PrefService* prefs = incognito ? profile->GetOffTheRecordPrefs()
60                                 : profile->GetPrefs();
61  bool from_incognito = false;
62  bool* from_incognito_ptr = incognito ? &from_incognito : NULL;
63  const PrefService::Preference* pref =
64      prefs->FindPreference(browser_pref.c_str());
65  CHECK(pref);
66
67  if (!pref->IsExtensionModifiable())
68    return kNotControllable;
69
70  if (PreferenceAPI::Get(profile)->DoesExtensionControlPref(
71          extension_id,
72          browser_pref,
73          from_incognito_ptr)) {
74    return kControlledByThisExtension;
75  }
76
77  if (PreferenceAPI::Get(profile)->CanExtensionControlPref(extension_id,
78                                                           browser_pref,
79                                                           incognito)) {
80    return kControllableByThisExtension;
81  }
82
83  return kControlledByOtherExtensions;
84}
85
86void DispatchEventToExtensions(
87    Profile* profile,
88    const std::string& event_name,
89    base::ListValue* args,
90    APIPermission::ID permission,
91    bool incognito,
92    const std::string& browser_pref) {
93  EventRouter* router = EventRouter::Get(profile);
94  if (!router || !router->HasEventListener(event_name))
95    return;
96  ExtensionService* extension_service =
97      ExtensionSystem::Get(profile)->extension_service();
98  const ExtensionSet* extensions = extension_service->extensions();
99  for (ExtensionSet::const_iterator it = extensions->begin();
100       it != extensions->end(); ++it) {
101    std::string extension_id = (*it)->id();
102    // TODO(bauerb): Only iterate over registered event listeners.
103    if (router->ExtensionHasEventListener(extension_id, event_name) &&
104        (*it)->permissions_data()->HasAPIPermission(permission) &&
105        (!incognito || IncognitoInfo::IsSplitMode(it->get()) ||
106         util::CanCrossIncognito(it->get(), profile))) {
107      // Inject level of control key-value.
108      base::DictionaryValue* dict;
109      bool rv = args->GetDictionary(0, &dict);
110      DCHECK(rv);
111      std::string level_of_control =
112          GetLevelOfControl(profile, extension_id, browser_pref, incognito);
113      dict->SetString(kLevelOfControlKey, level_of_control);
114
115      // If the extension is in incognito split mode,
116      // a) incognito pref changes are visible only to the incognito tabs
117      // b) regular pref changes are visible only to the incognito tabs if the
118      //    incognito pref has not alredy been set
119      Profile* restrict_to_profile = NULL;
120      bool from_incognito = false;
121      if (IncognitoInfo::IsSplitMode(it->get())) {
122        if (incognito &&
123            util::IsIncognitoEnabled(extension_id, profile)) {
124          restrict_to_profile = profile->GetOffTheRecordProfile();
125        } else if (!incognito &&
126                   PreferenceAPI::Get(profile)->DoesExtensionControlPref(
127                       extension_id,
128                       browser_pref,
129                       &from_incognito) &&
130                   from_incognito) {
131          restrict_to_profile = profile;
132        }
133      }
134
135      scoped_ptr<base::ListValue> args_copy(args->DeepCopy());
136      scoped_ptr<Event> event(new Event(event_name, args_copy.Pass()));
137      event->restrict_to_browser_context = restrict_to_profile;
138      router->DispatchEventToExtension(extension_id, event.Pass());
139    }
140  }
141}
142
143}  // namespace preference_helpers
144}  // namespace extensions
145