• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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/signin/signin_promo.h"
6 
7 #include "base/prefs/pref_service.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/first_run/first_run.h"
14 #include "chrome/browser/google/google_brand.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/profiles/profile_info_cache.h"
17 #include "chrome/browser/profiles/profile_manager.h"
18 #include "chrome/browser/signin/signin_manager_factory.h"
19 #include "chrome/browser/ui/webui/options/core_options_handler.h"
20 #include "chrome/browser/ui/webui/theme_source.h"
21 #include "chrome/common/net/url_util.h"
22 #include "chrome/common/pref_names.h"
23 #include "chrome/common/url_constants.h"
24 #include "components/google/core/browser/google_util.h"
25 #include "components/pref_registry/pref_registry_syncable.h"
26 #include "components/signin/core/browser/signin_manager.h"
27 #include "components/signin/core/common/profile_management_switches.h"
28 #include "content/public/browser/url_data_source.h"
29 #include "content/public/browser/web_contents.h"
30 #include "content/public/browser/web_ui.h"
31 #include "content/public/browser/web_ui_data_source.h"
32 #include "google_apis/gaia/gaia_urls.h"
33 #include "grit/browser_resources.h"
34 #include "grit/generated_resources.h"
35 #include "grit/theme_resources.h"
36 #include "net/base/escape.h"
37 #include "net/base/network_change_notifier.h"
38 #include "net/base/url_util.h"
39 #include "ui/base/l10n/l10n_util.h"
40 #include "url/gurl.h"
41 
42 using content::WebContents;
43 using net::GetValueForKeyInQuery;
44 
45 namespace {
46 
47 // Gaia cannot support about:blank as a continue URL, so using a hosted blank
48 // page instead.
49 const char kSignInLandingUrlPrefix[] =
50     "https://www.google.com/intl/%s/chrome/blank.html";
51 
52 // The maximum number of times we want to show the sign in promo at startup.
53 const int kSignInPromoShowAtStartupMaximum = 10;
54 
55 // Forces the web based signin flow when set.
56 bool g_force_web_based_signin_flow = false;
57 
58 // Checks we want to show the sign in promo for the given brand.
AllowPromoAtStartupForCurrentBrand()59 bool AllowPromoAtStartupForCurrentBrand() {
60   std::string brand;
61   google_brand::GetBrand(&brand);
62 
63   if (brand.empty())
64     return true;
65 
66   if (google_brand::IsInternetCafeBrandCode(brand))
67     return false;
68 
69   // Enable for both organic and distribution.
70   return true;
71 }
72 
73 // Returns true if a user has seen the sign in promo at startup previously.
HasShownPromoAtStartup(Profile * profile)74 bool HasShownPromoAtStartup(Profile* profile) {
75   return profile->GetPrefs()->HasPrefPath(prefs::kSignInPromoStartupCount);
76 }
77 
78 // Returns true if the user has previously skipped the sign in promo.
HasUserSkippedPromo(Profile * profile)79 bool HasUserSkippedPromo(Profile* profile) {
80   return profile->GetPrefs()->GetBoolean(prefs::kSignInPromoUserSkipped);
81 }
82 
83 }  // namespace
84 
85 namespace signin {
86 
ShouldShowPromo(Profile * profile)87 bool ShouldShowPromo(Profile* profile) {
88 #if defined(OS_CHROMEOS)
89   // There's no need to show the sign in promo on cros since cros users are
90   // already logged in.
91   return false;
92 #else
93 
94   // Don't bother if we don't have any kind of network connection.
95   if (net::NetworkChangeNotifier::IsOffline())
96     return false;
97 
98   // Don't show for supervised profiles.
99   if (profile->IsSupervised())
100     return false;
101 
102   // Display the signin promo if the user is not signed in.
103   SigninManager* signin = SigninManagerFactory::GetForProfile(
104       profile->GetOriginalProfile());
105   return !signin->AuthInProgress() && signin->IsSigninAllowed() &&
106       signin->GetAuthenticatedUsername().empty();
107 #endif
108 }
109 
ShouldShowPromoAtStartup(Profile * profile,bool is_new_profile)110 bool ShouldShowPromoAtStartup(Profile* profile, bool is_new_profile) {
111   DCHECK(profile);
112 
113   // Don't show if the profile is an incognito.
114   if (profile->IsOffTheRecord())
115     return false;
116 
117   if (!ShouldShowPromo(profile))
118     return false;
119 
120   if (!is_new_profile) {
121     if (!HasShownPromoAtStartup(profile))
122       return false;
123   }
124 
125   if (HasUserSkippedPromo(profile))
126     return false;
127 
128   // For Chinese users skip the sign in promo.
129   if (g_browser_process->GetApplicationLocale() == "zh-CN")
130     return false;
131 
132   PrefService* prefs = profile->GetPrefs();
133   int show_count = prefs->GetInteger(prefs::kSignInPromoStartupCount);
134   if (show_count >= kSignInPromoShowAtStartupMaximum)
135     return false;
136 
137   // This pref can be set in the master preferences file to allow or disallow
138   // showing the sign in promo at startup.
139   if (prefs->HasPrefPath(prefs::kSignInPromoShowOnFirstRunAllowed))
140     return prefs->GetBoolean(prefs::kSignInPromoShowOnFirstRunAllowed);
141 
142   // For now don't show the promo for some brands.
143   if (!AllowPromoAtStartupForCurrentBrand())
144     return false;
145 
146   // Default to show the promo for Google Chrome builds.
147 #if defined(GOOGLE_CHROME_BUILD)
148   return true;
149 #else
150   return false;
151 #endif
152 }
153 
DidShowPromoAtStartup(Profile * profile)154 void DidShowPromoAtStartup(Profile* profile) {
155   int show_count = profile->GetPrefs()->GetInteger(
156       prefs::kSignInPromoStartupCount);
157   show_count++;
158   profile->GetPrefs()->SetInteger(prefs::kSignInPromoStartupCount, show_count);
159 }
160 
SetUserSkippedPromo(Profile * profile)161 void SetUserSkippedPromo(Profile* profile) {
162   profile->GetPrefs()->SetBoolean(prefs::kSignInPromoUserSkipped, true);
163 }
164 
GetLandingURL(const char * option,int value)165 GURL GetLandingURL(const char* option, int value) {
166   const std::string& locale = g_browser_process->GetApplicationLocale();
167   std::string url = base::StringPrintf(kSignInLandingUrlPrefix, locale.c_str());
168   base::StringAppendF(&url, "?%s=%d", option, value);
169   return GURL(url);
170 }
171 
GetPromoURL(Source source,bool auto_close)172 GURL GetPromoURL(Source source, bool auto_close) {
173   return GetPromoURL(source, auto_close, false /* is_constrained */);
174 }
175 
GetPromoURL(Source source,bool auto_close,bool is_constrained)176 GURL GetPromoURL(Source source, bool auto_close, bool is_constrained) {
177   return GetPromoURLWithContinueURL(source, auto_close, is_constrained, GURL());
178 }
179 
GetPromoURLWithContinueURL(Source source,bool auto_close,bool is_constrained,GURL continue_url)180 GURL GetPromoURLWithContinueURL(Source source,
181                                 bool auto_close,
182                                 bool is_constrained,
183                                 GURL continue_url) {
184   DCHECK_NE(SOURCE_UNKNOWN, source);
185 
186   if (!switches::IsEnableWebBasedSignin()) {
187     std::string url(chrome::kChromeUIChromeSigninURL);
188     base::StringAppendF(&url, "?%s=%d", kSignInPromoQueryKeySource, source);
189     if (auto_close)
190       base::StringAppendF(&url, "&%s=1", kSignInPromoQueryKeyAutoClose);
191     if (is_constrained)
192       base::StringAppendF(&url, "&%s=1", kSignInPromoQueryKeyConstrained);
193     if (!continue_url.is_empty()) {
194       DCHECK(continue_url.is_valid());
195       std::string escaped_continue_url =
196           net::EscapeQueryParamValue(continue_url.spec(), false);
197       base::StringAppendF(&url,
198                           "&%s=%s",
199                           kSignInPromoQueryKeyContinue,
200                           escaped_continue_url.c_str());
201     }
202     return GURL(url);
203   }
204 
205   // Build a Gaia-based URL that can be used to sign the user into chrome.
206   // There are required request parameters:
207   //
208   //  - tell Gaia which service the user is signing into.  In this case,
209   //    a chrome sign in uses the service "chromiumsync"
210   //  - provide a continue URL.  This is the URL that Gaia will redirect to
211   //    once the sign is complete.
212   //
213   // The continue URL includes a source parameter that can be extracted using
214   // the function GetSourceForSignInPromoURL() below.  This is used to know
215   // which of the chrome sign in access points was used to sign the user in.
216   // It is also parsed for the |auto_close| flag, which indicates that the tab
217   // must be closed after sync setup is successful.
218   // See OneClickSigninHelper for details.
219   std::string query_string = "?service=chromiumsync&sarp=1";
220 
221   DCHECK(continue_url.is_empty());
222   std::string continue_url_str = GetLandingURL(kSignInPromoQueryKeySource,
223                                                static_cast<int>(source)).spec();
224   if (auto_close) {
225     base::StringAppendF(
226         &continue_url_str, "&%s=1", kSignInPromoQueryKeyAutoClose);
227   }
228 
229   base::StringAppendF(
230       &query_string,
231       "&%s=%s",
232       kSignInPromoQueryKeyContinue,
233       net::EscapeQueryParamValue(continue_url_str, false).c_str());
234 
235   return GaiaUrls::GetInstance()->service_login_url().Resolve(query_string);
236 }
237 
GetReauthURL(Profile * profile,const std::string & account_id)238 GURL GetReauthURL(Profile* profile, const std::string& account_id) {
239   if (switches::IsEnableWebBasedSignin()) {
240     return net::AppendQueryParameter(
241         signin::GetPromoURL(signin::SOURCE_SETTINGS, true),
242         "Email",
243         account_id);
244   }
245 
246   signin::Source source = switches::IsNewProfileManagement() ?
247       signin::SOURCE_REAUTH : signin::SOURCE_SETTINGS;
248 
249   GURL url = signin::GetPromoURL(
250       source, true /* auto_close */,
251       switches::IsNewProfileManagement() /* is_constrained */);
252   url = net::AppendQueryParameter(url, "email", account_id);
253   url = net::AppendQueryParameter(url, "validateEmail", "1");
254   return net::AppendQueryParameter(url, "readOnlyEmail", "1");
255 }
256 
GetNextPageURLForPromoURL(const GURL & url)257 GURL GetNextPageURLForPromoURL(const GURL& url) {
258   std::string value;
259   if (GetValueForKeyInQuery(url, kSignInPromoQueryKeyContinue, &value)) {
260     GURL continue_url = GURL(value);
261     if (continue_url.is_valid())
262       return continue_url;
263   }
264 
265   return GURL();
266 }
267 
GetSourceForPromoURL(const GURL & url)268 Source GetSourceForPromoURL(const GURL& url) {
269   std::string value;
270   if (GetValueForKeyInQuery(url, kSignInPromoQueryKeySource, &value)) {
271     int source = 0;
272     if (base::StringToInt(value, &source) && source >= SOURCE_START_PAGE &&
273         source < SOURCE_UNKNOWN) {
274       return static_cast<Source>(source);
275     }
276   }
277   return SOURCE_UNKNOWN;
278 }
279 
IsAutoCloseEnabledInURL(const GURL & url)280 bool IsAutoCloseEnabledInURL(const GURL& url) {
281   std::string value;
282   if (GetValueForKeyInQuery(url, kSignInPromoQueryKeyAutoClose, &value)) {
283     int enabled = 0;
284     if (base::StringToInt(value, &enabled) && enabled == 1)
285       return true;
286   }
287   return false;
288 }
289 
ShouldShowAccountManagement(const GURL & url)290 bool ShouldShowAccountManagement(const GURL& url) {
291   std::string value;
292   if (GetValueForKeyInQuery(
293           url, kSignInPromoQueryKeyShowAccountManagement, &value)) {
294     int enabled = 0;
295     if (base::StringToInt(value, &enabled) && enabled == 1)
296       return true;
297   }
298   return false;
299 }
300 
IsContinueUrlForWebBasedSigninFlow(const GURL & url)301 bool IsContinueUrlForWebBasedSigninFlow(const GURL& url) {
302   GURL::Replacements replacements;
303   replacements.ClearQuery();
304   const std::string& locale = g_browser_process->GetApplicationLocale();
305   GURL continue_url =
306       GURL(base::StringPrintf(kSignInLandingUrlPrefix, locale.c_str()));
307   return (
308       google_util::IsGoogleDomainUrl(
309           url,
310           google_util::ALLOW_SUBDOMAIN,
311           google_util::DISALLOW_NON_STANDARD_PORTS) &&
312       url.ReplaceComponents(replacements).path() ==
313         continue_url.ReplaceComponents(replacements).path());
314 }
315 
ForceWebBasedSigninFlowForTesting(bool force)316 void ForceWebBasedSigninFlowForTesting(bool force) {
317   g_force_web_based_signin_flow = force;
318 }
319 
RegisterProfilePrefs(user_prefs::PrefRegistrySyncable * registry)320 void RegisterProfilePrefs(
321     user_prefs::PrefRegistrySyncable* registry) {
322   registry->RegisterIntegerPref(
323       prefs::kSignInPromoStartupCount,
324       0,
325       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
326   registry->RegisterBooleanPref(
327       prefs::kSignInPromoUserSkipped,
328       false,
329       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
330   registry->RegisterBooleanPref(
331       prefs::kSignInPromoShowOnFirstRunAllowed,
332       true,
333       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
334   registry->RegisterBooleanPref(
335       prefs::kSignInPromoShowNTPBubble,
336       false,
337       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
338 }
339 
340 }  // namespace signin
341