Index: chrome/browser/password_manager/login_database.cc |
diff --git a/chrome/browser/password_manager/login_database.cc b/chrome/browser/password_manager/login_database.cc |
index ff431de6da21eaf71d8c70b57e09a046d6e46285..d8ccc8bcc4b23e6615cf8be070f49853223f1cfa 100644 |
--- a/chrome/browser/password_manager/login_database.cc |
+++ b/chrome/browser/password_manager/login_database.cc |
@@ -7,14 +7,18 @@ |
#include <algorithm> |
#include <limits> |
+#include "base/command_line.h" |
#include "base/file_util.h" |
#include "base/files/file_path.h" |
#include "base/logging.h" |
#include "base/metrics/histogram.h" |
#include "base/pickle.h" |
+#include "base/string_util.h" |
#include "base/strings/string_number_conversions.h" |
#include "base/time.h" |
#include "base/utf_string_conversions.h" |
+#include "chrome/common/chrome_switches.h" |
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
#include "sql/statement.h" |
#include "sql/transaction.h" |
@@ -45,6 +49,13 @@ enum LoginTableColumns { |
COLUMN_TIMES_USED |
}; |
+std::string GetPSLDomain(std::string signon_realm_str) { |
Ilya Sherman
2013/06/06 09:25:35
nit: Pass by const reference.
Ilya Sherman
2013/06/06 09:25:35
Please spell out acronyms like PSL; or better yet,
palmer
2013/06/06 21:16:42
|GetPublicDomainSuffix|? |GetPublicSuffix|?
nyquist
2013/06/07 22:51:10
Is |GetRegistryControlledDomain| OK? Since we tech
|
+ GURL signon_realm(signon_realm_str); |
palmer
2013/06/06 21:16:42
Declare this const if the callee takes a const &.
nyquist
2013/06/07 22:51:10
Done.
|
+ return net::registry_controlled_domains::GetDomainAndRegistry( |
+ signon_realm, |
+ net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); |
+} |
+ |
} // namespace |
LoginDatabase::LoginDatabase() { |
@@ -100,6 +111,10 @@ bool LoginDatabase::Init(const base::FilePath& db_path) { |
db_.Close(); |
return false; |
} |
+ |
+ psl_domain_matching_ = CommandLine::ForCurrentProcess()->HasSwitch( |
+ switches::kEnablePasswordAutofillPSLDomainMatching); |
+ |
return true; |
} |
@@ -334,6 +349,8 @@ bool LoginDatabase::InitPasswordFormFromStatement(PasswordForm* form, |
form->submit_element = s.ColumnString16(COLUMN_SUBMIT_ELEMENT); |
tmp = s.ColumnString(COLUMN_SIGNON_REALM); |
form->signon_realm = tmp; |
+ form->original_signon_realm = ""; |
+ form->is_psl_origin_match = false; |
form->ssl_valid = (s.ColumnInt(COLUMN_SSL_VALID) > 0); |
form->preferred = (s.ColumnInt(COLUMN_PREFERRED) > 0); |
form->date_created = base::Time::FromTimeT( |
@@ -357,19 +374,56 @@ bool LoginDatabase::GetLogins(const PasswordForm& form, |
std::vector<PasswordForm*>* forms) const { |
DCHECK(forms); |
// You *must* change LoginTableColumns if this query changes. |
- sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE, |
- "SELECT origin_url, action_url, " |
+ std::string signon_realm_operator = psl_domain_matching_ ? "regexp" : "=="; |
+ std::string sql_query = "SELECT origin_url, action_url, " |
palmer
2013/06/06 21:16:42
I think you can declare these strings const? I'm b
nyquist
2013/06/07 22:51:10
Done.
|
"username_element, username_value, " |
"password_element, password_value, submit_element, " |
"signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, " |
"scheme, password_type, possible_usernames, times_used " |
- "FROM logins WHERE signon_realm == ? ")); |
- s.BindString(0, form.signon_realm); |
+ "FROM logins WHERE signon_realm " + signon_realm_operator + " ? "; |
+ sql::Statement s; |
+ if (psl_domain_matching_) { |
+ // TODO(nyquist) Re-enable usage of cached statements if possible. |
+ // s.Assign(db_.GetCachedStatement(SQL_FROM_HERE, sql_query.c_str())); |
palmer
2013/06/06 21:16:42
Perhaps you still can? Have you tried it? It shoul
nyquist
2013/06/07 22:51:10
Will try again before I submit this. I agree that
|
+ s.Assign(db_.GetUniqueStatement(sql_query.c_str())); |
+ std::string domain = GetPSLDomain(form.signon_realm); |
+ // We need to escape and . in the domain. Since the domain has already been |
+ // sanitized using GURL, we do not need to escape any other characters. |
+ ReplaceChars(domain, ".", "\\.", &domain); |
+ // For a domain such as foo.bar, this regexp will match domains for any |
+ // scheme and on the form: http://foo.bar/, http://www.foo.bar/, |
+ // http://www.mobile.foo.bar/. It will not match http://notfoo.bar/. |
+ std::string regexp = "(\\w+?:\\/\\/)([\\w\\-_]+\\.)*" + domain + "\\/$"; |
palmer
2013/06/06 21:16:42
Can we instead use an explicit list of schemata, i
nyquist
2013/06/07 22:51:10
Done. Also added ^ at start of query. Still keepin
|
+ s.BindString(0, regexp); |
+ } else { |
+ s.Assign(db_.GetCachedStatement(SQL_FROM_HERE, sql_query.c_str())); |
+ s.BindString(0, form.signon_realm); |
+ } |
while (s.Step()) { |
scoped_ptr<PasswordForm> new_form(new PasswordForm()); |
if (!InitPasswordFormFromStatement(new_form.get(), s)) |
return false; |
+ if (psl_domain_matching_) { |
+ std::string found_psl_domain = GetPSLDomain(new_form->signon_realm); |
palmer
2013/06/06 21:16:42
More constiness, if possible
nyquist
2013/06/07 22:51:10
Done.
|
+ std::string form_psl_domain = GetPSLDomain(form.signon_realm); |
+ if (found_psl_domain != form_psl_domain) { |
+ // The database returned results that should not match. Skipping result. |
+ continue; |
+ } |
+ if (form.signon_realm != new_form->signon_realm) { |
+ // This is not a perfect match, so we need to create a new valid result. |
+ // We do this by copying over origin, signon realm and action from the |
+ // observed form and setting the original signon realm to what we found |
+ // in the database. We also set a flag to notify the caller that this |
+ // is not a perfect match. |
+ new_form->is_psl_origin_match = true; |
+ new_form->original_signon_realm = new_form->signon_realm; |
+ new_form->origin = form.origin; |
+ new_form->signon_realm = form.signon_realm; |
+ new_form->action = form.action; |
+ } |
+ } |
forms->push_back(new_form.release()); |
} |
return s.Succeeded(); |