Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/autofill/core/common/save_password_progress_logger.h" | 5 #include "components/autofill/core/common/save_password_progress_logger.h" |
| 6 | 6 |
| 7 #include <algorithm> | |
| 8 | |
| 7 #include "base/json/json_writer.h" | 9 #include "base/json/json_writer.h" |
| 8 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/memory/scoped_ptr.h" | |
| 9 #include "base/numerics/safe_conversions.h" | 12 #include "base/numerics/safe_conversions.h" |
| 13 #include "base/strings/string16.h" | |
| 14 #include "base/strings/string_util.h" | |
| 15 #include "base/strings/utf_string_conversions.h" | |
| 10 #include "base/values.h" | 16 #include "base/values.h" |
| 11 #include "components/autofill/core/common/password_form.h" | 17 #include "components/autofill/core/common/password_form.h" |
| 12 | 18 |
| 13 using base::checked_cast; | 19 using base::checked_cast; |
| 14 using base::Value; | 20 using base::Value; |
| 15 using base::DictionaryValue; | 21 using base::DictionaryValue; |
| 16 using base::FundamentalValue; | 22 using base::FundamentalValue; |
| 17 using base::StringValue; | 23 using base::StringValue; |
| 18 | 24 |
| 19 namespace autofill { | 25 namespace autofill { |
| 20 | 26 |
| 21 namespace { | 27 namespace { |
| 22 | 28 |
| 29 // Note 1: Caching the ID->string map in an array would be probably faster, but | |
| 30 // the switch statement is (a) robust against re-ordering, and (b) checks in | |
| 31 // compile-time, that all IDs get a string assigned. The expected frequency of | |
| 32 // calls is low enough (in particular, zero if password manager internals page | |
| 33 // is not open), that optimizing for code robustness is preferred agains speed. | |
|
Ilya Sherman
2014/04/16 22:02:11
nit: "agains" -> "against"
vabr (Chromium)
2014/04/17 12:33:09
Done.
| |
| 34 // Note 2: The messages can be used as dictionary keys. Do not use '.' in them. | |
| 35 std::string GetStringFromID(SavePasswordProgressLogger::StringID id) { | |
| 36 switch (id) { | |
| 37 case SavePasswordProgressLogger::STRING_DECISION_ASK: | |
| 38 return "Decision: ASK the user"; | |
| 39 case SavePasswordProgressLogger::STRING_DECISION_DROP: | |
| 40 return "Decision: DROP the password"; | |
| 41 case SavePasswordProgressLogger::STRING_DECISION_SAVE: | |
| 42 return "Decision: SAVE the password"; | |
| 43 case SavePasswordProgressLogger::STRING_METHOD: | |
| 44 return "Form method"; | |
| 45 case SavePasswordProgressLogger::STRING_METHOD_GET: | |
| 46 return "GET"; | |
| 47 case SavePasswordProgressLogger::STRING_METHOD_POST: | |
| 48 return "POST"; | |
| 49 case SavePasswordProgressLogger::STRING_METHOD_EMPTY: | |
| 50 return "(empty)"; | |
| 51 case SavePasswordProgressLogger::STRING_OTHER: | |
| 52 return "(other)"; | |
| 53 case SavePasswordProgressLogger::STRING_SCHEME_HTML: | |
| 54 return "HTML"; | |
| 55 case SavePasswordProgressLogger::STRING_SCHEME_BASIC: | |
| 56 return "Basic"; | |
| 57 case SavePasswordProgressLogger::STRING_SCHEME_DIGEST: | |
| 58 return "Digest"; | |
| 59 case SavePasswordProgressLogger::STRING_SCHEME_MESSAGE: | |
| 60 return "Scheme"; | |
| 61 case SavePasswordProgressLogger::STRING_SIGNON_REALM: | |
| 62 return "Signon realm"; | |
| 63 case SavePasswordProgressLogger::STRING_ORIGINAL_SIGNON_REALM: | |
| 64 return "Original signon realm"; | |
| 65 case SavePasswordProgressLogger::STRING_ORIGIN: | |
| 66 return "Origin"; | |
| 67 case SavePasswordProgressLogger::STRING_ACTION: | |
| 68 return "Action"; | |
| 69 case SavePasswordProgressLogger::STRING_USERNAME_ELEMENT: | |
| 70 return "Username element"; | |
| 71 case SavePasswordProgressLogger::STRING_PASSWORD_ELEMENT: | |
| 72 return "Password element"; | |
| 73 case SavePasswordProgressLogger::STRING_PASSWORD_AUTOCOMPLETE_SET: | |
| 74 return "Password autocomplete set"; | |
| 75 case SavePasswordProgressLogger::STRING_OLD_PASSWORD_ELEMENT: | |
| 76 return "Old password element"; | |
| 77 case SavePasswordProgressLogger::STRING_SSL_VALID: | |
| 78 return "SSL valid"; | |
| 79 case SavePasswordProgressLogger::STRING_PASSWORD_GENERATED: | |
| 80 return "Password generated"; | |
| 81 case SavePasswordProgressLogger::STRING_TIMES_USED: | |
| 82 return "Times used"; | |
| 83 case SavePasswordProgressLogger::STRING_USE_ADDITIONAL_AUTHENTICATION: | |
| 84 return "Use additional authentication"; | |
| 85 case SavePasswordProgressLogger::STRING_PSL_MATCH: | |
| 86 return "PSL match"; | |
| 87 case SavePasswordProgressLogger::STRING_NAME_OR_ID: | |
| 88 return "Form name or ID"; | |
| 89 case SavePasswordProgressLogger::STRING_MESSAGE: | |
| 90 return "Message"; | |
| 91 case SavePasswordProgressLogger::STRING_INVALID: | |
| 92 return "INVALID"; | |
| 93 // Intentionally no default: clause here -- all IDs need to get covered. | |
| 94 } | |
| 95 NOTREACHED(); // Win compilers don't believe this is unreachable. | |
| 96 return NULL; | |
|
Ilya Sherman
2014/04/16 22:02:11
NULL isn't a valid std::string. I think you meant
vabr (Chromium)
2014/04/17 12:33:09
Thanks! That was a relic from the time this return
| |
| 97 }; | |
| 98 | |
| 23 // Removes privacy sensitive parts of |url| (currently all but host and scheme). | 99 // Removes privacy sensitive parts of |url| (currently all but host and scheme). |
| 24 std::string ScrubURL(const GURL& url) { | 100 std::string ScrubURL(const GURL& url) { |
| 25 if (url.is_valid()) | 101 if (url.is_valid()) |
| 26 return url.GetWithEmptyPath().spec(); | 102 return url.GetWithEmptyPath().spec(); |
| 27 return std::string(); | 103 return std::string(); |
| 28 } | 104 } |
| 29 | 105 |
| 30 std::string FormSchemeToString(PasswordForm::Scheme scheme) { | 106 // Returns true for all characters which we don't want to see in the logged IDs |
| 107 // or names of HTML elements. | |
| 108 bool IsUnwantedInElementID(char c) { | |
| 109 return !IsAsciiAlpha(c) && !IsAsciiDigit(c); | |
| 110 } | |
| 111 | |
| 112 // Replaces all characters satisfying IsUnwantedInElementID by a ' ', and turns | |
| 113 // all characters to lowercase. This damages some valid HTML element IDs or | |
| 114 // names, but it is likely that it will be still possible to match the scrubbed | |
| 115 // string to the original ID or name in the HTML doc. That's good enough for the | |
| 116 // logging purposes, and provides some security benefits. | |
| 117 std::string ScrubElementID(std::string element_id) { | |
| 118 std::replace_if( | |
| 119 element_id.begin(), element_id.end(), IsUnwantedInElementID, ' '); | |
| 120 return StringToLowerASCII(element_id); | |
| 121 } | |
| 122 | |
| 123 SavePasswordProgressLogger::StringID FormSchemeToStringID( | |
| 124 PasswordForm::Scheme scheme) { | |
| 31 switch (scheme) { | 125 switch (scheme) { |
| 32 case PasswordForm::SCHEME_HTML: | 126 case PasswordForm::SCHEME_HTML: |
| 33 return "HTML"; | 127 return SavePasswordProgressLogger::STRING_SCHEME_HTML; |
| 34 case PasswordForm::SCHEME_BASIC: | 128 case PasswordForm::SCHEME_BASIC: |
| 35 return "BASIC"; | 129 return SavePasswordProgressLogger::STRING_SCHEME_BASIC; |
| 36 case PasswordForm::SCHEME_DIGEST: | 130 case PasswordForm::SCHEME_DIGEST: |
| 37 return "DIGEST"; | 131 return SavePasswordProgressLogger::STRING_SCHEME_DIGEST; |
| 38 case PasswordForm::SCHEME_OTHER: | 132 case PasswordForm::SCHEME_OTHER: |
| 39 return "OTHER"; | 133 return SavePasswordProgressLogger::STRING_OTHER; |
| 40 } | 134 } |
| 41 NOTREACHED(); // Win compilers don't believe this is unreachable. | 135 NOTREACHED(); // Win compilers don't believe this is unreachable. |
| 42 return std::string(); | 136 return SavePasswordProgressLogger::StringID::STRING_INVALID; |
| 43 } | 137 } |
| 44 | 138 |
| 45 StringValue DecisionToStringValue( | 139 SavePasswordProgressLogger::StringID FormMethodToStringID( |
| 46 SavePasswordProgressLogger::Decision decision) { | 140 const std::string& method) { |
| 47 switch (decision) { | 141 std::string method_processed; |
| 48 case SavePasswordProgressLogger::DECISION_SAVE: | 142 base::TrimWhitespaceASCII( |
| 49 return StringValue("SAVE the password"); | 143 StringToLowerASCII(method), base::TRIM_ALL, &method_processed); |
| 50 case SavePasswordProgressLogger::DECISION_ASK: | 144 if (method_processed.empty()) |
| 51 return StringValue("ASK the user whether to save the password"); | 145 return SavePasswordProgressLogger::STRING_METHOD_EMPTY; |
| 52 case SavePasswordProgressLogger::DECISION_DROP: | 146 else if (method_processed == "get") |
| 53 return StringValue("DROP the password"); | 147 return SavePasswordProgressLogger::STRING_METHOD_GET; |
| 54 } | 148 else if (method_processed == "post") |
| 55 NOTREACHED(); // Win compilers don't believe this is unreachable. | 149 return SavePasswordProgressLogger::STRING_METHOD_POST; |
| 56 return StringValue(std::string()); | 150 else |
| 151 return SavePasswordProgressLogger::STRING_OTHER; | |
| 152 } | |
| 153 | |
| 154 // GetValueFromLog: Sanitize the arguments, and return them as base::Value. | |
| 155 scoped_ptr<Value> GetValueFromLog(const GURL& url) { | |
| 156 return scoped_ptr<Value>(Value::CreateStringValue(ScrubURL(url))); | |
| 157 } | |
| 158 | |
| 159 scoped_ptr<Value> GetValueFromLog( | |
| 160 SavePasswordProgressLogger::StringID message) { | |
| 161 return scoped_ptr<Value>(Value::CreateStringValue(GetStringFromID(message))); | |
| 162 } | |
| 163 | |
| 164 scoped_ptr<Value> GetValueFromLog(int number) { | |
| 165 return scoped_ptr<Value>(Value::CreateIntegerValue(number)); | |
| 166 } | |
| 167 | |
| 168 scoped_ptr<Value> GetValueFromLog(bool truth_value) { | |
| 169 return scoped_ptr<Value>(Value::CreateBooleanValue(truth_value)); | |
| 170 } | |
| 171 | |
| 172 scoped_ptr<Value> GetValueFromLog(const std::string& element_id) { | |
| 173 return scoped_ptr<Value>( | |
| 174 Value::CreateStringValue(ScrubElementID(element_id))); | |
| 175 } | |
| 176 | |
| 177 scoped_ptr<Value> GetValueFromLog(const base::string16& element_id) { | |
| 178 return scoped_ptr<Value>( | |
| 179 Value::CreateStringValue(ScrubElementID(UTF16ToUTF8(element_id)))); | |
| 180 } | |
| 181 | |
| 182 template <class T> | |
| 183 void AddToDict(DictionaryValue* dict, | |
| 184 SavePasswordProgressLogger::StringID label, | |
| 185 T log) { | |
| 186 dict->Set(GetStringFromID(label), GetValueFromLog(log).release()); | |
| 57 } | 187 } |
|
Ilya Sherman
2014/04/16 22:02:11
Hmm, I'm not thrilled about the addition of this m
vabr (Chromium)
2014/04/17 12:33:09
As for the style guide, it says: "Use overloaded f
| |
| 58 | 188 |
| 59 } // namespace | 189 } // namespace |
| 60 | 190 |
| 61 SavePasswordProgressLogger::SavePasswordProgressLogger() {} | 191 SavePasswordProgressLogger::SavePasswordProgressLogger() { |
| 62 | |
| 63 SavePasswordProgressLogger::~SavePasswordProgressLogger() {} | |
| 64 | |
| 65 void SavePasswordProgressLogger::LogPasswordForm(const std::string& message, | |
| 66 const PasswordForm& form) { | |
| 67 DictionaryValue log; | |
| 68 // Do not use the "<<" operator for PasswordForms, because it also prints | |
| 69 // passwords. Also, that operator is only for testing. | |
| 70 log.SetString("scheme", FormSchemeToString(form.scheme)); | |
| 71 log.SetString("signon realm", ScrubURL(GURL(form.signon_realm))); | |
| 72 log.SetString("original signon realm", | |
| 73 ScrubURL(GURL(form.original_signon_realm))); | |
| 74 log.SetString("origin", ScrubURL(form.origin)); | |
| 75 log.SetString("action", ScrubURL(form.action)); | |
| 76 log.SetString("username element", form.username_element); | |
| 77 log.SetString("password element", form.password_element); | |
| 78 log.SetBoolean("password autocomplete set", form.password_autocomplete_set); | |
| 79 log.SetString("old password element", form.old_password_element); | |
| 80 log.SetBoolean("ssl valid", form.ssl_valid); | |
| 81 log.SetBoolean("password generated", | |
| 82 form.type == PasswordForm::TYPE_GENERATED); | |
| 83 log.SetInteger("times used", form.times_used); | |
| 84 log.SetBoolean("use additional authentication", | |
| 85 form.use_additional_authentication); | |
| 86 log.SetBoolean("is PSL match", form.IsPublicSuffixMatch()); | |
| 87 LogValue(message, log); | |
| 88 } | 192 } |
| 89 | 193 |
| 90 void SavePasswordProgressLogger::LogHTMLForm(const std::string& message, | 194 SavePasswordProgressLogger::~SavePasswordProgressLogger() { |
| 91 const std::string& name_or_id, | |
| 92 const std::string& method, | |
| 93 const GURL& action) { | |
| 94 DictionaryValue log; | |
| 95 log.SetString("name_or_id", name_or_id); | |
| 96 log.SetString("method", method); | |
| 97 log.SetString("action", ScrubURL(action)); | |
| 98 LogValue(message, log); | |
| 99 } | 195 } |
| 100 | 196 |
| 101 void SavePasswordProgressLogger::LogURL(const std::string& message, | 197 void SavePasswordProgressLogger::LogPasswordForm( |
| 102 const GURL& url) { | 198 SavePasswordProgressLogger::StringID label, |
| 103 LogValue(message, StringValue(ScrubURL(url))); | 199 const PasswordForm& form) { |
| 200 DictionaryValue log; | |
| 201 AddToDict(&log, STRING_SCHEME_MESSAGE, FormSchemeToStringID(form.scheme)); | |
| 202 AddToDict(&log, STRING_SCHEME_MESSAGE, FormSchemeToStringID(form.scheme)); | |
| 203 AddToDict(&log, STRING_SIGNON_REALM, GURL(form.signon_realm)); | |
| 204 AddToDict( | |
| 205 &log, STRING_ORIGINAL_SIGNON_REALM, GURL(form.original_signon_realm)); | |
| 206 AddToDict(&log, STRING_ORIGIN, form.origin); | |
| 207 AddToDict(&log, STRING_ACTION, form.action); | |
| 208 AddToDict(&log, STRING_USERNAME_ELEMENT, form.username_element); | |
| 209 AddToDict(&log, STRING_PASSWORD_ELEMENT, form.password_element); | |
| 210 AddToDict( | |
| 211 &log, STRING_PASSWORD_AUTOCOMPLETE_SET, form.password_autocomplete_set); | |
| 212 AddToDict(&log, STRING_OLD_PASSWORD_ELEMENT, form.old_password_element); | |
| 213 AddToDict(&log, STRING_SSL_VALID, form.ssl_valid); | |
| 214 AddToDict(&log, | |
| 215 STRING_PASSWORD_GENERATED, | |
| 216 form.type == PasswordForm::TYPE_GENERATED); | |
| 217 AddToDict(&log, STRING_TIMES_USED, form.times_used); | |
| 218 AddToDict(&log, | |
| 219 STRING_USE_ADDITIONAL_AUTHENTICATION, | |
| 220 form.use_additional_authentication); | |
| 221 AddToDict(&log, STRING_PSL_MATCH, form.IsPublicSuffixMatch()); | |
| 222 LogValue(label, &log); | |
| 104 } | 223 } |
| 105 | 224 |
| 106 void SavePasswordProgressLogger::LogBoolean(const std::string& message, | 225 void SavePasswordProgressLogger::LogHTMLForm( |
| 107 bool value) { | 226 SavePasswordProgressLogger::StringID label, |
| 108 LogValue(message, FundamentalValue(value)); | 227 const std::string& name_or_id, |
| 228 const std::string& method, | |
| 229 const GURL& action) { | |
| 230 DictionaryValue log; | |
| 231 AddToDict(&log, STRING_NAME_OR_ID, name_or_id); | |
| 232 AddToDict(&log, STRING_METHOD, FormMethodToStringID(method)); | |
| 233 AddToDict(&log, STRING_ACTION, action); | |
| 234 LogValue(label, &log); | |
| 109 } | 235 } |
| 110 | 236 |
| 111 void SavePasswordProgressLogger::LogNumber(const std::string& message, | 237 void SavePasswordProgressLogger::LogURL( |
| 112 int value) { | 238 SavePasswordProgressLogger::StringID label, |
| 113 LogValue(message, FundamentalValue(value)); | 239 const GURL& url) { |
| 240 LogValue(label, GetValueFromLog(url).get()); | |
| 114 } | 241 } |
| 115 | 242 |
| 116 void SavePasswordProgressLogger::LogNumber(const std::string& message, | 243 void SavePasswordProgressLogger::LogBoolean( |
| 117 size_t value) { | 244 SavePasswordProgressLogger::StringID label, |
| 118 LogValue(message, FundamentalValue(checked_cast<int, size_t>(value))); | 245 bool truth_value) { |
| 246 LogValue(label, GetValueFromLog(truth_value).get()); | |
| 119 } | 247 } |
| 120 | 248 |
| 121 void SavePasswordProgressLogger::LogFinalDecision(Decision decision) { | 249 void SavePasswordProgressLogger::LogNumber( |
| 122 LogValue("Final decision taken", DecisionToStringValue(decision)); | 250 SavePasswordProgressLogger::StringID label, |
| 251 int signed_number) { | |
| 252 LogValue(label, GetValueFromLog(signed_number).get()); | |
| 123 } | 253 } |
| 124 | 254 |
| 125 void SavePasswordProgressLogger::LogMessage(const std::string& message) { | 255 void SavePasswordProgressLogger::LogNumber( |
| 126 LogValue("Message", StringValue(message)); | 256 SavePasswordProgressLogger::StringID label, |
| 257 size_t unsigned_number) { | |
| 258 LogValue(label, | |
| 259 GetValueFromLog(checked_cast<int, size_t>(unsigned_number)).get()); | |
| 127 } | 260 } |
| 128 | 261 |
| 129 void SavePasswordProgressLogger::LogValue(const std::string& name, | 262 void SavePasswordProgressLogger::LogMessage( |
| 130 const Value& log) { | 263 SavePasswordProgressLogger::StringID message) { |
| 264 LogValue(STRING_MESSAGE, GetValueFromLog(message).get()); | |
| 265 } | |
| 266 | |
| 267 void SavePasswordProgressLogger::LogValue(StringID label, const Value* log) { | |
| 131 std::string log_string; | 268 std::string log_string; |
| 132 bool conversion_to_string_successful = base::JSONWriter::WriteWithOptions( | 269 bool conversion_to_string_successful = base::JSONWriter::WriteWithOptions( |
| 133 &log, base::JSONWriter::OPTIONS_PRETTY_PRINT, &log_string); | 270 log, base::JSONWriter::OPTIONS_PRETTY_PRINT, &log_string); |
| 134 DCHECK(conversion_to_string_successful); | 271 DCHECK(conversion_to_string_successful); |
| 135 SendLog(name + ": " + log_string); | 272 SendLog(GetStringFromID(label) + ": " + log_string); |
| 136 } | 273 } |
| 137 | 274 |
| 138 } // namespace autofill | 275 } // namespace autofill |
| OLD | NEW |