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/signin/about_signin_internals.h" 6 7 #include "base/debug/trace_event.h" 8 #include "base/hash.h" 9 #include "base/i18n/time_formatting.h" 10 #include "base/logging.h" 11 #include "base/prefs/pref_service.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "chrome/browser/profiles/profile.h" 14 #include "chrome/browser/signin/signin_internals_util.h" 15 #include "chrome/browser/signin/signin_manager.h" 16 #include "chrome/browser/signin/token_service.h" 17 #include "chrome/browser/signin/token_service_factory.h" 18 #include "chrome/browser/ui/webui/signin_internals_ui.h" 19 #include "google_apis/gaia/gaia_constants.h" 20 21 using base::Time; 22 using namespace signin_internals_util; 23 24 AboutSigninInternals::AboutSigninInternals() : profile_(NULL) { 25 // Initialize default values for tokens. 26 for (size_t i = 0; i < kNumTokenPrefs; ++i) { 27 signin_status_.token_info_map.insert(std::pair<std::string, TokenInfo>( 28 kTokenPrefsArray[i], 29 TokenInfo(std::string(), "Not Loaded", std::string(), 0, 30 kTokenPrefsArray[i]))); 31 } 32 } 33 34 AboutSigninInternals::~AboutSigninInternals() { 35 } 36 37 void AboutSigninInternals::AddSigninObserver( 38 AboutSigninInternals::Observer* observer) { 39 signin_observers_.AddObserver(observer); 40 } 41 42 void AboutSigninInternals::RemoveSigninObserver( 43 AboutSigninInternals::Observer* observer) { 44 signin_observers_.RemoveObserver(observer); 45 } 46 47 void AboutSigninInternals::NotifySigninValueChanged( 48 const UntimedSigninStatusField& field, 49 const std::string& value) { 50 unsigned int field_index = field - UNTIMED_FIELDS_BEGIN; 51 DCHECK(field_index >= 0 && 52 field_index < signin_status_.untimed_signin_fields.size()); 53 54 signin_status_.untimed_signin_fields[field_index] = value; 55 56 // Also persist these values in the prefs. 57 const std::string pref_path = SigninStatusFieldToString(field); 58 profile_->GetPrefs()->SetString(pref_path.c_str(), value); 59 60 NotifyObservers(); 61 } 62 63 void AboutSigninInternals::NotifySigninValueChanged( 64 const TimedSigninStatusField& field, 65 const std::string& value) { 66 unsigned int field_index = field - TIMED_FIELDS_BEGIN; 67 DCHECK(field_index >= 0 && 68 field_index < signin_status_.timed_signin_fields.size()); 69 70 Time now = Time::NowFromSystemTime(); 71 std::string time_as_str = UTF16ToUTF8(base::TimeFormatFriendlyDate(now)); 72 TimedSigninStatusValue timed_value(value, time_as_str); 73 74 signin_status_.timed_signin_fields[field_index] = timed_value; 75 76 // Also persist these values in the prefs. 77 const std::string value_pref = SigninStatusFieldToString(field) + ".value"; 78 const std::string time_pref = SigninStatusFieldToString(field) + ".time"; 79 profile_->GetPrefs()->SetString(value_pref.c_str(), value); 80 profile_->GetPrefs()->SetString(time_pref.c_str(), time_as_str); 81 82 NotifyObservers(); 83 } 84 85 void AboutSigninInternals::RefreshSigninPrefs() { 86 // Return if no profile exists. Can occur in unit tests. 87 if (!profile_) 88 return; 89 90 PrefService* pref_service = profile_->GetPrefs(); 91 for (int i = UNTIMED_FIELDS_BEGIN; i < UNTIMED_FIELDS_END; ++i) { 92 const std::string pref_path = 93 SigninStatusFieldToString(static_cast<UntimedSigninStatusField>(i)); 94 95 signin_status_.untimed_signin_fields[i - UNTIMED_FIELDS_BEGIN] = 96 pref_service->GetString(pref_path.c_str()); 97 } 98 for (int i = TIMED_FIELDS_BEGIN ; i < TIMED_FIELDS_END; ++i) { 99 const std::string value_pref = SigninStatusFieldToString( 100 static_cast<TimedSigninStatusField>(i)) + ".value"; 101 const std::string time_pref = SigninStatusFieldToString( 102 static_cast<TimedSigninStatusField>(i)) + ".time"; 103 104 TimedSigninStatusValue value(pref_service->GetString(value_pref.c_str()), 105 pref_service->GetString(time_pref.c_str())); 106 signin_status_.timed_signin_fields[i - TIMED_FIELDS_BEGIN] = value; 107 } 108 109 // Get status and timestamps for all token services. 110 for (size_t i = 0; i < kNumTokenPrefs; i++) { 111 const std::string pref = TokenPrefPath(kTokenPrefsArray[i]); 112 const std::string value = pref + ".value"; 113 const std::string status = pref + ".status"; 114 const std::string time = pref + ".time"; 115 const std::string time_internal = pref + ".time_internal"; 116 117 TokenInfo token_info(pref_service->GetString(value.c_str()), 118 pref_service->GetString(status.c_str()), 119 pref_service->GetString(time.c_str()), 120 pref_service->GetInt64(time_internal.c_str()), 121 kTokenPrefsArray[i]); 122 123 signin_status_.token_info_map[kTokenPrefsArray[i]] = token_info; 124 } 125 126 NotifyObservers(); 127 } 128 129 void AboutSigninInternals::NotifyTokenReceivedSuccess( 130 const std::string& token_name, 131 const std::string& token, 132 bool update_time) { 133 // This should have been initialized already. 134 DCHECK(signin_status_.token_info_map.count(token_name)); 135 136 const std::string status_success = "Successful"; 137 signin_status_.token_info_map[token_name].token = token; 138 signin_status_.token_info_map[token_name].status = status_success; 139 140 // Also update preferences. 141 const std::string value_pref = TokenPrefPath(token_name) + ".value"; 142 const std::string time_pref = TokenPrefPath(token_name) + ".time"; 143 const std::string time_internal_pref = 144 TokenPrefPath(token_name) + ".time_internal"; 145 const std::string status_pref = TokenPrefPath(token_name) + ".status"; 146 profile_->GetPrefs()->SetString(value_pref.c_str(), token); 147 profile_->GetPrefs()->SetString(status_pref.c_str(), "Successful"); 148 149 // Update timestamp if needed. 150 if (update_time) { 151 Time now = Time::NowFromSystemTime(); 152 int64 time_as_int = now.ToInternalValue(); 153 const std::string time_as_str = 154 UTF16ToUTF8(base::TimeFormatFriendlyDate(now)); 155 signin_status_.token_info_map[token_name].time = time_as_str; 156 signin_status_.token_info_map[token_name].time_internal = time_as_int; 157 profile_->GetPrefs()->SetString(time_pref.c_str(), time_as_str); 158 profile_->GetPrefs()->SetInt64(time_internal_pref.c_str(), time_as_int); 159 } 160 161 NotifyObservers(); 162 } 163 164 165 void AboutSigninInternals::NotifyTokenReceivedFailure( 166 const std::string& token_name, 167 const std::string& error) { 168 Time now = Time::NowFromSystemTime(); 169 int64 time_as_int = now.ToInternalValue(); 170 const std::string time_as_str = 171 UTF16ToUTF8(base::TimeFormatFriendlyDate(now)); 172 173 // This should have been initialized already. 174 DCHECK(signin_status_.token_info_map.count(token_name)); 175 176 signin_status_.token_info_map[token_name].token.clear(); 177 signin_status_.token_info_map[token_name].status = error; 178 signin_status_.token_info_map[token_name].time = time_as_str; 179 signin_status_.token_info_map[token_name].time_internal = time_as_int; 180 181 // Also update preferences. 182 const std::string value_pref = TokenPrefPath(token_name) + ".value"; 183 const std::string time_pref = TokenPrefPath(token_name) + ".time"; 184 const std::string time_internal_pref = 185 TokenPrefPath(token_name) + ".time_internal"; 186 const std::string status_pref = TokenPrefPath(token_name) + ".status"; 187 profile_->GetPrefs()->SetString(value_pref.c_str(), std::string()); 188 profile_->GetPrefs()->SetString(time_pref.c_str(), time_as_str); 189 profile_->GetPrefs()->SetInt64(time_internal_pref.c_str(), time_as_int); 190 profile_->GetPrefs()->SetString(status_pref.c_str(), error); 191 192 NotifyObservers(); 193 } 194 195 // While clearing tokens, we don't update the time or status. 196 void AboutSigninInternals::NotifyClearStoredToken( 197 const std::string& token_name) { 198 // This should have been initialized already. 199 DCHECK(signin_status_.token_info_map.count(token_name)); 200 201 signin_status_.token_info_map[token_name].token.clear(); 202 203 const std::string value_pref = TokenPrefPath(token_name) + ".value"; 204 profile_->GetPrefs()->SetString(value_pref.c_str(), std::string()); 205 206 NotifyObservers(); 207 } 208 209 void AboutSigninInternals::Initialize(Profile* profile) { 210 DCHECK(!profile_); 211 profile_ = profile; 212 213 RefreshSigninPrefs(); 214 215 SigninManagerFactory::GetForProfile(profile)-> 216 AddSigninDiagnosticsObserver(this); 217 TokenServiceFactory::GetForProfile(profile)-> 218 AddSigninDiagnosticsObserver(this); 219 } 220 221 void AboutSigninInternals::Shutdown() { 222 SigninManagerFactory::GetForProfile(profile_)-> 223 RemoveSigninDiagnosticsObserver(this); 224 TokenServiceFactory::GetForProfile(profile_)-> 225 RemoveSigninDiagnosticsObserver(this); 226 } 227 228 void AboutSigninInternals::NotifyObservers() { 229 FOR_EACH_OBSERVER(AboutSigninInternals::Observer, 230 signin_observers_, 231 OnSigninStateChanged(signin_status_.ToValue())); 232 } 233 234 scoped_ptr<DictionaryValue> AboutSigninInternals::GetSigninStatus() { 235 return signin_status_.ToValue().Pass(); 236 } 237 238 Time AboutSigninInternals::GetTokenTime( 239 const std::string& token_name) const { 240 TokenInfoMap::const_iterator iter = 241 signin_status_.token_info_map.find(token_name); 242 if (iter == signin_status_.token_info_map.end()) 243 return base::Time(); 244 return base::Time::FromInternalValue(iter->second.time_internal); 245 } 246