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 "chrome/browser/android/banners/app_banner_settings_helper.h"
6
7#include <algorithm>
8#include <string>
9
10#include "chrome/browser/content_settings/host_content_settings_map.h"
11#include "chrome/browser/profiles/profile.h"
12#include "components/content_settings/core/common/content_settings_pattern.h"
13#include "content/public/browser/web_contents.h"
14#include "url/gurl.h"
15
16namespace {
17std::string SanitizePackageName(std::string package_name) {
18  // DictionaryValue doesn't allow '.' in the keys.  Replace them with ' '
19  // because you can't have a package name with a ' ' in it.
20  std::replace(package_name.begin(), package_name.end(), '.', ' ');
21  return package_name;
22}
23
24// Max number of apps that a particular site may show a banner for.
25const size_t kMaxAppsPerSite = 3;
26}  // namespace
27
28bool AppBannerSettingsHelper::IsAllowed(content::WebContents* web_contents,
29                                        const GURL& origin_url,
30                                        const std::string& package_name) {
31  std::string sanitized_package_name = SanitizePackageName(package_name);
32  Profile* profile =
33      Profile::FromBrowserContext(web_contents->GetBrowserContext());
34  if (profile->IsOffTheRecord() || web_contents->GetURL() != origin_url ||
35      sanitized_package_name.empty()) {
36    return false;
37  }
38
39  // Check if this combination has been previously disabled.
40  HostContentSettingsMap* settings = profile->GetHostContentSettingsMap();
41  if (!settings)
42    return false;
43  scoped_ptr<base::Value> value =
44      settings->GetWebsiteSetting(origin_url,
45                                  origin_url,
46                                  CONTENT_SETTINGS_TYPE_APP_BANNER,
47                                  std::string(),
48                                  NULL);
49  if (!value.get()) {
50    // We've never blocked a banner on this site.
51    return true;
52  } else if (value->IsType(base::Value::TYPE_DICTIONARY)) {
53    // We expect to get a Dictionary back, where the keys are the package names.
54    base::DictionaryValue* banner_dict =
55        static_cast<base::DictionaryValue*>(value.get());
56    bool is_allowed = false;
57    if (banner_dict->GetBoolean(sanitized_package_name, &is_allowed)) {
58      return is_allowed;
59    } else {
60      return banner_dict->size() < ::kMaxAppsPerSite;
61    }
62  } else {
63    // Somehow the value we got back is not a dictionary (e.g. the settings were
64    // corrupted by malware).  Try to clear it out.
65    ContentSettingsPattern pattern(ContentSettingsPattern::FromURL(origin_url));
66    if (pattern.IsValid()) {
67      settings->SetWebsiteSetting(pattern,
68                                  ContentSettingsPattern::Wildcard(),
69                                  CONTENT_SETTINGS_TYPE_APP_BANNER,
70                                  std::string(),
71                                  NULL);
72      return true;
73    }
74  }
75
76  return false;
77}
78
79void AppBannerSettingsHelper::Block(content::WebContents* web_contents,
80                                    const GURL& origin_url,
81                                    const std::string& package_name) {
82  std::string sanitized_package_name = SanitizePackageName(package_name);
83  DCHECK(!sanitized_package_name.empty());
84
85  Profile* profile =
86      Profile::FromBrowserContext(web_contents->GetBrowserContext());
87  HostContentSettingsMap* settings = profile->GetHostContentSettingsMap();
88  ContentSettingsPattern pattern(ContentSettingsPattern::FromURL(origin_url));
89  if (!settings || !pattern.IsValid())
90    return;
91
92  scoped_ptr<base::Value> value =
93      settings->GetWebsiteSetting(origin_url,
94                                  origin_url,
95                                  CONTENT_SETTINGS_TYPE_APP_BANNER,
96                                  std::string(),
97                                  NULL);
98  base::DictionaryValue* banner_dict = NULL;
99  if (value.get() && value->IsType(base::Value::TYPE_DICTIONARY)) {
100    banner_dict = static_cast<base::DictionaryValue*>(value.release());
101  } else {
102    banner_dict = new base::DictionaryValue();
103  }
104
105  // Update the setting and save it back.
106  banner_dict->SetBoolean(sanitized_package_name, false);
107  settings->SetWebsiteSetting(pattern,
108                              ContentSettingsPattern::Wildcard(),
109                              CONTENT_SETTINGS_TYPE_APP_BANNER,
110                              std::string(),
111                              banner_dict);
112}
113