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